Envelope Support / Resistance

#region Namespaces 
using System;
using System.IO;
using System.Linq;
#endregion

namespace ScriptCode {
	/// <summary>
	/// This is a range-bound trading strategy that generates trade signals using support and resistance levels defined by moving average Envelopes. 
	/// The lower Envelope is the specified percentage below the 14-period exponentially weighted moving average (EMA) of the Close price and represents the support level.
	/// The upper Envelope is the specified percentage above the 14-period EMA of the Close price and represents the resistance level. 
	/// 
	/// Support and resistance margin parameters are included to determine when the Close price enters the support or resistance area. 
	/// The support margin level is the specified percent above the lower Envelope while the resistance margin level is the specified percent below the upper Envelope. 
	/// A buy signal is generated when the Close price enters the area between the lower Envelope and support margin level while a sell signal is generated when the Close price enters the area between the upper Envelope and resistance margin level.
	/// 
	/// Trading Rules: 
	/// 
	/// Long Entry: A buy market order is generated when the Close price is at or between the lower Envelope and the support margin level.
	/// Long Exit: A sell market order is generated when the Close price is at or between the upper Envelope and the resistance margin level.
	/// 
	/// Short Entry: A sell short market order is generated when the Close price is at or between the upper Envelope and the resistance margin level.
	/// Short Exit: A buy-to-cover market order is generated when the Close price is at or between the lower Envelope and the support margin level.
	/// </summary>
	public partial class MyTradingStrategy : TradingStrategyScriptBase  // NEVER CHANGE THE CLASS NAME 
	{
#region Variables
		// The trigger indicator.
		private Indicator _indicator;
		// The lower envelope support indicator.
		private Indicator _supportIndicator;
		// The upper envelope resistance indicator.
		private Indicator _resistanceIndicator;
		// The percentage distance from the support level in which support starts.
		private double _supportMargin;
		// The percentage distance from the resistance level in which resistance starts.
		private double _resistanceMargin;
		// Indicates whether to enable the trading strategy script to short symbols.  
		private bool _enableShorting;
		// Indicates whether to enable the trading strategy script to long symbols.  
		private bool _enableLonging;
		// The percent distance from the entry price in which to place a stop loss order.
		private double _stopLoss;
		// The percent distance from the entry price in which to place a take profit order. 
		private double _takeProfit;
#endregion

#region OnInitialize
		/// <summary>
		/// This function is used for accepting the script parameters and for initializing the script prior to all other function calls.
		/// Once the script is assigned to a desktop, its parameter values can be specified by the user and can be selected for optimization. 
		/// </summary>
		/// --------------------------------------------------------------------------------------------------
		/// PLEASE USE THE SCRIPT WIZARD (CTRL+W) TO ADD, EDIT AND REMOVE THE SCRIPT PARAMETERS
		/// --------------------------------------------------------------------------------------------------
		/// YOU MUST SET A PARAM TAG FOR EACH PARAMETER ACCEPTED BY THIS FUNCTION.
		/// ALL PARAM TAGS SHOULD BE SET IN THE 'OnInitialize' REGION, RIGHT ABOVE THE 'OnInitialize' FUNCTION.
		/// THE ORDER OF THE TAGS MUST MATCH THE ORDER OF THE ACTUAL PARAMETERS.

		/// REQUIRED ATTRIBUTES:
		/// (1) name: The exact parameter name.
		/// (2) type: The type of data to collect from the user: 
		/// Set to "Integer" when the data type is 'int'
		/// Set to "IntegerArray" when the data type is 'int[]'
		/// Set to "DateTime" when the data type is 'long'  
		/// Set to "DateTimeArray" when the data type is 'long[]'  
		/// Set to "Boolean" when the data type is 'bool'
		/// Set to "BooleanArray" when the data type is 'bool[]'
		/// Set to "Double" when the data type is 'double'
		/// Set to "DoubleArray" when the data type is 'double[]'
		/// Set to "String" when the data type is 'string'
		/// Set to "StringArray" when the data type is 'string[]'
		/// Set to "Indicator" when the data type is 'Indicator'
		/// Set to "Pattern" when the data type is 'Pattern'
		/// Set to "Signal" when the data type is 'Signal'
		/// Set to "Drawing" when the data type is 'Drawing'

