set flag Reparse. sclass Corridor { settable double ladderStep = 1; settable int capacity = 6; settable bool openTwoPositionsAtStart = true; record noeq Position(double openingPrice, double direction) { double closingPrice = Double.NaN; int digitizedOpeningPrice() { ret digitizePrice(openingPrice); } bool isLong() { ret direction > 0; } bool isShort() { ret direction < 0; } bool closed() { ret !isNaN(closingPrice); } S type() { ret trading_directionToPositionType(direction); } double profitAtPrice(double price) { ret (price-openingPrice)*direction; } double profit() { ret profitAtPrice(closed() ? closingPrice : currentPrice()); } void close { if (closed()) fail("Can't close again"); openPositions.remove(this); closingPrice = currentPrice(); closedPositions.add(this); realizedProfit += profit(); print(this); printPositions(); } toString { ret renderFunctionCall( spaceCombine( closed() ? "Closed" : null, type() ), openingPrice + " [" + digitizedOpeningPrice() + "]", "profit=" + profit()); } } gettable double currentPrice = 0; gettable double oldPrice = Double.NaN; gettable double startingPrice = Double.NaN; gettable double digitizationBase; gettable int lastDirection; gettable double realizedProfit; gettable int stepCount; gettable new LinkedHashSet openPositions; gettable new L closedPositions; gettable new DoubleBuffer priceHistory; Position openPosition(double direction) { var p = new Position(currentPrice(), direction); openPositions.add(p); print("Opening " + p); printPositions(); ret p; } bool hasPosition(double price, double direction) { ret findPosition(price, direction) != null; } Position closePosition(double price, double direction) { var p = findPosition(price, direction); p?.close(); ret p; } Position findPosition(double price, double direction) { ret firstThat(openPositions(), p -> p.digitizedOpeningPrice() == digitizedPrice(price) && p.direction == direction); } Position openShort() { ret openPosition(-1); } Position openLong() { ret openPosition(1); } void printPositions { print(colonCombine(n2(openPositions, "open position"), joinWithComma(openPositions))); } bool started() { ret !isNaN(startingPrice); } void start { if (started()) fail("Already started"); startingPrice = currentPrice(); digitizationBase = frac(startingPrice/ladderStep); print("Starting CORRIDOR at " + startingPrice + " +/- " + ladderStep); if (openTwoPositionsAtStart) { openPosition(1); openPosition(-1); } } int digitizePrice aka digitizedPrice(double price) { ret iround((price-digitizationBase)/ladderStep); } int oldPriceDigitized() { ret digitizePrice(oldPrice); } int currentPriceDigitized() { ret digitizePrice(currentPrice()); } void prices(double... prices) { fOr (price : prices) price(price); } void currentPrice aka price(double price) { oldPrice = currentPrice; if (oldPrice == price) ret; currentPrice = price; int direction = sign(price-oldPrice); lastDirection = direction; if (oldPriceDigitized() == currentPriceDigitized()) ret; bool first = empty(priceHistory); priceHistory.add(price); ++stepCount; if (first) printWithPrecedingNL("Starting price: " + price); else printWithPrecedingNL(commaCombine( "Step " + stepCount + ". Old price: " + oldPrice, "New price: " + price)); if (started()) step(); print(this); } swappable void step { // Close forward position "behind us" closePosition(currentPrice()-ladderStep*lastDirection(), lastDirection()); int p1 = oldPriceDigitized(); int p2 = currentPriceDigitized(); // Open backward position here (if not there yet) int direction = lastDirection(); if (!hasPosition(currentPrice(), -direction)) openPosition(-direction); } double unrealizedProfit() { ret doubleSum(map(openPositions, ->.profit())); } L shortPositionsAtOrBelowPrice(double openingPrice) { ret filter(openPositions, p -> p.isShort() && p.openingPrice <= openingPrice); } L longPositionsAtOrAbovePrice(double openingPrice) { ret filter(openPositions, p -> p.isLong() && p.openingPrice >= openingPrice); } L negativePositions() { ret filter(openPositions, p -> p.profit() < 0); } double debt() { ret doubleSum(map(negativePositions(), ->.profit())); } double profit() { ret realizedProfit+unrealizedProfit(); } LS status() { ret ll( "Step " + n2(stepCount), "Profit: " + profit(), "Realized profit: " + realizedProfit + " from " + n2(closedPositions, "closed position"), "Unrealized profit: " + unrealizedProfit() + " in " + n2(openPositions, "open position"), "Debt: " + debt(), ); } toString { ret commaCombine(status()); } }