Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

348
LINES

< > BotCompany Repo | #1036196 // Corridor

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (30017L) is out of date.

1  
concept Corridor extends G22TradingStrategy {
2  
  // how many cells the corridor has
3  
  settableWithVar int capacity = 3;
4  
  
5  
  settableWithVar int maxPositionsPerDirection = 100;
6  
7  
  settableWithVar bool instantRestart = true;
8  
  
9  
  // initial position behavior
10  
  settableWithVar bool openTwoPositionsAtStart;
11  
  settableWithVar bool openRandomPositionAtStart = true;
12  
  settableWithVar int openFixedDirectionAtStart; // 1 or -1 or 0
13  
  
14  
  // later position opening behavior
15  
  settableWithVar bool alwaysOpenTwoPositions;
16  
  
17  
  // Pre-run to check if coin is in corridor mode (dev.)
18  
  //settableWithVar bool usePreRun;
19  
  //settableWithVar AbstractJuicer preRunJuicer;
20  
  
21  
  settableWithVar bool endStrategyWhenCapacityExceeded = true;
22  
  
23  
  settableWithVar bool useStrategyJuicer;
24  
  !include #1036390 // MultiPullbackJuicer maker include
25  
  settableWithVar SignalWithStrength closeSignal;
26  
  
27  
  // internal
28  
  
29  
  persistable class Position extends G22TradingStrategy.Position {
30  
  }
31  
  
32  
  // direction: -1 or 1 for normal short or long
33  
  // To change size of of position, use -2, 2 etc
34  
  Position openPosition(int direction) {
35  
    if (l(positionsInDirection(direction)) >= maxPositionsPerDirection) {
36  
      log("Not opening new position in direction " + direction + ", max reached");
37  
      null;
38  
    }
39  
    
40  
    new Position p;
41  
    p.marginToUse = marginPerPosition*abs(direction);
42  
    ret openPosition(p, direction);
43  
  }
44  
45  
  void start {
46  
    if (started()) fail("Already started");
47  
    if (currentPrice() == 0)
48  
      ret with primed(true);
49  
    
50  
    // Save starting price, create price cells & digitizer
51  
    
52  
    startingPrice = currentPrice();
53  
    startTime = currentTime();
54  
    var priceCells = makePriceCells(startingPrice);
55  
    print("Made price cells: " + priceCells);
56  
    digitizer = new PriceDigitizer2(priceCells);
57  
    digitizer.verbose(verbose);
58  
    //digitizer.init(startingPrice);
59  
    
60  
    makeStrategyJuicer();
61  
    
62  
    log("Starting CORRIDOR at " + startingPrice + " +/- " + cellSize);
63  
    
64  
    startAction();
65  
  }
66  
  
67  
  swappable void startAction {
68  
    if (openTwoPositionsAtStart) {
69  
      nextStep();
70  
      openPosition(1);
71  
      openPosition(-1);
72  
      afterStep();
73  
    } else if (openRandomPositionAtStart) {
74  
      nextStep();
75  
      log("Opening random initial position.");
76  
      openPosition(securelyTossCoin() ? 1 : - 1);
77  
      afterStep();
78  
    } else if (openFixedDirectionAtStart != 0) {
79  
      nextStep();
80  
      log("Opening fixed initial position.");
81  
      openPosition(sign(openFixedDirectionAtStart));
82  
      afterStep();
83  
    }
84  
  }
85  
  
86  
  void price(double price) {
87  
    if (currentPrice == price) ret;
88  
    currentPrice = price;
89  
    
90  
    if (hasClosedItself()) ret;
91  
    
92  
    if (!started()) {
93  
      if (primed) {
94  
        primed(false);
95  
        start();
96  
      } else
97  
        ret;
98  
    }
99  
    
100  
    digitizer.digitize(price);
101  
    direction = sign(digitizedPrice()-lastDigitizedPrice());
102  
    
103  
    if (applyStrategyJuicer()) ret;
104  
    
105  
    // No cell move?
106  
    if (direction == 0) ret with afterStep();
107  
108  
    nextStep();
109  
    //printWithPrecedingNL("New digitized price: " + digitizedPrice());
110  
111  
    if (started())
112  
      step();
113  
      
114  
    print(this);
115  
  }
116  
  
117  
  // true if exit
118  
  bool applyStrategyJuicer() {
119  
    // Check strategy juicer
120  
    closeSignal(strongestSignal(strategyJuicer?.calculateCloseSignals()));
121  
    if (closeSignal != null && closeSignal.isTrigger()) {
122  
      log("Juicer close signal! " + closeSignal);
123  
      closeOrRestart();
124  
      afterStep();
125  
      true;
126  
    }
127  
    
128  
    false;
129  
  }
130  
  
131  
  swappable void step {
132  
    double p1 = lastDigitizedPrice();
133  
    double p2 = digitizedPrice();
134  
    direction = sign(p2-p1);
135  
    if (direction == 0) ret;
136  
    
137  
    // Find winning positions to close
138  
    
139  
    L<G22TradingStrategy.Position> toClose = new L;
140  
    for (p : direction > 0
141  
      ? longPositionsAtOrBelowDigitizedPrice(p1)
142  
      : shortPositionsAtOrAboveDigitizedPrice(p1)) {
143  
      cast p to Position;
144  
      p.closeReason("WIN");
145  
      log("Closing winner position at " + formatPriceX(currentPrice) + " (" + p1 + " -> " + p2 + "): " + p);
146  
      toClose.add(p);
147  
    }
148  
    
149  
    // Dismantle/close corridor if too large
150  
    double limit = fromCellNumber(toCellNumber(digitizedPrice())-capacity*direction);
151  
    var toDismantle = direction > 0
152  
      ? shortPositionsAtOrBelowDigitizedPrice(limit)
153  
      : longPositionsAtOrAboveDigitizedPrice(limit);
154  
    if (logToPrint) printVars(dismantleLimit := formatPriceX(limit),
155  
      +direction,
156  
      +capacity,
157  
      +digitizedPrice(),
158  
      +toDismantle);
159  
    
160  
    if (nempty(toDismantle)) {
161  
      if (endStrategyWhenCapacityExceeded) {
162  
        log("Capacity exceeded!");
163  
        closeOrRestart();
164  
        afterStep();
165  
        ret;
166  
      } else {
167  
        for (p : toDismantle) {
168  
          cast p to Position;
169  
          p.closeReason("DISMANTLE");
170  
          toClose.add(p);
171  
        }
172  
      }
173  
    }
174  
      
175  
    //printVars("step", +p1, +p2, +direction, +closed, +opened);
176  
    
177  
    if (nempty(toClose))
178  
      closePositions(toClose);
179  
180  
    // Apply take profits etc BEFORE possibly opening a new position
181  
    afterStep();
182  
    
183  
    openNewPositionAfterMove();
184  
      
185  
    // Apply take profits, stop loss etc
186  
    afterStep();
187  
  }
188  
  
189  
  void closeOrRestart {
190  
    if (instantRestart)
191  
      restart();
192  
    else
193  
      closeMyself();
194  
  }
195  
  
196  
  void restart {
197  
    closeMyself();
198  
    active(true);
199  
    closedItself(0);
200  
    startAction();
201  
  }
202  
203  
  swappable void openNewPositionAfterMove {  
204  
    // Open backward position here (if not there yet)
205  
    openPositionIfNotThere(-direction);
206  
      
207  
    // Open forward position if configured as such
208  
    if (alwaysOpenTwoPositions)
209  
      openPositionIfNotThere(direction);
210  
  }
211  
  
212  
  Position openPositionIfNotThere(int direction) {
213  
    if (!hasPosition(digitizedPrice(), direction))
214  
      ret openPosition(direction);
215  
    else
216  
      null;
217  
  }
218  
  
219  
  swappable S mainDesc() {
220  
    try answer renderCustomName();
221  
222  
    ret capacity + "x" + formatCellSize(cellSize) + " Corridor";
223  
  }
224  
  
225  
  S baseToString() {
226  
    ret colonCombine(
227  
      _conceptID() == 0 ? "" : "Strategy " + _conceptID(),
228  
      spaceCombine(
229  
        squareBracketUnlessEmpty(areaDesc()),
230  
        mainDesc(),
231  
        nempty(cryptoCoin) ? "on " + cryptoCoin : ""
232  
      ),
233  
    );
234  
  }
235  
  
236  
  LS status() {
237  
    var r = currentCorridorPriceRange();
238  
    ret listCombine(
239  
      super.status(),
240  
      "Max capacity: " + capacity,
241  
      !started() ? null : "Current corridor: " + (r == null ? "-" : formatPrice(r.start) + " to " + formatPrice(r.end) + " (" + formatPercentage(currentCorridorSizeInPercent(), 3) + ")"),
242  
      "Profit unit: " + formatMarginPrice(profitUnitBeforeAdversity()) + "/" + marginCoin + " " + formatMarginPrice(profitUnitAfterAdversity()) + ", loss unit: " + marginCoin + " " + formatMarginPrice(lossUnit()),
243  
      closeSignal == null ?: "Close signal: " + closeSignal,
244  
    );
245  
  }
246  
  
247  
  // Corridor.toString
248  
  toString {
249  
    ret baseToString();
250  
  } 
251  
  
252  
  S renderCustomName() {
253  
    ret empty(customName) ? null : simpleQuoteOpt(trim(customName));
254  
  }
255  
  
256  
  double maxCorridorPercentSize() {
257  
    ret capacity*cellSize;
258  
  }
259  
  
260  
  DoubleRange currentCorridorPriceRange() {
261  
    double[] openingPrices = mapToDoubleArray(openPositions, ->.openingPrice);
262  
    ret doubleRange(doubleMin(openingPrices), doubleMax(openingPrices));
263  
  }
264  
  
265  
  double currentCorridorSizeInPercent() {
266  
    DoubleRange r = currentCorridorPriceRange();
267  
    ret r == null ? 0 : asPercentIncrease(r.end, r.start);
268  
  }
269  
270  
  Position openShort() { ret openPosition(-1); }
271  
  Position openLong() { ret openPosition(1); }
272  
  
273  
  {
274  
    cellSize(3.0);
275  
  }
276  
  
277  
  double positionSize() { ret marginPerPosition*leverage; }
278  
  double profitUnitBeforeAdversity() { ret cellSize/100*positionSize(); }
279  
  double profitUnitAfterAdversity() { ret (cellSize-adversity)/100*positionSize(); }
280  
  double lossUnit() { ret (cellSize+adversity)/100*positionSize(); }
281  
  
282  
  // Uses profit calculated in profit units
283  
  // (could alternatively use investment units, but like this the
284  
  // loss ratio should stay more consistent between coins [=leverage values])
285  
  class ProfitUnitsJuiceable is Juiceable {
286  
    public double juiceValue() {
287  
      ret coinProfit()/profitUnitBeforeAdversity();
288  
    }
289  
  }
290  
  
291  
  // Update strategy juicer if it exists
292  
  void updateStrategyJuicer {
293  
    if (strategyJuicer != null) {
294  
      makeStrategyJuicer();
295  
      applyStrategyJuicer();
296  
    }
297  
  }
298  
  
299  
  // Can also update existing juicer with new params
300  
  void makeStrategyJuicer {
301  
    if (!useStrategyJuicer) ret with strategyJuicer(null);
302  
    var j = makeJuicer();
303  
    j.copyTransientValuesFrom(strategyJuicer);
304  
    j.juiceable(new ProfitUnitsJuiceable);
305  
    strategyJuicer(j);
306  
  }
307  
  
308  
  S fieldsToReset() {
309  
    ret lines(ll(super.fieldsToReset(), [[closeSignal strategyJuicer]]));
310  
  }
311  
  
312  
  double currentCellNumber() {
313  
    ret toCellNumber(currentPrice());
314  
  }
315  
  
316  
  // Cell we're in
317  
  int currentDigitizedCell() {
318  
    ret iround(toCellNumber(digitizedPrice()));
319  
  }
320  
  
321  
  int priceDirection() {
322  
    ret sign(currentCellNumber()-currentDigitizedCell());
323  
  }
324  
  
325  
  // Cell we're currently moving to
326  
  int targetCell() {
327  
    ret currentDigitizedCell()+priceDirection();
328  
  }
329  
  
330  
  double targetPrice() {
331  
    ret fromCellNumber(targetCell());
332  
  }
333  
  
334  
  // Coin profit when next target is reached
335  
  double targetProfit() {
336  
    ret coinProfitAtPrice(targetPrice());
337  
  }
338  
  
339  
  // Is profit currently going up or down
340  
  int profitDirection() {
341  
    ret sign(targetProfit()-coinProfit());
342  
  }
343  
  
344  
  // progress to next target in percent
345  
  double progressInProfitDirection() {
346  
    ret absDiff(currentCellNumber(), currentDigitizedCell())*100;
347  
  }
348  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): elmgxqgtpvxh, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1036196
Snippet name: Corridor
Eternal ID of this version: #1036196/345
Text MD5: 8cfd09e821b755ad662489afd55962ee
Author: stefan
Category: javax / gazelle 22
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-12-06 21:56:41
Source code size: 9923 bytes / 348 lines
Pitched / IR pitched: No / No
Views / Downloads: 827 / 2252
Version history: 344 change(s)
Referenced in: [show references]