persistable sclass MultiStopLossJuicer extends AbstractJuicer { // Must have at least one level, otherwise no closing at all sclass Level { // At juice value minJuiceValue, define the stopLoss. settable double minJuiceValue; settable double stopLoss; toString { ret "Stop loss " + stopLoss + "% starting at " + formatDouble2(minJuiceValue); } } settableWithVar new L levels; // Highest juice value seen settableWithVar double crest = -infinity(); // for current level, set by MultiStopLossJuicer itself settableWithVar StopLossJuicer stopLossJuicer; settableWithVar int levelsTriggered; Level nextLevel() { ret _get(levels, levelsTriggered); } { onCalculatingCloseSignals(signals -> { if (juiceValue > crest) crest(juiceValue); Level level; while ((level = nextLevel()) != null && crest >= level.minJuiceValue) { levelsTriggered(levelsTriggered+1); var slj = new StopLossJuicer(level.stopLoss); slj.juiceable(juiceable()); stopLossJuicer(slj); } if (stopLossJuicer != null) addAll(signals, stopLossJuicer.calculateCloseSignals()); }); } void addLevel(double minJuiceValue, double stopLoss) { levels.add(new Level().+minJuiceValue.+stopLoss); } toString { ret commaCombine( shortClassName(this), levels, crest == -infinity() ? null : "Highest profit seen: " + formatDouble2(crest), "Levels triggered: " + levelsTriggered, "Current stop loss: " + stopLossJuicer, ); } // Hmm. Is this correct? void copyTransientValuesFrom(AbstractJuicer juicer) { if (juicer cast MultiStopLossJuicer) crest(juicer.crest); } }