persistable class Position extends G22TradingStrategy.Position { settable AbstractJuicer juicer; toString { ret super.toString() + (juicer == null ? "" : ". " + commaCombine(juicer.currentSignals())); } } srecord ProfitBeforeLeverageJuiceable(Position p) is Juiceable { public double juiceValue() { ret p.profitBeforeLeverage(); } } void juiceStrategy_price(double price) { if (currentPrice == price) ret; currentPrice = price; afterwards { afterStep(); change(); } juiceStrategy_newPrice(price); } void juiceStrategy_newPrice(double price) { for (p : openPositions()) { cast p to Position; if (p.juicer != null) { var signals = p.juicer.calculateCloseSignals(); var strongest = highestBy(signals, s -> s.strength()); if (strongest != null && strongest.isTrigger()) { p.close(strongest); } } } } Position openShort() { ret openPosition(-1); } Position openLong() { ret openPosition(1); } Position openPosition(int direction, O openReason default null) { new Position p; p.marginToUse = marginToUseForNewPosition(); addJuicer(p); ret openPosition(p, direction, openReason); } void addJuicer(Position p) { var j = makeJuicer(); if (j == null) ret; j.copyTransientValuesFrom(p.juicer); j.juiceable(new ProfitBeforeLeverageJuiceable(p)); p.juicer(j); } void recreateJuicersForExistingPositions aka updateJuicers() { for (p : openPositions()) { cast p to Position; addJuicer(p); } } L openPositions() { ret (L) super.openPositions(); } L allJuicers aka juicers() { ret map(openPositions(), -> .juicer()); }