set flag Reparse. sclass Corridor { record noeq Position(double openingPrice, double direction) { double closingPrice = Double.NaN; gettable int digitizedOpeningPrice = digitizePrice(openingPrice); 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()); } } settable double ladderStep = 1; 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; new LinkedHashSet openPositions; new L closedPositions; Position openPosition(double direction) { var p = new Position(currentPrice(), direction); openPositions.add(p); print("Opening " + p); printPositions(); ret p; } 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); openPosition(1); openPosition(-1); } int digitizePrice(double price) { ret iround((price-digitizationBase)/ladderStep); } int oldPriceDigitized() { ret digitizePrice(oldPrice); } int currentPriceDigitized() { ret digitizePrice(currentPrice()); } selfType currentPrice aka price(double price) { oldPrice = currentPrice; if (oldPrice == price) this; currentPrice = price; int direction = sign(price-oldPrice); lastDirection = direction; if (oldPriceDigitized() == currentPriceDigitized()) this; ++stepCount; printWithPrecedingNL(commaCombine( "Step " + stepCount + ". Old price: " + oldPrice, "New price: " + price)); step(); this; } swappable void step { for (p : cloneList(openPositions)) { if (digitizePrice(p.openingPrice) < currentPriceDigitized() && p.direction == lastDirection) p.close(); } } double unrealizedProfit() { ret doubleSum(map(openPositions, ->.profit())); } L negativePositions() { ret filter(openPositions, p -> p.profit() < 0); } double negativePositionSum() { ret doubleSum(map(negativePositions(), ->.profit())); } double profit() { ret realizedProfit+unrealizedProfit(); } LS status() { ret ll( "Profit: " + profit(), "Realized profit: " + realizedProfit + " from " + n2(closedPositions, "closed position"), "Unrealized profit: " + unrealizedProfit() + " in " + n2(openPositions, "open position"), "Negative positions: " + negativePositionSum(), ); } toString { ret commaCombine(status()); } }