persistable sclass MultiPullbackJuicer extends StopLossJuicer { sclass Level { // Starting at juice value minJuiceValue, keep keepPercentage of the juice settable double minJuiceValue; settable double keepPercentage; } settableWithVar new L levels; // Highest juice value seen settableWithVar double crest = -infinity(); { onCalculatingCloseSignals(signals -> { if (juiceValue > crest) crest(juiceValue); if (crest < 0) ret; double keepPercentage = getKeepPercentageForJuiceValue(juiceValue); if (isNaN(keepPercentage)) ret; double toKeep = crest*keepPercentage; double maxPullback = crest-toKeep; var signal = new CloseSignal().createdBy(this).reason("Profit"); if (maxPullback == 0) signal.strength(1); else signal.strength(doubleRatio(crest-juiceValue, maxPullback)); signals.add(signal); }); } double getKeepPercentageForJuiceValue(double juice) { for (int i = l(levels)-1; i >= 0; i--) { Level level = levels.get(i); if (juice < level.minJuiceValue) continue; Level nextLevel = get(levels, i+1); if (nextLevel == null) ret level.keepPercentage; ret blend(level.keepPercentage, nextLevel.keepPercentage, transformToZeroToOne(juice, level.minJuiceValue, nextLevel.minJuiceValue)); } } }