		/// OPTIONAL ATTRIBUTES:
		/// (3) default: The default parameter value is only valid when the type is Integer, Boolean, Double, String or an API Type. 
		/// (4) min: The minimum parameter value is only valid when the type is Integer or Double.
		/// (5) max: The maximum parameter value is only valid when the type is Integer or Double.

		/// EXAMPLE: <param name="" type="" default="" min="" max="">Enter the parameter description here.</param> 
		/// --------------------------------------------------------------------------------------------------
		/// <param name="indicatorColor" type="C_Color" default="ROYAL_BLUE">The color of the indicator.</param>
		/// <param name="supportIndicatorColor" type="C_Color" default="GREEN">The color of the support indicator.</param>
		/// <param name="supportIndicatorPercent" type="Double" default="3">The percentage distance from the close for the support envelope. </param>
		/// <param name="resistanceIndicatorColor" type="C_Color" default="GREEN">The color of the resistance indicator.</param>
		/// <param name="resistanceIndicatorPercent" type="Double" default="3">The percentage distance from the close for the resistance envelope. </param>
		/// <param name="supportMargin" type="Double" default="0.2">The percentage distance from the support level in which support starts. </param>
		/// <param name="resistanceMargin" type="Double" default="0.2">The percentage distance from the resistance level in which resistance starts.</param>
		/// <param name="enableShorting" type="Boolean" default="True">Indicates whether to enable the trading strategy to short symbols. </param>
		/// <param name="enableLonging" type="Boolean" default="True">Indicates whether to enable the trading strategy to long symbols. </param>
		/// <param name="stopLoss" type="Double" default="0">The percent distance from the entry price in which to place a stop loss order. (0 to ignore). </param>
		/// <param name="takeProfit" type="Double" default="0">The percent distance from the entry price in which to place a take profit order. (0 to ignore). </param>
		public void OnInitialize(
			C_Color indicatorColor,
			C_Color supportIndicatorColor,
			double supportIndicatorPercent,
			C_Color resistanceIndicatorColor,
			double resistanceIndicatorPercent,
			double supportMargin,
			double resistanceMargin,
			bool enableShorting,
			bool enableLonging,
			double stopLoss,
			double takeProfit) {
			// Set the script parameters to script variables. 
			_supportMargin = supportMargin;
			_resistanceMargin = resistanceMargin;
			_enableShorting = enableShorting;
			_enableLonging = enableLonging;
			_stopLoss = stopLoss;
			_takeProfit = takeProfit;

			// Remove all of the indicators from the chart so that we don't get duplicates.
			ChartIndicatorRemoveAll(SymbolIndex());			
			// Create the close indicator for the underlying symbol.
			_indicator = IndicatorCLOSE(SymbolIndex());
			// Plot the indicator on the underlying symbol's chart.
			int indicatorItemID = ChartIndicatorPlot(SymbolIndex(), _indicator, "", - 1, 1);
			// Set the indicator pen.
			ChartIndicatorSetPenByIndex(SymbolIndex(), indicatorItemID, 0, indicatorColor, C_DashStyle.SOLID, 2);

			// Create the lower envelope indicator for the underlying symbol.
			_supportIndicator = IndicatorENVL(IndicatorCLOSE(SymbolIndex()), supportIndicatorPercent, 14);
			// Plot the indicator on the underlying symbol's chart.
			int supportIndicatorItemID = ChartIndicatorPlot(SymbolIndex(), _supportIndicator, "", - 1, 1);
			// Set the indicator pen.
			ChartIndicatorSetPenByIndex(SymbolIndex(), supportIndicatorItemID, 0, supportIndicatorColor, C_DashStyle.SOLID, 2);

			// Create the upper envelope indicator for the underlying symbol.
			_resistanceIndicator = IndicatorENVU(IndicatorCLOSE(SymbolIndex()), resistanceIndicatorPercent, 14);
			// Plot the indicator on the underlying symbol's chart.
			int resistanceIndicatorID = ChartIndicatorPlot(SymbolIndex(), _resistanceIndicator, "", - 1, 1);
			// Set the indicator pen.
			ChartIndicatorSetPenByIndex(SymbolIndex(), resistanceIndicatorID, 0, resistanceIndicatorColor, C_DashStyle.SOLID, 2);
		}
#endregion

#region OnBarUpdate
		/// <summary>
		/// This function is called after each new bar of each symbol assigned to the Desktop strategy. 
		/// It should evaluate the specified symbol and its new bar in order to determine whether to generate new orders for it. 
		/// Never create indicators, signals or patterns from OnBarUpdate, for performance reasons those should be created from OnInitialize.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The index of the symbol in the strategy symbol table</param>
		/// <param name="dataSeries" type="Integer">The number indicating the data series from which the symbol was updated. 
		/// According to the Desktop strategy data series settings: 0 for the main data series, 1 for the second data series, etc. (See the DataSeriesSwitch function).</param>
		/// <param name="completedBars" type="Integer">The number of completed bars for the specified symbol since the last call to OnBarUpdate.
		/// Always 1 unless the bar type can generate multiple completed bars from a single tick/minute/day update (depending on the underlying bar source).</param>
		public override void OnBarUpdate(
			int symbolIndex,
			int dataSeries,
			int completedBars) {
			// Get the current indicator value. 
			double value = _indicator[0];
			// Get the current support indicator value. 
			double supportValue = _supportIndicator[0];
			// Get the current resistance indicator value.
			double resistanceValue = _resistanceIndicator[0];

			// Check whether the indicator is near the support level.
			if (supportValue <= value && value <= supportValue * (1 + (_supportMargin / 100))) {
				// Check whether there is an open short position. 
				if (_enableShorting && PositionExistsInDirection(C_PositionStatus.OPEN, C_Direction.SHORT_SIDE)) {
					// Generate a buy to cover market order. 
					BrokerMarket(C_ActionType.BUY_TO_COVER, 0, C_TIF.DAY, "Indicator hit support.");
				}
				// Check whether there are no open long position.
				if (_enableLonging && !PositionExistsInDirection(C_PositionStatus.OPEN, C_Direction.LONG_SIDE) && !OrderExists(C_Status.PENDING)) {
					// Generate a buy market order. 
					int orderIndex = BrokerMarket(C_ActionType.BUY, 0, C_TIF.DAY, "Indicator hit support. ");
					// Set a stop loss on the order. 
					BrokerSetStopLossPercent(orderIndex, _stopLoss, true, "");
					// Set a take profit on the order. 
					BrokerSetTakeProfitPercent(orderIndex, _takeProfit, true, "");
				}
			}
			// Check whether the indicator is near the resistance level.
			else if (resistanceValue * (1 - (_resistanceMargin / 100)) <= value && value <= resistanceValue) {
				// Check whether there is an open long position. 
				if (_enableLonging && PositionExistsInDirection(C_PositionStatus.OPEN, C_Direction.LONG_SIDE)) {
					// Generate a sell market order. 
					BrokerMarket(C_ActionType.SELL, 0, C_TIF.DAY, "Indicator hit resistance.");
				}
				// Check whether there are no open short position. 
				if (_enableShorting && !PositionExistsInDirection(C_PositionStatus.OPEN, C_Direction.SHORT_SIDE) && !OrderExists(C_Status.PENDING)) {
					// Generate a sell short market order. 
					int orderIndex = BrokerMarket(C_ActionType.SELL_SHORT, 0, C_TIF.DAY, "Indicator hit resistance.");
					// Set a stop loss on the order. 
					BrokerSetStopLossPercent(orderIndex, _stopLoss, true, "");
					// Set a take profit on the order. 
					BrokerSetTakeProfitPercent(orderIndex, _takeProfit, true, "");
				}
			}
		}
#endregion

#region OnOrderUpdate
		/// <summary>
		/// This function is called when an order is executed or cancelled.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index</param>
		/// <param name="orderIndex" type="Integer">The order index</param>
		/// <param name="status" type="C_Status">The updated status of the order</param>
		public override void OnOrderUpdate(
			int symbolIndex,
			int orderIndex,
			C_Status status) {
			// OnOrderUpdate Content
		}
#endregion

#region OnPositionUpdate
		/// <summary>
		/// This function is called when a position is opened or closed. 
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index</param>
		/// <param name="positionIndex" type="Integer">The position index</param>
		/// <param name="status" type="C_PositionStatus">The updated status of the position</param>
		public override void OnPositionUpdate(
			int symbolIndex,
			int positionIndex,
			C_PositionStatus status) {
			// OnPositionUpdate Content
		}
#endregion

#region OnNewsUpdate
		/// <summary>
		/// This function is called when a news update is received and only if the NO_NEWS_UPDATES comment is removed.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index for the update</param>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="title" type="String">The update title</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnNewsUpdate(
			int symbolIndex,
			long dateTime,
			string title,
			string message,
			C_MessageType type) {
			// OnNewsUpdate Content
			// [NO_NEWS_UPDATES] - Delete this comment to enable news updates to this strategy.
		}
#endregion

#region OnRSSUpdate
		/// <summary>
		/// This function is called when an RSS update is received and only if the NO_RSS_UPDATES comment is removed.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index for the update</param>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="title" type="String">The update title</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnRSSUpdate(
			int symbolIndex,
			long dateTime,
			string title,
			string message,
			C_MessageType type) {
			// OnRSSUpdate Content
			// [NO_RSS_UPDATES] - Delete this comment to enable RSS updates to this strategy.
		}
