Painted Bars with MACD Gradient

GeonsVL

Member
Joined
Sep 19, 2019
Posts
18
Likes
6
Hi to all!
With inspiration of Painted Trend, I want to see in MotiveWave the classic Tradestation MACD Gradient.

Is there anyone else out there that is interested in that indicator?
Any help from some MW API guru?
 
Here is my simple MACD with colored histogram:

package study_examples;

import com.motivewave.platform.sdk.common.DataContext;
import com.motivewave.platform.sdk.common.Defaults;
import com.motivewave.platform.sdk.common.Enums;
import com.motivewave.platform.sdk.common.Inputs;
import com.motivewave.platform.sdk.common.LineInfo;
import com.motivewave.platform.sdk.common.Util;
import com.motivewave.platform.sdk.common.desc.*;
import com.motivewave.platform.sdk.study.Study;
import com.motivewave.platform.sdk.study.StudyHeader;

import java.awt.Color;

@StudyHeader(
namespace = "com.mycompany",
id = "ColorMACD",
name = "My Color MACD",
desc = "MACD with user-configurable 4-color histogram.",
menu = "My Studies",
overlay = false
)
public class ColorMACD extends Study {
enum Values { MACD, SIGNAL, HIST }
final static String HIST_IND = "histInd";

// User-configurable histogram color keys
final static String COLOR_RISE_ABOVE = "riseAboveZeroColor";
final static String COLOR_FALL_ABOVE = "fallAboveZeroColor";
final static String COLOR_RISE_BELOW = "riseBelowZeroColor";
final static String COLOR_FALL_BELOW = "fallBelowZeroColor";

@Override
public void initialize(Defaults defaults) {
var sd = createSD();
var tab = sd.addTab("General");

var grp = tab.addGroup("Inputs");
grp.addRow(new InputDescriptor(Inputs.INPUT, "Input", Enums.BarInput.CLOSE));
grp.addRow(new IntegerDescriptor(Inputs.PERIOD, "Period 1", 12, 1, 9999, 1));
grp.addRow(new IntegerDescriptor(Inputs.PERIOD2, "Period 2", 26, 1, 9999, 1));
grp.addRow(new IntegerDescriptor(Inputs.SIGNAL_PERIOD, "Signal Period", 9, 1, 9999, 1));

tab = sd.addTab("Display");

grp = tab.addGroup("Paths");
grp.addRow(new PathDescriptor(Inputs.PATH, "MACD Path", defaults.getLineColor(), 1.5f, null, true, false, true));
grp.addRow(new PathDescriptor(Inputs.SIGNAL_PATH, "Signal Path", defaults.getRed(), 1.0f, null, true, false, true));
grp.addRow(new BarDescriptor(Inputs.BAR, "Default Bar Color", defaults.getBarColor(), true, true));

grp = tab.addGroup("Histogram Colors");
grp.addRow(new ColorDescriptor(COLOR_RISE_ABOVE, "Rising Above Zero", Color.GREEN));
grp.addRow(new ColorDescriptor(COLOR_FALL_ABOVE, "Falling Above Zero", new Color(0, 128, 0)));
grp.addRow(new ColorDescriptor(COLOR_RISE_BELOW, "Rising Below Zero", Color.CYAN));
grp.addRow(new ColorDescriptor(COLOR_FALL_BELOW, "Falling Below Zero", Color.RED));

grp = tab.addGroup("Indicators");
grp.addRow(new IndicatorDescriptor(Inputs.IND, "MACD Ind", null, null, false, true, true));
grp.addRow(new IndicatorDescriptor(Inputs.SIGNAL_IND, "Signal Ind", defaults.getRed(), null, false, false, true));
grp.addRow(new IndicatorDescriptor(HIST_IND, "Hist Ind", defaults.getBarColor(), null, false, false, true));

var desc = createRD();
desc.setMinTick(0.0001);
desc.setLabelSettings(Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD);

desc.exportValue(new ValueDescriptor(Values.MACD, "MACD", new String[]{Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2}));
desc.exportValue(new ValueDescriptor(Values.SIGNAL, "MACD Signal", new String[]{Inputs.SIGNAL_PERIOD}));
desc.exportValue(new ValueDescriptor(Values.HIST, "MACD Histogram", new String[]{Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD}));

desc.declarePath(Values.MACD, Inputs.PATH);
desc.declarePath(Values.SIGNAL, Inputs.SIGNAL_PATH);
desc.declareBars(Values.HIST, Inputs.BAR);

desc.declareIndicator(Values.MACD, Inputs.IND);
desc.declareIndicator(Values.SIGNAL, Inputs.SIGNAL_IND);
desc.declareIndicator(Values.HIST, HIST_IND);

desc.setRangeKeys(Values.MACD, Values.SIGNAL, Values.HIST);
desc.addHorizontalLine(new LineInfo(0, null, 1.0f, new float[]{3, 3}));
}

@Override
protected void calculate(int index, DataContext ctx) {
int period1 = getSettings().getInteger(Inputs.PERIOD);
int period2 = getSettings().getInteger(Inputs.PERIOD2);
int period = Util.max(period1, period2);
if (index < period) return;

Object input = getSettings().getInput(Inputs.INPUT);
var series = ctx.getDataSeries();
Double ma1 = series.ema(index, period1, input);
Double ma2 = series.ema(index, period2, input);
if (ma1 == null || ma2 == null) return;

double macd = ma1 - ma2;
series.setDouble(index, Values.MACD, macd);

int signalPeriod = getSettings().getInteger(Inputs.SIGNAL_PERIOD);
if (index < period + signalPeriod) return;

Double signal = series.sma(index, signalPeriod, Values.MACD);
if (signal == null) return;

series.setDouble(index, Values.SIGNAL, signal);

double hist = macd - signal;
series.setDouble(index, Values.HIST, hist);

Double prevHist = series.getDouble(index - 1, Values.HIST);
boolean isRising = prevHist != null && hist > prevHist;

// Use user-selected colors
Color riseAbove = getSettings().getColor(COLOR_RISE_ABOVE);
Color fallAbove = getSettings().getColor(COLOR_FALL_ABOVE);
Color riseBelow = getSettings().getColor(COLOR_RISE_BELOW);
Color fallBelow = getSettings().getColor(COLOR_FALL_BELOW);

Color barColor;
if (hist >= 0) {
barColor = isRising ? riseAbove : fallAbove;
} else {
barColor = isRising ? riseBelow : fallBelow;
}

series.setBarColor(index, Values.HIST, barColor);
series.setComplete(index);
}
}
 
