How to Write an Indicator Plugin

Here is a brief idea of how to write an indicator plugin for Qtstalker. I will take an actual plugin and walk you through it. We will use the MA plugin as the example.


Using Settings

Settings are used to store values that can be changed by the user. Each setting has 3 elements. Here is an example setting:
set(tr("Color"), "red", Setting::Color);
The first field tr("Color"), is the key, or how the setting will be refered to as. The user will see this as the setting name.
The second field "red", is the actual value of the setting. The user will see this as the setting value and will be able to modify it.
The third field Setting::Color, is the type of setting to create. This defines how the setting will be edited. Look at Setting.h for more info on what setting types are available.

Each indicator will have different settings depending on the needs of the indicator.

About Alerts

The alert function returns an array of ints. Each element of the alert array can have only 3 values. The 3 values are -1,0,1. A value of -1 means we are short. A value of 0 means we are out. A value 1 means we are long. The alert array will always be the same size as the original data the indicator used to calculate. So to create the alert array you simply begin where the indicator data starts relative to the input data, decide if you are short, long or out and put the appropriate value into the array. You then repeat this for every element advancing forward until you reach the end of data. Then the array of ints is returned to Qtstalker.

Plugin Header

#include "IndicatorPlugin.h"

class MA : public IndicatorPlugin
{
public:
MA ();

// This must be a virtual destructor
virtual ~MA ();

// This function is called by Qtstalker to create the data that plots to the screen. Re-implement this function
void calculate ();

// This optional function is called by Qtstalker to issue alerts for backtesting. Re-implement this function
QMemArray<int> getAlerts ();
};

// Every plugin must have this function placed here at the end of the header file.
extern "C"
{
Plugin * create ();
}

Plugin Implementation

#include "MA.h"

MA::MA ()
{
// This is what you will call your plugin.
pluginName = "MA";

// All plugins are version 0.2 right now.
version = 0.2;

// This is where you define the user and internal settings. Basically all the defaults.

// Every plugin must have this setting. Dont change this.
set(tr("Type"), pluginName, Setting::None);

// This sets to the color of the MA
set(tr("Color"), "red", Setting::Color);

// This sets the type of line the for MA
set(tr("Line Type"), tr("Line"), Setting::LineType);

// This sets the text that will label the MA
set(tr("Label"), pluginName, Setting::Text);

// This sets the period of the MA
set(tr("Period"), "10", Setting::Integer);

// This sets what input data will be used to base the MA on.
set(tr("Input"), tr("Close"), Setting::InputField);

// This sets the type of MA to use
set(tr("MA Type"), "SMA", Setting::MAType);

// All plugins must have this setting. This setting defines which of the 2 plot areas the indicator will be assigned.
// A true value means that the indicator will use the main plot.
// A false value means indicator will plot on the tabbed area.
set(tr("Plot"), tr("True"), Setting::None);

// All plugins must have this setting. This setting defines if there is an alert function available to use.
// True means there is an alert function available
// False means there is no alert function available
set(tr("Alert"), tr("True"), Setting::None);

// This is for a brief description of the plugin function.
about = "Moving Average\n";
}

MA::~MA ()
{
}

// All plugins must re-implement this function. This is where we perform the indicator calculations and produce the data to be plotted.
void MA::calculate ()
{
// Here I am getting the current period setting for the MA
int period = getInt(tr("Period"));

// Here we are getting the input data to base our MA on
PlotLine *in = getInput(getData(tr("Input")));

// Here we use the IndicatorPlugin::getMA function to get an MA
PlotLine *data = getMA(in, getData(tr("MA Type")), period);

// Just cleaning up here
delete in;

// Here we are setting the color of the MA
data->setColor(getData(tr("Color")));

// Here we are setting the line type of the MA
data->setType(getData(tr("Line Type")));

// Here we are setting the label of the MA
data->setLabel(getData(tr("Label")));

// Here is where we assign the MA to be plotted.
output.append(data);
}

// If you want your plugin to issue alerts for backtesting, then re-implement this function
QMemArray<int> MA::getAlerts ()
{
// First we clear any old data
alerts.fill(0, data.count());

// Check to see if there is any plots to scan
if (! output.count())
return alerts;

// get the MA plot data
PlotLine *line = output.at(0);

// get the input data the MA is based on
PlotLine *in = getInput(getData(tr("Input")));

// here we are aligning the MA and input data up for our data pointer
int listLoop = data.count() - line->getSize() + 1;

// this is our MA data index pointer
int lineLoop;

// this is var is where we keep track of the current status of the alerts, -1,0,1 values. We always start off as out = 0.
int status = 0;

for (lineLoop = 1; listLoop < (int) data.count(); lineLoop++, listLoop++)
{
switch (status)
{
// we are currently short, check to see if we need to go long
case -1:
if ((in->getData(listLoop) > line->getData(lineLoop)) && (in->getData(listLoop - 1) >= line->getData(lineLoop - 1)))
// we are switching to long
status = 1;
break;

// we are currently long, check to see if need to go short
case 1:
if ((in->getData(listLoop) < line->getData(lineLoop)) && (in->getData(listLoop - 1) <= line->getData(lineLoop - 1)))
// we are switching to short
status = -1;
break;

// we are currently out, check to see if we go long or short
default:
if ((in->getData(listLoop) > line->getData(lineLoop)) && (in->getData(listLoop - 1) >= line->getData(lineLoop - 1)))
status = 1;
else
{
if ((in->getData(listLoop) < line->getData(lineLoop)) && (in->getData(listLoop - 1) <= line->getData(lineLoop - 1)))
status = -1;
}
break;
}

// save the current status to the alert array
alerts[listLoop] = status;
}

// clean up
delete in;

// we are done
return alerts;
}

// All plugins must have this function placed here at the end.
Plugin * create ()
{
// Substitute the "MA" with the name of your plugin class
MA *o = new MA;
return ((Plugin *) o);
}