Standard Deviation Channels

Standard Deviation Channels

#region Namespaces
using System;
#endregion 

namespace ScriptCode {
	/// <summary>
	/// Drawing scripts are used for drawing a visual object.
	/// 
	/// This script can be used in several ways:
	/// (1) It can be used on a chart by clicking the chart in order to set the drawing's anchor points.
	/// (2) It can be used from another script by having that script set the drawing's anchor points.
	/// </summary>
	public partial class MyDrawing : DrawingScriptBase // NEVER CHANGE THE CLASS NAME 
	{
#region Variables
		// The symbol index on which the drawing tool will be drawn.
		private int _symbolIndex;
		// The number of standard deviations distance from the linear regression line where to draw the channels.
		private double _standardDeviations;
#endregion

#region OnInitialize
        /// <summary>
        /// This function is called when a new drawing instance is created.
        /// </summary>
        /// --------------------------------------------------------------------------------------------------
        /// THIS FUNCTION MUST ACCEPT THE SYMBOL INDEX PARAMETER AND SHOULD NOT ACCEPT ANY OTHER PARAMETERS.
        /// --------------------------------------------------------------------------------------------------
		/// <param name="symbolIndex" type="Symbol" default="">The symbol index on which the drawing tool will be drawn.</param>
		/// <param name="standardDeviations" type="Double" default="2">The number of standard deviations distance from the linear regression line where to draw the channels.</param>
		public void OnInitialize(
			int symbolIndex,
			double standardDeviations) {
			// Initialize the drawing for the symbol to accept 2 anchor points. 		 
			DrawingInitialize(symbolIndex, 2);
			// Set the icon for the drawing tool.
			DrawingSetIcon("StdDev Channels");
			// Set the symbol index.
			_symbolIndex = symbolIndex;
			// Set the standard deviations.
			_standardDeviations = standardDeviations;
		}
#endregion

#region OnChartSetup
		/// <summary>
		/// This function is used for setting up the drawing on the chart and registering its pens (see the DrawingRegisterPen function).
		/// </summary>
		public override void OnChartSetup() {
			// Register the pen with which to draw the channels.
			DrawingRegisterPen("Line Pen", new int[] {
				22 ,81, 238, 255
			}, C_DashStyle.SOLID, 2);
		}
#endregion

#region OnDraw
		/// <summary>
		/// This function is used to draw the drawing by setting all of its anchor points, lines and labels on a virtual canvas. 
		/// The canvas x-axis values are the date and time of the underlying symbol bars and its y-axis values are the symbol prices. 
		///
		/// The location of the drawing on the canvas is specified by the drawing anchor points, which can either be specified by 
		/// clicking on a chart or from another script (see the Drawing functions).
		/// </summary>
		public override void OnDraw() {
			// Get the X value of anchor point 0. 
			int x1 = DrawingAnchorPointBarShift(0);
			// Get the Y value of anchor point 0. 
			double y1 = DrawingAnchorPointValue(0);
			// Get the X value of anchor point 1. 
			int x2 = DrawingAnchorPointBarShift(1);
			// Get the Y value of anchor point 1. 
			double y2 = DrawingAnchorPointValue(1);

			if (x1 < 0 || x2 < 0)
				return ;

			// Get the Double of bars in the drawing range. 
			int length = Math.Abs(x1 - x2);
			// Get the minimum X.
			int minX = Math.Min(x1, x2);
			// Use for summing the X values. 
			double sumX = 0;
			// Use for summing the Y values. 
			double sumY = 0;
			// Use for summing the X times Y values. 
			double sumXY = 0;
			// Use for summing the X powers 2 values. 
			double sumXPow2 = 0;
			double b = 0;
			double a = 0;

			if (x1 > x2) {
				// Iterate over the values while calculating the linear regression parameters. 
				for (int i = 0; i <= length - 1; i++) {
					sumX += x2 + i;
					sumY += DataClose(minX + i);
					sumXY += (x2 + i) * DataClose(minX + i);
					sumXPow2 += Math.Pow(x2 + i, 2);
				}
			} else {
				// Iterate over the values while calculating the linear regression parameters. 
				for (int i = 0; i <= length - 1; i++) {
					sumX += x1 + i;
					sumY += DataClose(minX + i);
					sumXY += (x1 + i) * DataClose(minX + i);
					sumXPow2 += Math.Pow(x1 + i, 2);
				}
			}
			// Calculate the linear regression line intersect. 
			b = (length * sumXY - (sumX * sumY)) / (length * sumXPow2 - (sumX * sumX));
			// Calculate the linear regression slope. 
			a = (sumY - b * sumX) / length;

			// Calculate the Y value of anchor point 1. 
			y2 = a + b * x2;
			DrawingSetAnchorPoint(1, x2, y2);
			// Draw the middle line. 
			DrawingSetLine("Line Pen", x1, y1, "", x2, y2, "");
			// Calculate the mean Y value 
			double meanY = sumY / length;
			// The standard deviation. 
			double SD = 0;
			for (int i = 0; i <= length - 1; i++) {
				SD += Math.Pow(meanY - DataClose(minX + i), 2);
			}
			// Calculate the standard deviation. 
			SD = _standardDeviations * Math.Sqrt(SD / length);
			// Draw the upper channel. 
			DrawingSetLine("Line Pen", x1, y1 + SD, "", x2, y2 + SD, "");
			// Draw the lower channel. 
			DrawingSetLine("Line Pen", x1, y1 - SD, "", x2, y2 - SD, "");
		}
#endregion
	}
}