I added Squeeze dots to the zero line (BB inside KC: Squeeze on, red, BB outside KC: Squeeze off, green):

package ColorMACD;

import com.motivewave.platform.sdk.common.DataContext;
import com.motivewave.platform.sdk.common.Defaults;
import com.motivewave.platform.sdk.common.Enums;
import com.motivewave.platform.sdk.common.Inputs;
import com.motivewave.platform.sdk.common.LineInfo;
import com.motivewave.platform.sdk.common.Util;
import com.motivewave.platform.sdk.common.desc.*;
import com.motivewave.platform.sdk.study.Study;
import com.motivewave.platform.sdk.study.StudyHeader;

import java.awt.Color;

@StudyHeader(
namespace = "com.mycompany",
id = "ColorMACD",
name = "My Color MACD",
desc = "MACD with user-configurable 4-color histogram.",
menu = "My Studies",
overlay = false
)
public class ColorMACD extends Study {
enum Values { MACD, SIGNAL, HIST }
final static String HIST_IND = "histInd";

// User-configurable histogram color keys
final static String COLOR_RISE_ABOVE = "riseAboveZeroColor";
final static String COLOR_FALL_ABOVE = "fallAboveZeroColor";
final static String COLOR_RISE_BELOW = "riseBelowZeroColor";
final static String COLOR_FALL_BELOW = "fallBelowZeroColor";

@Override
public void initialize(Defaults defaults) {
var sd = createSD();
var tab = sd.addTab("General");

var grp = tab.addGroup("Inputs");
grp.addRow(new InputDescriptor(Inputs.INPUT, "Input", Enums.BarInput.CLOSE));
grp.addRow(new IntegerDescriptor(Inputs.PERIOD, "Period 1", 12, 1, 9999, 1));
grp.addRow(new IntegerDescriptor(Inputs.PERIOD2, "Period 2", 26, 1, 9999, 1));
grp.addRow(new IntegerDescriptor(Inputs.SIGNAL_PERIOD, "Signal Period", 9, 1, 9999, 1));

tab = sd.addTab("Display");

grp = tab.addGroup("Paths");
grp.addRow(new PathDescriptor(Inputs.PATH, "MACD Path", defaults.getLineColor(), 1.5f, null, true, false, true));
grp.addRow(new PathDescriptor(Inputs.SIGNAL_PATH, "Signal Path", defaults.getRed(), 1.0f, null, true, false, true));
grp.addRow(new BarDescriptor(Inputs.BAR, "Default Bar Color", defaults.getBarColor(), true, true));

grp = tab.addGroup("Histogram Colors");
grp.addRow(new ColorDescriptor(COLOR_RISE_ABOVE, "Rising Above Zero", Color.GREEN));
grp.addRow(new ColorDescriptor(COLOR_FALL_ABOVE, "Falling Above Zero", new Color(0, 128, 0)));
grp.addRow(new ColorDescriptor(COLOR_RISE_BELOW, "Rising Below Zero", Color.CYAN));
grp.addRow(new ColorDescriptor(COLOR_FALL_BELOW, "Falling Below Zero", Color.RED));

grp = tab.addGroup("Indicators");
grp.addRow(new IndicatorDescriptor(Inputs.IND, "MACD Ind", null, null, false, true, true));
grp.addRow(new IndicatorDescriptor(Inputs.SIGNAL_IND, "Signal Ind", defaults.getRed(), null, false, false, true));
grp.addRow(new IndicatorDescriptor(HIST_IND, "Hist Ind", defaults.getBarColor(), null, false, false, true));

var desc = createRD();
desc.setMinTick(0.0001);
desc.setLabelSettings(Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD);

desc.exportValue(new ValueDescriptor(Values.MACD, "MACD", new String[]{Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2}));
desc.exportValue(new ValueDescriptor(Values.SIGNAL, "MACD Signal", new String[]{Inputs.SIGNAL_PERIOD}));
desc.exportValue(new ValueDescriptor(Values.HIST, "MACD Histogram", new String[]{Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD}));

desc.declarePath(Values.MACD, Inputs.PATH);
desc.declarePath(Values.SIGNAL, Inputs.SIGNAL_PATH);
desc.declareBars(Values.HIST, Inputs.BAR);

desc.declareIndicator(Values.MACD, Inputs.IND);
desc.declareIndicator(Values.SIGNAL, Inputs.SIGNAL_IND);
desc.declareIndicator(Values.HIST, HIST_IND);

desc.setRangeKeys(Values.MACD, Values.SIGNAL, Values.HIST);
desc.addHorizontalLine(new LineInfo(0, null, 1.0f, new float[]{3, 3}));
}

@Override
protected void calculate(int index, DataContext ctx) {
int period1 = getSettings().getInteger(Inputs.PERIOD);
int period2 = getSettings().getInteger(Inputs.PERIOD2);
int period = Util.max(period1, period2);
if (index < period) return;

Object input = getSettings().getInput(Inputs.INPUT);
var series = ctx.getDataSeries();
Double ma1 = series.ema(index, period1, input);
Double ma2 = series.ema(index, period2, input);
if (ma1 == null || ma2 == null) return;

double macd = ma1 - ma2;
series.setDouble(index, Values.MACD, macd);

int signalPeriod = getSettings().getInteger(Inputs.SIGNAL_PERIOD);
if (index < period + signalPeriod) return;

Double signal = series.sma(index, signalPeriod, Values.MACD);
if (signal == null) return;

series.setDouble(index, Values.SIGNAL, signal);

double hist = macd - signal;
series.setDouble(index, Values.HIST, hist);

Double prevHist = series.getDouble(index - 1, Values.HIST);
boolean isRising = prevHist != null && hist > prevHist;

// Use user-selected colors
Color riseAbove = getSettings().getColor(COLOR_RISE_ABOVE);
Color fallAbove = getSettings().getColor(COLOR_FALL_ABOVE);
Color riseBelow = getSettings().getColor(COLOR_RISE_BELOW);
Color fallBelow = getSettings().getColor(COLOR_FALL_BELOW);

Color barColor;
if (hist >= 0) {
barColor = isRising ? riseAbove : fallAbove;
} else {
barColor = isRising ? riseBelow : fallBelow;
}

series.setBarColor(index, Values.HIST, barColor);
series.setComplete(index);
}
}
 
Top