Skip to content

Instantly share code, notes, and snippets.

@nickmitchko
Created July 1, 2020 14:37
Show Gist options
  • Save nickmitchko/45189a7e2ac9269fbb1a5a3c8b795d00 to your computer and use it in GitHub Desktop.
Save nickmitchko/45189a7e2ac9269fbb1a5a3c8b795d00 to your computer and use it in GitHub Desktop.
HeikinAshi Candle Implementation
package com.nmitchko.storage.Candles;
import com.nmitchko.storage.Candle;
import com.nmitchko.storage.Candles.enums.CandleDirection;
import com.nmitchko.storage.Candles.enums.CandlePeriod;
import com.nmitchko.storage.Candles.enums.CandleType;
import org.ta4j.core.Bar;
import java.sql.Timestamp;
/**
* HeikinAski Candle used for better trend analysis
*/
public class HeikinAshiCandle implements Candle {
/**
* The Heikin Ashi high for the candle, not the exchange high
* MAX(exchange high, HA-Open, HA-Close)
*/
public double high;
/**
* The Heikin Ashi open
* [HA-open t-1 + HA-Close t-1) / 2
*/
public double open;
/**
* The Heikin Ashi close
* [open + high + low + close) /4
*/
public double close;
/**
* Volume for this candle (same as exchange candle)
*/
public double volume;
/**
* SQL timestamp of the candle close
*/
public Timestamp closeTime;
/**
* Period of the candle, set via enum
*/
public CandlePeriod candlePeriod;
/**
* Direction of the candle
*/
public CandleDirection candleDirection;
/**
* The Heikin Ashi low for the candle, not the exchange low
* MIN(exchange low, HA-Open, HA-close)
*/
private double low;
public HeikinAshiCandle(Timestamp closeTime, double high, double low, double open, double close, double volume) {
this.closeTime = closeTime;
this.high = high;
this.low = low;
this.open = open;
this.close = close;
this.volume = volume;
}
public HeikinAshiCandle(Bar ta4jBar) {
this.closeTime = new Timestamp(ta4jBar.getEndTime().toLocalDateTime().getNano());
this.high = ta4jBar.getHighPrice().doubleValue();
this.low = ta4jBar.getLowPrice().doubleValue();
this.open = ta4jBar.getOpenPrice().doubleValue();
this.close = ta4jBar.getClosePrice().doubleValue();
this.candleDirection = (this.close > this.open) ? CandleDirection.UP : CandleDirection.DOWN;
this.volume = ta4jBar.getVolume().doubleValue();
}
public HeikinAshiCandle(HeikinAshiCandle previous, Candle candle) {
if (previous == null) {
throw new NullPointerException("Previous candle cannot be null. Pass the exchange candle for first period.");
}
this.open = this.calculateOpen(previous);
this.close = this.calculateClose(candle.getOpen(), candle.getHigh(), candle.getLow(), candle.getClose());
this.high = this.calculateHigh(candle.getHigh());
this.low = this.calculateLow(candle.getLow());
this.candleDirection = (this.close > this.open) ? CandleDirection.UP : CandleDirection.DOWN;
this.closeTime = new Timestamp(candle.getCandleCloseTime().getTime());
this.volume = candle.getVolume();
}
/**
* @param previous Previous candle, should not be null, for starting period pass the exchange
* candle.
*/
public HeikinAshiCandle(HeikinAshiCandle previous, Timestamp closeTime, double high, double low, double open, double close, double volume) {
if (previous == null) {
throw new NullPointerException("Previous candle cannot be null. Pass the exchange candle for first period.");
}
this.open = this.calculateOpen(previous);
this.close = this.calculateClose(open, high, low, close);
this.high = this.calculateHigh(high);
this.low = this.calculateLow(low);
this.candleDirection = (this.close > this.open) ? CandleDirection.UP : CandleDirection.DOWN;
this.closeTime = closeTime;
this.volume = volume;
}
private double calculateClose(double open, double high, double low, double close) {
return (open + high + low + close) / 4;
}
private double calculateHigh(double high) {
return Double.max(Double.max(high, this.open), this.close);
}
private double calculateLow(double low) {
return Double.min(Double.min(low, this.open), this.close);
}
private double calculateOpen(HeikinAshiCandle previous) {
return (previous.getOpen() + previous.getClose()) * 0.5;
}
/**
* @return Returns the candle time of close
*/
@Override
public Timestamp getCandleCloseTime() {
return this.closeTime;
}
/**
* @return Returns whether the candle was positive or negative (green or red)
* When close greater than open, return up, else down
*/
@Override
public CandleDirection getCandleDirection() {
return this.candleDirection;
}
/**
* @return Returns the candle period as an enum
*/
@Override
public CandlePeriod getCandlePeriod() {
if (this.candlePeriod == null) {
throw new NullPointerException("You need to set a candle period!");
}
return this.candlePeriod;
}
/**
* @param period the period this candle represents in a timeframe enum
*/
@Override
public void setCandlePeriod(CandlePeriod period) {
this.candlePeriod = period;
}
/**
* @return Returns the close of the candle
*/
@Override
public double getClose() {
return this.close;
}
/**
* @return Returns the high of the candle
*/
@Override
public double getHigh() {
return this.high;
}
/**
* @return Returns the low of the candle period
*/
@Override
public double getLow() {
return this.low;
}
/**
* @return Returns the Open of the candle period
*/
@Override
public double getOpen() {
return this.open;
}
/**
* @return Candle type for this candle instance
*/
@Override
public CandleType getType() {
return CandleType.HEIKINASHI;
}
/**
* @return returns the volume for this candle
*/
@Override
public double getVolume() {
return this.volume;
}
@Override
public String toString() {
return "HeikinAshiCandle{" +
"high=" + high +
", low=" + low +
", open=" + open +
", close=" + close +
", volume=" + volume +
", closeTime=" + closeTime +
", candlePeriod=" + candlePeriod +
", candleDirection=" + candleDirection +
'}';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment