## 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);
    }