Классический конверт описан во многих источниках.
Для реализации этой стратегии за основу взят скрипт на сайте Wealth-Lab.

В этом конкретном примере открытие позиции выполняется при пробитии верхней границы конверта (по закрытию - то есть цена закрытия больше границы) , которая отсчитывается на некотором расстоянии от простой скользящей средней. Дополнительным условием принимается то, что закрытие последующей свечи происходит выше предыдущей (на которой и произошло пробитие канала), только после этого и происходит открытие позиции.

Закрытие позиции производится при пробитии нижней границы конверта (цена закрытия меньше границы).

В классическом варианте конверта открытие происходит по стоп-ордеру, который выставляется на границе, а закрытие на самой скользящей средней. Однако в нашей реализации сохранена схема первоисточника. Также можно было бы каждую границу (верхнюю и нижнюю) вычислять со своими коэффициентами - это поле для приложения сил творческих пользователей.
Кстати, в нашем примере мы считаем параметры для длинных и коротких позиций отдельно.
И хотя они близки по значениям, но все же так будет "по грамотному".
Вот так эта система выглядит в коде:

Ссылка на файл: http://www.tslab.ru/ubb/ubbthreads.php?ubb=download&Number=1100&filename=envelope_script.cs

Code:
/*================================================================================
 * Стратегия: Envelope (конверт)
 * Платформа: TSLab версия 1.1.7.0
 * Дата создания: 05.07.2010
 * Реализовано: Laber
 *================================================================================*/

using System; 
using System.Collections.Generic;
using TSLab.Script;
using TSLab.Script.Handlers;
using TSLab.Script.Optimization;
using TSLab.Script.Helpers;

namespace TSLab.Envelope
{

	//================================================================================
	public class Envelope : IExternalScript
	{
		// используем переменные-флаги для сигналов
		public bool bBuy; // флаг сигнала открытия длинной позиции
		public bool bSell; // флаг сигнала закрытия длинной позиции
		public bool bShort; // флаг сигнала открытия короткой позиции
		public bool bCover; // флаг сигнала закрытия короткой позиции
		public IPosition LongPos, ShortPos;
		 
		//================================================================================
		// функция вычисления верхней границы конверта (последовательность значений)
		// nSMA - серия значений простой скользящей средней
		// Shift - смещение границы от скользящей средней
		public IList<double> GenHighRange(ISecurity source, IList<double> nSMA, double Shift)
		{
			double vHighRange = 0;
			// серия значений HighRange
			IList<double> nHighRange = new List<double>(source.Bars.Count);

			for (int bar = 0; bar < source.Bars.Count; bar++)
			{
				vHighRange = nSMA[bar] * (1 + Shift);
				//--------------------------------------------------------------------------------
				// добавление нового значения в последовательность
				nHighRange.Add(vHighRange);
			}
			return nHighRange;
		}
		
		//================================================================================
		// функция вычисления нижней границы конверта (последовательность значений)
		// nSMA - серия значений простой скользящей средней
		// Shift - смещение границы от скользящей средней
		public IList<double> GenLowRange(ISecurity source, IList<double> nSMA, double Shift)
		{
			double vLowRange = 0;
			// серия значений LowRange
			IList<double> nLowRange = new List<double>(source.Bars.Count);

			for (int bar = 0; bar < source.Bars.Count; bar++)
			{
				vLowRange = nSMA[bar] * (1 - Shift);
				//--------------------------------------------------------------------------------
				// добавление нового значения в последовательность
				nLowRange.Add(vLowRange);
			}
			return nLowRange;
		}
		
		//================================================================================
		// Параметры оптимизации
		// параметра для длинных позиций
		public OptimProperty LongPeriodParam = new OptimProperty(22, 2, 50, 2);
		public OptimProperty LongShiftParam = new OptimProperty(0.01, 0.01, 0.1, 0.005);
		// параметра для коротких позиций
		public OptimProperty ShortPeriodParam = new OptimProperty(24, 2, 50, 2);
		public OptimProperty ShortShiftParam = new OptimProperty(0.01, 0.01, 0.1, 0.005);

