sclass NoLoseCloudStrategy extends G22CandleBasedStrategyWithMultiStopLossJuicer is IntegrityCheckable { settableWithVar int fastPeriod = 10; // the "slow" MA settableWithVar int slowPeriod = 15; // the fast MA (for opening) settableWithVar int slowestPeriod = 60; // the fast MA (for opening) settableWithVar double cloudThickness = 5; // false = only manual openLong() and openShort(), // not based on indicators. // true = auto-open positions indefinitely depending on // indicators. settableWithVar bool autoPositions = true; // temporal fields follow S fieldsToReset() { ret lineCombine(super.fieldsToReset(), [[ ma1 ma2 ma3 cloudTop movingAverage1_cache movingAverage2_cache movingAverage3_cache cloudTop cloudBottom candleOverlapWithCloud showCloud lastShowCloud signal ]]); } settableWithVar double ma1; settableWithVar double ma2; settableWithVar double ma3; settableWithVar double cloudTop; settableWithVar double cloudBottom; settableWithVar bool candleOverlapWithCloud; settableWithVar bool showCloud; settableWithVar bool lastShowCloud; settableWithVar int signal; // -1, 0 or 1 bool upTrend() { ret ma1 > ma2; } bool slowUpTrend() { ret ma1 > ma3; } bool trendValid() { ret upTrend() == slowUpTrend(); } settable transient O visualizer; double cloudMin() { ret min(cloudTop, cloudBottom); } double cloudMax() { ret max(cloudTop, cloudBottom); } void strategyStep { candleOverlapWithCloud(rangesOverlap( doubleRange(cloudMin(), cloudMax()), doubleRange(completedCandle().low(), completedCandle().high()))); showCloud(trendValid() && candleOverlapWithCloud()); bool entrySignal = showCloud && !lastShowCloud; signal(entrySignal ? upTrend() ? 1 : -1 : 0); if (signal != 0 && drift() == 0) openPosition(signal); } simplyCached MAIndicator movingAverage1() { ret new MAIndicator(fastPeriod); } simplyCached MAIndicator movingAverage2() { ret new MAIndicator(slowPeriod); } simplyCached MAIndicator movingAverage3() { ret new MAIndicator(slowestPeriod); } L indicators() { ret ll(movingAverage1(), movingAverage2(), movingAverage3()); } { granularity(5); onNewPrice(price -> strategyStep()); onCandleCompleted(candle -> { lastShowCloud(showCloud()); ma1(movingAverage1()!); ma2(movingAverage2()!); ma3(movingAverage3()!); strategyStep(); }); } LS status() { ret listCombine( "MA periods: " + fastPeriod + " " + slowPeriod + " " + slowestPeriod, "Do: " + (!autoPositions ? "Only manual positions" : commaCombine(stringIf(doLongs(), "Longs"), stringIf(doShorts(), "Shorts"))), "Moving averages: " + formatDouble_significant(ma1, 4) + ", " + formatDouble_significant(ma2, 4) + ", " + formatDouble_significant(ma3, 4), super.status() ); } void afterStep :: before { } bool doShorts() { true; } bool doLongs() { true; } int candlesNeededBeforeOperational() { ret intMax(fastPeriod, slowPeriod, slowestPeriod); } bool usingCells() { false; } public void integrityCheck { movingAverage1().integrityCheck(); movingAverage2().integrityCheck(); movingAverage3().integrityCheck(); } }