I am using period = 10 and multiplier = 3. Here is the code. Where might I be wrong. Because my upperband and lowerband are way off from charting platfroms such as trading view or zerodha. I am getting 5 minute candle data for 2 days and based on that calculating the ATR and supertrend. (so maybe 224 candles and 10 period).
class SupertrendCalculator {
final List<StockDataKite> candles;
final int period;
final double multiplier;
final int emaPeriod = 13; // EMA period
SupertrendCalculator({
required this.candles,
this.period = 10,
this.multiplier = 3,
});
List<double> calculateATR() {
List<double> trValues = []; // True Range values
List<double> atrValues = List.filled(candles.length, 0.0); // ATR values
// Calculate True Range for each candle
for (int i = 0; i < candles.length; i++) {
double highLow = candles[i].high - candles[i].low;
double highClosePrev =
i == 0 ? 0 : (candles[i].high - candles[i - 1].close).abs();
double lowClosePrev =
i == 0 ? 0 : (candles[i].low - candles[i - 1].close).abs();
double trueRange = max(highLow, max(highClosePrev, lowClosePrev));
trValues.add(trueRange);
//print('True range length ${candles.length} ${trValues}');
}
// Calculate ATR
for (int i = period; i < candles.length; i++) {
if (i == period) {
// Initial ATR is the average of the first 'period' TR values
double sumTR = trValues.sublist(0, period).reduce((a, b) => a + b);
atrValues[i] = sumTR / period;
} else {
// Subsequent ATR values are calculated using the previous ATR value
atrValues[i] =
((atrValues[i - 1] * (period - 1)) + trValues[i]) / period;
}
}
return atrValues;
}
dynamic calculateEMA({bool single = false}) {
List<double> emaValues = List.filled(candles.length, 0.0);
double multiplier = 2 / (emaPeriod + 1.0);
if (candles.isNotEmpty) {
// Set the first EMA value to the first close price
emaValues[0] = candles[0].close;
for (int i = 1; i < candles.length; i++) {
double closePrice = candles[i].close;
// EMA formula
emaValues[i] =
((closePrice - emaValues[i - 1]) * multiplier) + emaValues[i - 1];
}
}
if (single == true) {
return emaValues.last;
} else {
return emaValues;
}
}
List calculateSupertrend() {
List<double> atr = calculateATR();
List<double> ema = calculateEMA(); // Calculate EMA values
bool trend = false; // Initial trend
double upperBand = 0.0, lowerBand = 0.0;
for (int i = candles.length - period; i < candles.length; i++) {
// First, calculate new bands regardless of the current trend
var hl2 = (candles[i].high + candles[i].low) / 2;
double newUpperBand = hl2 + (multiplier * atr[i]);
double newLowerBand = hl2 - (multiplier * atr[i]);
if (trend && candles[i].close < newLowerBand) {
trend =
false; // If current close is below the new lower band in an uptrend, switch
to downtrend
} else if (!trend && candles[i].close > newUpperBand) {
trend =
true; // If current close is above the new upper band in a downtrend, switch
to uptrend
}
// Update bands based on the new trend direction
if (trend) {
upperBand = newUpperBand; // In an uptrend, always update the upper band
lowerBand = max(
lowerBand, newLowerBand); // Lower band doesn't decrease in uptrend
} else {
lowerBand =
newLowerBand; // In a downtrend, always update the lower band
upperBand = min(upperBand,
newUpperBand); // Upper band doesn't increase in downtrend
}
bool isEMATouchingOrClose = (ema[i] - candles[i].close).abs() <=
(candles[i].close * 0.003); // EMA is within 0.5% of the close price
if (trend &&
candles[i].close > candles[i].open &&
candles[i].close > ema[i] &&
isEMATouchingOrClose &&
ema[i] > ema[i - 1] &&
ema[i - 1] > ema[i - 2]) {
candles[i].supertrendSignal = "BUY"; // Uptrend and EMA is increasing
} else if (!trend &&
candles[i].close < candles[i].open &&
isEMATouchingOrClose &&
ema[i] < ema[i - 1] &&
candles[i].close < ema[i] &&
ema[i - 1] < ema[i - 2]) {
candles[i].supertrendSignal = "SELL"; // Downtrend and EMA is decreasing
} else {
candles[i].supertrendSignal = "HOLD";
}
// print(
// '${candles[i].timestamp} -- ${trend} -- ${candles[i].supertrendSignal}');
}
for (var candle in candles) {
print(
"Candle ${candle.timestamp}: Close=${candle.close}, Trend=${candle.supertrendSignal}, Signal=${candle.supertrendSignal}");
}
return [
candles.last.supertrendSignal,
ema.last,
candles.last.open,
candles.last.close
];
}
}
The problem occurs when my code gives wrong signals because it things stock is in uptrend while it is in downtrend because of the messed up values of upper and lower bands. But when i change my multiplier to 1.3 or something within this range, this problems somewhat becomes less worrisome. But still I want the same upper band and lowerband values as othe r charting platforms.