#endregion

#region OnAlertUpdate
		/// <summary>
		/// This function is called when an alert update is received and only if the NO_ALERT_UPDATES comment is removed.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index for the update</param>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnAlertUpdate(
			int symbolIndex,
			long dateTime,
			string message,
			C_MessageType type) {
			// OnAlertUpdate Content
			// [NO_ALERT_UPDATES] - Delete this comment to enable alert updates to this strategy.
		}
#endregion

#region OnJournalUpdate
		/// <summary>
		/// This function is called when a journal update is received and only if the NO_JOURNAL_UPDATES comment is removed.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index for the update</param>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="title" type="String">The update title</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnJournalUpdate(
			int symbolIndex,
			long dateTime,
			string title,
			string message,
			C_MessageType type) {
			// OnJournalUpdate Content
			// [NO_JOURNAL_UPDATES] - Delete this comment to enable journal updates to this strategy.
		}
#endregion

#region OnDataConnectionUpdate
		/// <summary>
		/// This function is called when a data connection update is received and only if the NO_DATA_CONNECTION_UPDATES comment is removed.
		/// </summary>
		/// <param name="symbolIndex" type="Integer">The symbol index for the update</param>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnDataConnectionUpdate(
			int symbolIndex,
			long dateTime,
			string message,
			C_MessageType type) {
			// OnDataConnectionUpdate Content
			// [NO_DATA_CONNECTION_UPDATES] - Delete this comment to enable data connection updates to this strategy.
		}
#endregion

#region OnBrokerConnectionUpdate
		/// <summary>
		/// This function is called when a broker connection update is received and only if the NO_BROKER_CONNECTION_UPDATES comment is removed.
		/// </summary>
		/// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param>
		/// <param name="message" type="String">The update message</param>   
		/// <param name="type" type="C_MessageType">The message type</param>
		public override void OnBrokerConnectionUpdate(
			long dateTime,
			string message,
			C_MessageType type) {
			// OnBrokerConnectionUpdate Content
			// [NO_BROKER_CONNECTION_UPDATES] - Delete this comment to enable broker connection updates to this strategy.
		}
#endregion

#region OnShutdown
		/// <summary>
		/// This function is called when the script is shutdown.
		/// </summary>
		public override void OnShutdown() {
			// OnShutdown Content
		}
#endregion
	}
}