Study Plot Example
In this example we are going to create a Study Plot based on a simple MACD. Note: if you would like a more comprehensive MACD example, you can look at the source code for the MACD indicator that exists within MotiveWave™.
MACD stands for ‘Moving Average Convergence/Divergence’ and was written by Gerald Appel in the 1970s. If you would like more information on this study go to: http://en.wikipedia.org/wiki/MACD.
Here is a screen shot of what this study looks like:
Figure 30 - Simple MACD
Here is a screen shot of the Study Dialog that the user will use to configure the Simple MACD:
Let us start by looking at the source code for this study:
1
package study_examples;
2
3
import com.motivewave.platform.sdk.common.*;
4
import com.motivewave.platform.sdk.common.desc.*;
5
import com.motivewave.platform.sdk.study.*;
6
7
/** Simple MACD example. This example shows how to create a Study Plot
8
that is based on the MACD study. For simplicity code from the
9
MotiveWave MACD study has been removed or altered. */
10
@StudyHeader(
11
namespace="com.mycompany",
12
id="SimpleMACD",
13
name="Simple MACD",
14
desc="This is a simple version of the <b>MACD</b> for example purposes.",
15
menu="My Studies",
16
overlay=false)
17
public class SimpleMACD extends Study
18
{
19
// This enumeration defines the variables that we are going to store in the
20
// Data Series
21
enum Values { MACD, SIGNAL, HIST };
22
final static String HIST_IND = "histInd"; // Histogram Parameter
23
24
/** This method initializes the settings and defines the runtime settings. */
25
@Override
26
public void initialize(Defaults defaults)
27
{
28
// Define the settings for this study
29
// We are creating 2 tabs: 'General' and 'Display'
30
SettingsDescriptor settings = new SettingsDescriptor();
31
setSettingsDescriptor(settings);
32
SettingTab tab = new SettingTab("General");
33
settings.addTab(tab);
34
35
// Define the 'Inputs'
36
SettingGroup inputs = new SettingGroup("Inputs");
37
inputs.addRow(new InputDescriptor(Inputs.INPUT, "Input", Enums.BarInput.CLOSE));
38
inputs.addRow(new IntegerDescriptor(Inputs.PERIOD, "Period 1", 12, 1, 9999, 1));
39
inputs.addRow(new IntegerDescriptor(Inputs.PERIOD2, "Period 2", 26, 1, 9999, 1));
40
inputs.addRow(new IntegerDescriptor(Inputs.SIGNAL_PERIOD, "Signal Period", 9, 1, 9999, 1));
41
tab.addGroup(inputs);
42
43
tab = new SettingTab("Display");
44
settings.addTab(tab);
45
// Allow the user to configure the settings for the paths and the histogram
46
SettingGroup paths = new SettingGroup("Paths");
47
tab.addGroup(paths);
48
paths.addRow(new PathDescriptor(Inputs.PATH, "MACD Path",
49
defaults.getLineColor(), 1.5f, null, true, false, true));
50
paths.addRow(new PathDescriptor(Inputs.SIGNAL_PATH, "Signal Path",
51
defaults.getRed(), 1.0f, null, true, false, true));
52
paths.addRow(new BarDescriptor(Inputs.BAR, "Bar Color", defaults.getBarColor(), true, true));
53
// Allow the user to display and configure indicators on the vertical axis
54
SettingGroup indicators = new SettingGroup("Indicators");
55
tab.addGroup(indicators);
56
indicators.addRow(new IndicatorDescriptor(Inputs.IND, "MACD Ind",
57
null, null, false, true, true));
58
indicators.addRow(new IndicatorDescriptor(Inputs.SIGNAL_IND, "Signal Ind",
59
defaults.getRed(), null, false, false, true));
60
indicators.addRow(new IndicatorDescriptor(HIST_IND, "Hist Ind",
61
defaults.getBarColor(), null, false, false, true));
62
63
RuntimeDescriptor desc = new RuntimeDescriptor();
64
setRuntimeDescriptor(desc);
65
desc.setLabelSettings(Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD);
66
// We are exporting 3 values: MACD, SIGNAL and HIST (histogram)
67
desc.exportValue(new ValueDescriptor(Values.MACD, "MACD", new String[]
68
{Inputs.INPUT, Inputs.PERIOD, Inputs.PERIOD2}));
69
desc.exportValue(new ValueDescriptor(Values.SIGNAL, "MACD Signal",
70
new String[] {Inputs.SIGNAL_PERIOD}));
71
desc.exportValue(new ValueDescriptor(Values.HIST, "MACD Histogram", new String[]
72
{Inputs.PERIOD, Inputs.PERIOD2, Inputs.SIGNAL_PERIOD}));
73
// There are two paths, the MACD path and the Signal path
74
desc.declarePath(Values.MACD, Inputs.PATH);
75
desc.declarePath(Values.SIGNAL, Inputs.SIGNAL_PATH);
76
// Bars displayed as the histogram
77
desc.declareBars(Values.HIST, Inputs.BAR);
78
// These are the indicators that are displayed in the vertical axis
79
desc.declareIndicator(Values.MACD, Inputs.IND);
80
desc.declareIndicator(Values.SIGNAL, Inputs.SIGNAL_IND);
81
desc.declareIndicator(Values.HIST, HIST_IND);
82
83
// These variables are used to define the range of the vertical axis
84
desc.setRangeKeys(Values.MACD, Values.SIGNAL, Values.HIST);
85
// Display a 'Zero' line that is dashed.
86
desc.addHorizontalLine(new LineInfo(0, null, 1.0f, new float[] {3,3}));
87
}
88
89
/** This method calculates the MACD values for the data at the given index. */
90
@Override
91
protected void calculate(int index, DataContext ctx)
92
{
93
int period1 = getSettings().getInteger(Inputs.PERIOD);
94
int period2 = getSettings().getInteger(Inputs.PERIOD2);
95
int period = Util.max(period1, period2);
96
if (index < period) return; // not enough data to compute the MAs
97
98
// MACD is the difference between two moving averages.
99
// In our case we are going to use an exponential moving average (EMA)
100
Object input = getSettings().getInput(Inputs.INPUT);
101
DataSeries series = ctx.getDataSeries();
102
Double MA1 = null, MA2 = null;
103
104
MA1 = series.ema(index, period1, input);
105
MA2 = series.ema(index, period2, input);
106
if (MA1 == null || MA2 == null) return;
107
108
// Define the MACD value for this index
109
double MACD = MA1 - MA2;
110
series.setDouble(index, Values.MACD, MACD);
111
112
int signalPeriod = getSettings().getInteger(Inputs.SIGNAL_PERIOD);
113
if (index < period + signalPeriod) return; // Not enough data yet
114
115
// Calculate moving average of MACD (signal path)
116
Double signal = series.sma(index, signalPeriod, Values.MACD);
117
series.setDouble(index, Values.SIGNAL, signal);
118
if (signal == null) return;
119
120
// Histogram is the difference between the MACD and the signal path
121
series.setDouble(index, Values.HIST, MACD - signal);
122
series.setComplete(index);
123
}
124
}
Copied!