		//================================================================================
		public virtual void Execute(IContext ctx, ISecurity source)
		{
			int StartBar = 0;

			#region Variables
			// для длинных позиций
			int LongPeriod; // период расчета простой скользящей средней SMA
			double LongShift; // смещение границ конверта от скользящей средней
			// для коротких длинных позиций
			int ShortPeriod; // период расчета простой скользящей средней SMA
			double ShortShift; // смещение границ конверта от скользящей средней
			
			#endregion
			//--------------------------------------------------------------------------------
			#region Obtain parameters
			LongPeriod = LongPeriodParam;
			LongShift = LongShiftParam;
			ShortPeriod = ShortPeriodParam;
			ShortShift = ShortShiftParam;

			StartBar = LongPeriod + 1;
			if (ShortPeriod > LongPeriod) StartBar = ShortPeriod + 1;

			// Вычисляем верхнюю и нижнюю границы конверта.
			// Используем GetData для кеширования данных и ускорения оптимизации.
			// для длинных позиций
			// серия для простой скользящей средней SMA
			IList<double> nLongSMA = ctx.GetData("LongSMA", new[] {LongPeriod.ToString()},
			delegate { return Series.SMA(source.ClosePrices, LongPeriod); });
			// серия значений верхней границы
			IList<double> nLongHighRange = ctx.GetData("LongHighRange", new[] {LongPeriod.ToString()+LongShift.ToString()},
			delegate { return GenHighRange(source, nLongSMA, LongShift); });
			// серия значений нижней границы
			IList<double> nLongLowRange = ctx.GetData("LongLowRange", new[] {LongPeriod.ToString()+LongShift.ToString()},
			delegate { return GenLowRange(source, nLongSMA, LongShift); });
			// для коротких позиций
			// серия для простой скользящей средней SMA
			IList<double> nShortSMA = ctx.GetData("ShortSMA", new[] {ShortPeriod.ToString()},
			delegate { return Series.SMA(source.ClosePrices, ShortPeriod); });
			// серия значений верхней границы
			IList<double> nShortHighRange = ctx.GetData("ShortHighRange", new[] {ShortPeriod.ToString()+ShortShift.ToString()},
			delegate { return GenHighRange(source, nShortSMA, ShortShift); });
			// серия значений нижней границы
			IList<double> nShortLowRange = ctx.GetData("ShortLowRange", new[] {ShortPeriod.ToString()+ShortShift.ToString()},
			delegate { return GenLowRange(source, nShortSMA, ShortShift); });
			
			#endregion
			//================================================================================
			#region основной цикл - проход по барам
			int barsCount = source.Bars.Count;
			for (int bar = StartBar; bar < barsCount-1; bar++)
			{
				//--------------------------------------------------------------------------------
				#region generate signals
				// сброс значений сигналов
				bBuy = false;
				bSell = false;
				bShort = false;
				bCover = false;
				
				// установка сигналов по условиям
				// для длинных позиций
				if (source.ClosePrices[bar-1] > nLongHighRange[bar-1])
				{
					if (source.ClosePrices[bar] > source.ClosePrices[bar-1]) bBuy = true;
				}
				if (source.ClosePrices[bar] < nLongLowRange[bar]) bSell = true;
				// для коротких позиций
				if (source.ClosePrices[bar-1] < nShortLowRange[bar-1])
				{
					if (source.ClosePrices[bar] < source.ClosePrices[bar-1]) bShort = true;
				}
				if (source.ClosePrices[bar] > nShortHighRange[bar]) bCover = true;
				#endregion	
				//================================================================================
				#region execute signals
				//--------------------------------------------------------------------------------
				// выполнение сигналов для длинной позиции
				IPosition LongPos = source.Positions.GetLastActiveForSignal("LN");
				if (LongPos == null)
				{
					// Если нет активной длинной позиции
					if (bBuy)
					{
						// Если есть сигнал Buy, 
						// выдаем ордер на открыте новой длинной позиции.
						source.Positions.BuyAtMarket(bar+1, 1, "LN");
					}
				}
				else
				{
					// Если есть активная длинная позиция 
					if (bSell)
					{
						// Если есть сигнал Sell, 
						// выдаем ордер на закрыте длинной позиции.
						LongPos.CloseAtMarket(bar+1, "LX");
					}
				}
				//--------------------------------------------------------------------------------
				// выполнение сигналов для короткой позиции
				IPosition ShortPos = source.Positions.GetLastActiveForSignal("SN");
				if (ShortPos == null)
				{
					// Если нет активной короткой позиции
					if (bShort)
					{
						// Если есть сигнал Short
						// выдаем ордер на открыте новой короткой позиции.
						source.Positions.SellAtMarket(bar+1, 1, "SN");
			
					}
				}
				else
				{
					// Если есть активная короткая позиция, 
					if (bCover)
					{
						// Если есть сигнал Cover
						// выдаем ордер на закрыте короткой позиции.
						ShortPos.CloseAtMarket(bar+1, "SX");
					}
				}
				#endregion
			}
			#endregion
			//================================================================================
			#region прорисовка графиков
			// Берем основную панель (Pane)
			IPane mainPane = ctx.First;
 
			// для длинных позиций
			// Отрисовка простой скользящей средней
			mainPane.AddList("LongSMA", nLongSMA, ListStyles.LINE, 0x00a0a0, LineStyles.DOT, PaneSides.RIGHT);
			// Отрисовка верхней и нижней границы конверта
			mainPane.AddList("LongHighRange", nLongHighRange, ListStyles.LINE, 0x0000a0, LineStyles.DOT, PaneSides.RIGHT);
			mainPane.AddList("LongLowRange", nLongLowRange, ListStyles.LINE, 0xf07070, LineStyles.DOT, PaneSides.RIGHT);

			// для коротких позиций
			// Отрисовка простой скользящей средней
			mainPane.AddList("ShortSMA", nShortSMA, ListStyles.LINE, 0xa000a0, LineStyles.DOT, PaneSides.RIGHT);
			// Отрисовка верхней и нижней границы конверта
			mainPane.AddList("ShortHighRange", nShortHighRange, ListStyles.LINE, 0x7070f0, LineStyles.DOT, PaneSides.RIGHT);
			mainPane.AddList("ShortLowRange", nShortLowRange, ListStyles.LINE, 0xa00000, LineStyles.DOT, PaneSides.RIGHT);

			#endregion
			//--------------------------------------------------------------------------------
		}
	}
}




На графике отображены границы ценовых каналов:





Результаты тестирования стратегии.


Кривая капитала:




Отчет с результатами тестирования:





В прикрепленных файлах можно найти всю необходимую информацию по этой стратегии.


Attachments
envelope_chart.png (2959 downloads)
Description: сриншот графика с границами конверта

envelope_equity.png (2460 downloads)
Description: скриншот кривой капитала (доходности стратегии)

envelope_report.png (2464 downloads)
Description: скриншот отчета по результатам тестирования

envelope_scheme.xml (593 downloads)
Description: блок-схема в xml-формате

envelope_script.cs (621 downloads)
Description: скрипт на C#




Отредактировано andy (Mon Jul 05 2010 07:15 PM)