set flag Reparse. sclass Corridor { record noeq Position(/*settable*/ double openingPrice, /*settable*/ double direction) { /*settable*/ double closingPrice = Double.NaN; 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(); } toString { ret renderFunctionCall( spaceCombine( closed() ? "Closed" : null, type() ), openingPrice, "profit=" + profit()); } } record noeq Threshold(/*settable*/ double price, /*settable*/ double direction, Runnable action) { void trigger { print("Triggered at " + price + " " + direction + ": " + action); callF(action); } } settable double epsilon = 0.001; settable double ladderStep = 1; gettable double currentPrice = 0; gettable double lastDirection; gettable double realizedProfit; new L loops; new TreeMultiMap thresholds; new LinkedHashSet openPositions; new L closedPositions; record noeq Loop(/*settable*/ double startingPrice, /*settable*/ double direction) { Position position; Loop successor; class Open is Runnable { run { position = openPosition(direction); if (successor == null) successor = new Loop(startingPrice+ladderStep, direction).init(); } toString { ret spaceCombine("Open", startingPrice, direction); } } class Close is Runnable { run { position?.close(); } toString { ret spaceCombine("Close", startingPrice, direction); } } selfType init() { loops.add(this); addThreshold(startingPrice, -direction, new Open); addThreshold(startingPrice+ladderStep, direction, new Close); this; } toString { ret formatRecordVars("Loop", +startingPrice, +direction, +position, succ := successor == null ?: "t" ); } } Position openPosition(double direction) { ret addAndReturn(openPositions, new Position(currentPrice(), direction)); } Threshold addThreshold(double price, double direction, Runnable action) { var t = new Threshold(price, direction, action); thresholds.put(t.price, t); bool triggered = (lastDirection == 0 || lastDirection == direction) && absDiff(currentPrice, price) < epsilon; printVars addThreshold(+currentPrice, +price, +direction, +lastDirection, +triggered); if (triggered) t.trigger(); ret t; } void start { double price = currentPrice(); lastDirection = 0; new Loop(price, 1).init(); new Loop(price, -1).init(); } selfType currentPrice(double price) { double oldPrice = currentPrice; if (oldPrice == price) this; currentPrice = price; int direction = sign(price-oldPrice); lastDirection = direction; NavigableMap> map = thresholds.innerMap(); map = direction > 0 ? map.subMap(oldPrice, false, price, true) : map.subMap(price, true, oldPrice, false); LL thresholdsCrossed = map cloneList(values(map)); if (direction < 0) reverseInPlace(thresholdsCrossed); for (actions : thresholdsCrossed) for (t : actions) if (t.direction == direction) t.trigger(); this; } double unrealizedProfit() { ret doubleSum(map(openPositions, ->.profit())); } LS status() { ret ll( "Realized profit: " + realizedProfit, "Unrealized profit: " + unrealizedProfit(), n2(openPositions, "open position"), n2(closedPositions, "closed position"), n2(loops, "loop"), n2(keysSize(thresholds), "threshold"), n2(l(thresholds), "threshold action"), ); } toString { ret commaCombine(status()); } }