StudyHeader Annotation (@StudyHeader)

The main difference in the study header from the previous example is the ‘overlay’ tag is set to false. This indicates to MotiveWave™ that this study should be displayed in a separate study plot. You will notice here as well that we have included some HTML markup in the ‘desc’ tag. The description displayed in the Study Dialog supports HTML so you can put any valid HTML tags here (do not include JavaScript, this is not supported).
Figure 31 - Simple MACD Study Header

initialize method

We have defined a bit more in the initialize section from the previous example. To illustrate the usage of tabs, we have created 2 tabs: ‘General’ and ‘Display’. We have also defined the bars for the histogram (see BarDescriptor).
Indicators are displayed on the vertical axis (right side of the screen). By default, we are only going to show the first indicator (MACD), but we will allow the user to show indicators for the current signal value as well as the histogram. For this we will use the IndicatorDescriptor and set the values accordingly. We have organized these into a Setting Group called ‘Indicators’
The following screen shot (with markup) shows the part of the initialize method where we are describing the settings for the study:
Figure 32 - Simple MACD initialize settings
Next, we need to describe the runtime parameters using the RuntimeDescriptor. For the label, we want to append the input, period, period2 and the signal period.
In this case, we are going to export 3 values: MACD, SIGNAL and HIST.
In order to display the histogram as bars, we use the ‘declareBars’ method on the study descriptor. This will tell MotiveWave™ to show vertical bars using the BarDescriptor identified by Inputs.BAR.
Figure 33 - Simple MACD initialize runtime

calculate Method

The calculate method is used to compute the values for each historical bar in the data series. In our case, we are going to do the following:
  1. 1.
    Retrieve User Settings – these are accessed from the getSettings() method.
  2. 2.
    Compute and Store the MACD – The DataSeries object contains the historical data as well as the utility methods for computing moving averages. The MACD value is stored in the data series at the given index using the key Values.MACD.
  3. 3.
    Compute and Store the signal – The signal is a moving average of the MACD. Use the data series to compute the moving average with Values.MACD as the key. The signal value is stored in the data series at the given index using the key: Values.SIGNAL.
  4. 4.
    Compute and store the histogram – The histogram is simply the difference between the MACD and the signal. This is stored in the data series at the given index using the key: Values.HIST.
  5. 5.
    Mark the index as ‘Complete’ - Finally, indicate that this index is ‘complete’. This allows MotiveWave™ to cache these values (to improve performance).
Figure 34 - Simple MACD calculate method
Last modified 1yr ago