Warning: session_start(): open(/var/lib/php/sessions/sess_4ne1uba1865c699c5koppj5k56, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// Design notes.
//
// NG stands for "Non-Garbage"
//
// !Design notes end
sclass NGSStrategy2 extends G22CandleBasedStrategyWithTrailingStop {
settable int period1 = 100; // the "slow" MA
settable int period2 = 5; // the fast MA (for opening)
settable double maMinMove = 0.07; // MA trend threshold
settable double maMoveHysteresis = 0.01; // MA trend non-oscillation threshold
// per-run fields
S fieldsToReset() {
ret lineCombine(super.fieldsToReset(), [[
ma1 ma2 lastMA1 maMove movingAverage1_cache movingAverage2_cache
maMoveHistory maDirection maDirectionHistory
]]);
}
settable double ma1;
settable double ma2;
settable double lastMA1 = Double.NaN;
settable double maMove;
settable int maDirection;
Side longSide = new(1);
Side shortSide = new(-1);
gettable TickerSequence maMoveHistory = new TickerSequence("maMove");
gettable TickerSequence maDirectionHistory = new TickerSequence("maDirection");
// Side = logic for one side (long/short = direction 1/-1)
record Side(int direction) {
// Our condition is:
// Price has to be in a band close to the MA first (band 1)
// and then move into a band further away from the MA (band 2)
// Are we allowed to open positions in this direction at all?
bool enabled = true;
// First band (close to MA)
DoubleRange band1 = new(0.2, 0.6);
// Second band
DoubleRange band2 = new(0.6, 1.0);
}
void ngsStep aka ngsLogic() {
double close = currentPrice();
double drift = drift();
}
simplyCached MAIndicator movingAverage1() {
ret new MAIndicator(period1);
}
simplyCached MAIndicator movingAverage2() {
ret new MAIndicator(period2);
}
L indicators() {
ret ll(movingAverage1(), movingAverage2());
}
bool maRising() { ret maDirection > 0; }
bool maFalling() { ret maDirection < 0; }
double moveSignal() { ret maMove/maMinMove*100; }
double maPlusPercent(dbl ma1 default ma1, double percent) { ret ma1*(1+percent/100); }
double maMinusPercent(dbl ma1 default ma1, double percent) { ret ma1*(1-percent/100); }
{
granularity(30);
onNewPrice(price -> ngsStep());
onCandleCompleted(candle -> {
lastMA1(ma1);
ma1(movingAverage1()!);
ma2(movingAverage2()!);
maMove((ma1/lastMA1-1)*100);
maMoveHistory?.addIfPriceChanged(maMove, currentTime());
if (maMove >= maMinMove)
maDirection(1);
else if (maMove <= -maMinMove)
maDirection(-1);
else if (maDirection < 0 && maMove >= -maMinMove2()
|| maDirection > 0 && maMove <= maMinMove2())
maDirection(0);
maDirectionHistory?.addIfPriceChanged(maDirection, currentTime());
ngsStep();
});
}
double maMinMove2() { ret maMinMove-maMoveHysteresis; }
LS status() {
ret listCombine(
"Min distance, MA min move: " + minDistance + " " + maMinMove + " (current move: " + formatDouble(maMove, 4) + ")",
"MA periods: " + period1 + " " + period2,
"Do: " + commaCombine(stringIf(doLongs(), "Longs"), stringIf(doShorts(), "Shorts")),
"Moving averages: " + formatDouble_significant(ma1, 4) + ", " + formatDouble_significant(ma2, 4),
super.status()
);
}
void afterStep :: before {
}
}