У вас не стоит Flash Player
Настройки
#7211 - Mon Jun 28 2010 02:30 PM High-Low (channel breakout) + скользящий стоп
Laber Offline
journeyman

Registered: Mon Jun 28 2010
Записи: 59
Модификация скрипта Hi-Lo.

Начав работать с программой TSLab, первым делом, думаю, как и многие, познакомились с встроенным скриптом Hi-Lo. С документацией к программе идет пример этой же очень простой, но и при этой достаточно эффективной, стратегии на языке C#.

Система основана на пробитии уровней Максимум за/Минимум за. Период

Сегодня мы немного изменим условия системы и посмотрим на результаты. Условия входа в позиции (Long/Short) оставим прежними, а вот выходы теперь будут по трейл-стопу. Конечно, такую систему проще собрать из блоков, что и сделано для примера в TSLab. Но в данном случае хочется показать именно в программном коде пример применения трейл-стопов.

Итак, система в визуальном редакторе будет выглядеть вот так:



А вот так эта система будет выглядеть в виде кода с простым скользящим стопом:

http://www.tslab.ru/ubb/ubbthreads.php?ubb=download&Number=952&filename=high_low.cs

Code:
/*================================================================================
 * Стратегия: High-Low (channel breakout)
 * Платформа: TSLab версия 1.1.7.0
 * Дата создания: 01.06.2010
 * Реализовано: Laber
 *================================================================================*/

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

namespace TSLab.High_Low
{

	public class System_High_Low : IExternalScript
	{
		// Параметры оптимизации задаются при помощи типа OptimProperty.
		// Параметры оптимизации для длинных позиций 
		public OptimProperty High1Period = new OptimProperty(20, 10, 100, 5);
		public OptimProperty Low1Period = new OptimProperty(10, 10, 100, 5);

		// Параметры оптимизации для коротких позици
		public OptimProperty Low2Period = new OptimProperty(20, 10, 100, 5);
		public OptimProperty High2Period = new OptimProperty(10, 10, 100, 5);

		// Параметры закрытия по скользящему стопу
		public OptimProperty LongStop = new OptimProperty(50, 1, 200, 1);
		public OptimProperty ShortStop = new OptimProperty(50, 1, 200, 1);

		public virtual void Execute(IContext ctx, ISecurity source)
		{
			#region Вычисляем максимумы и минимумы.
			// Используем GetData для кеширования данных и ускорения оптимизация.
			// При неиспользовании кэша увеличивается объем обрабатываемых данных, что ведет к сильному замедлению оптимизации.
			// Следует учесть, что необходимо перечислить абсолютно все изменяемые переменные используемые в вычислениях.
			// Не соблюдение этого правила приведет к некорректной работе и результатам оптимизации.
			IList<double> high1 = ctx.GetData("Highest", new[] {High1Period.ToString()},
			delegate { return Series.Highest(source.HighPrices, High1Period); });
			IList<double> low1 = ctx.GetData("Lowest", new[] {Low1Period.ToString()},
			delegate { return Series.Lowest(source.LowPrices, Low1Period); });
			IList<double> high2 = ctx.GetData("Highest", new[] {High2Period.ToString()},
			delegate { return Series.Highest(source.HighPrices, High2Period); });
			IList<double> low2 = ctx.GetData("Lowest", new[] {Low2Period.ToString()},
			delegate { return Series.Lowest(source.LowPrices, Low2Period); });
 
			#endregion
			// =================================================
			#region Variables
			double MaxPrice; // максимальная цена с момента открытия длинной позиции
			double MinPrice; // минимальная цена с момента открытия короткой позиции
			double LongStopPrice; // цена скользящего стопа длинной позиции
			double ShortStopPrice; // цена скользящего стопа короткой позиции
			
			// серия значений стоп-цены длинной позиции
			IList<double> nLongStopPrice = new List<double>(source.Bars.Count);
			// серия значений стоп-цены короткой позиции
			IList<double> nShortStopPrice = new List<double>(source.Bars.Count);

			#endregion
			//--------------------------------------------------------------------------------
			#region Init vars
			// начальные значения переменным задавать не обязательно
			// при открытии позиции переменным задаются реальные значения
			MaxPrice = source.HighPrices[0];	
			MinPrice = source.LowPrices[0];
			LongStopPrice = MinPrice;
			ShortStopPrice = MaxPrice;
			#endregion
			// =================================================
			#region прорисовка графиков
			// Берем основную панель (Pane).
			IPane mainPane = ctx.First;
		 
			// Отрисовка графиков.
			mainPane.AddList(string.Format("High1({0}) [{1}]", High1Period, source.Symbol), high1, ListStyles.LINE,
			0x00ff00, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList(string.Format("Low1({0}) [{1}]", Low1Period, source.Symbol), low1, ListStyles.LINE,
			0xff0000, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList(string.Format("Low2({0}) [{1}]", Low2Period, source.Symbol), low2, ListStyles.LINE,
			0xff0000, LineStyles.DASH, PaneSides.RIGHT);
			mainPane.AddList(string.Format("High2({0}) [{1}]", High2Period, source.Symbol), high2, ListStyles.LINE,
			0x00ff00, LineStyles.DASH, PaneSides.RIGHT);
 			#endregion
			// =================================================
			#region Основной цикл обработки (торговля).
			
			int barsCount = source.Bars.Count;
			for (int bar = 0; (bar < barsCount); bar++)
			{
				// выполнение сигналов для длинной позиции
				IPosition LongPos = source.Positions.GetLastActiveForSignal("LN");
				if (LongPos == null)
				{
					// Если нет активной длинной позиции, 
					// выдаем условный ордер на открыте новой длинной позиции.
					source.Positions.BuyIfGreater(bar + 1, 1, high1[bar], "LN");
					MaxPrice = source.HighPrices[bar];
				}
				else
				{
					// Если есть активная длинная позиция, 
					// вычисляем стоп-цену по максимуму
					LongStopPrice = MaxPrice * (1 - LongStop * 1.0 / 1000);
					// или по нижнему краю ценового канала
					if (low1[bar] > LongStopPrice) LongStopPrice = low1[bar];
					// выдаем условный ордер на закрыте длинной позиции.
					LongPos.CloseAtStop(bar + 1, LongStopPrice, "LX");
					// сдвигаем максимум после отработки стоп-ордера
					if (source.HighPrices[bar] > MaxPrice) MaxPrice = source.HighPrices[bar];
				}
				//--------------------------------------------------------------------------------
				// выполнение сигналов для короткой позиции
				IPosition ShortPos = source.Positions.GetLastActiveForSignal("SN");
				if (ShortPos == null)
				{
					// Если нет активной короткой позиции, 
					// выдаем условный ордер на открыте новой короткой позиции.
					source.Positions.SellIfLess(bar + 1, 1, low2[bar], "SN");
					MinPrice = source.LowPrices[bar];
				}
				else
				{
					// Если есть активная короткая позиция,
					// вычисляем стоп-цену по минимуму
					ShortStopPrice = MinPrice * (1 + ShortStop * 1.0 / 1000);
					// или по верхнему краю ценового канала
					if (high2[bar] < ShortStopPrice) ShortStopPrice = high2[bar];
					// выдаем условный ордер на закрыте короткой позиции.
					ShortPos.CloseAtStop(bar + 1, ShortStopPrice, "SX");
					// сдвигаем минимум после отработки стоп-ордера
					if (source.LowPrices[bar] < MinPrice) MinPrice = source.LowPrices[bar];
				}
				
				// добавляем значения стопов для текущего бара в соответствующие серии
				nLongStopPrice.Add(LongStopPrice);
				nShortStopPrice.Add(ShortStopPrice);
			}
			#endregion
			// =================================================
			#region прорисовка стопов
			mainPane.AddList("LongStop", nLongStopPrice, ListStyles.LINE, 0xff00a0, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList("ShortStop", nShortStopPrice, ListStyles.LINE, 0xa000ff, LineStyles.SOLID, PaneSides.RIGHT);
			#endregion
		}
	}
}



На графике отображены границы ценовых каналов и значения скользящих стопов:




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

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



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




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

scheme_script_1.xml - блок-схема в xml-формате
scheme_script_2.xml - блок-схема стратегии с использованием скрипта на C# (в xml-формате)
chart.png - сриншот графика с границами ценовых каналов и стопами
equity.png - скриншот кривой капитала (доходности стратегии)
report.png - скриншот отчета по результатам тестирования
scheme_1.png - скриншот блок-схемы
scheme_2.png - скриншот блок-схемы с использованием срипта на C#
high_low.cs - скрипт на C#




Attachments
scheme_script_1.xml (324 downloads)
scheme_script_2.xml (524 downloads)
chart.png (3018 downloads)
equity.png (2688 downloads)
report.png (2642 downloads)
scheme_1.png (2377 downloads)
scheme_2.png (539 downloads)
high_low.cs (990 downloads)



Отредактировано Laber (Mon Jun 28 2010 05:42 PM)

Наверх
#7221 - Mon Jun 28 2010 02:43 PM Re: High-Low (channel breakout) + скользящий стоп [Re: Laber]
777 Offline
Carpal Tunnel

Registered: Thu Apr 01 2010
Записи: 2564
Loc: г. Дзержинский
Laber здравствуйте!
Вы клиент или работник, почему ник не красный?


Отредактировано 777 (Mon Jun 28 2010 02:48 PM)
_________________________
«Существует 3 типа лжи: ложь, наглая ложь и статистика»
Дизраэли.

Наверх
#7233 - Mon Jun 28 2010 03:16 PM Re: High-Low (channel breakout) + скользящий стоп [Re: 777]
profit Offline
Pooh-Bah

Registered: Wed Jan 13 2010
Записи: 1835
Здесь вообще может один человек за всех играет роли.Максимум три.
_________________________
Делаю простые вещи.

Наверх
#7259 - Mon Jun 28 2010 06:37 PM Re: High-Low (channel breakout) + скользящий стоп [Re: Laber]
777 Offline
Carpal Tunnel

Registered: Thu Apr 01 2010
Записи: 2564
Loc: г. Дзержинский
Originally Posted By: Laber

http://www.tslab.ru/ubb/ubbthreads.php?ubb=download&Number=952&filename=high_low.cs

Code:
/*================================================================================
 * Стратегия: High-Low (channel breakout)
 * Платформа: TSLab версия 1.1.7.0
 * Дата создания: 01.06.2010
 * Реализовано: Laber
 *================================================================================*/

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

namespace TSLab.High_Low
{

	public class System_High_Low : IExternalScript
	{
		// Параметры оптимизации задаются при помощи типа OptimProperty.
		// Параметры оптимизации для длинных позиций 
		public OptimProperty High1Period = new OptimProperty(20, 10, 100, 5);
		public OptimProperty Low1Period = new OptimProperty(10, 10, 100, 5);

		// Параметры оптимизации для коротких позици
		public OptimProperty Low2Period = new OptimProperty(20, 10, 100, 5);
		public OptimProperty High2Period = new OptimProperty(10, 10, 100, 5);

		// Параметры закрытия по скользящему стопу
		public OptimProperty LongStop = new OptimProperty(50, 1, 200, 1);
		public OptimProperty ShortStop = new OptimProperty(50, 1, 200, 1);

		public virtual void Execute(IContext ctx, ISecurity source)
		{
			#region Вычисляем максимумы и минимумы.
			// Используем GetData для кеширования данных и ускорения оптимизация.
			// При неиспользовании кэша увеличивается объем обрабатываемых данных, что ведет к сильному замедлению оптимизации.
			// Следует учесть, что необходимо перечислить абсолютно все изменяемые переменные используемые в вычислениях.
			// Не соблюдение этого правила приведет к некорректной работе и результатам оптимизации.
			IList<double> high1 = ctx.GetData("Highest", new[] {High1Period.ToString()},
			delegate { return Series.Highest(source.HighPrices, High1Period); });
			IList<double> low1 = ctx.GetData("Lowest", new[] {Low1Period.ToString()},
			delegate { return Series.Lowest(source.LowPrices, Low1Period); });
			IList<double> high2 = ctx.GetData("Highest", new[] {High2Period.ToString()},
			delegate { return Series.Highest(source.HighPrices, High2Period); });
			IList<double> low2 = ctx.GetData("Lowest", new[] {Low2Period.ToString()},
			delegate { return Series.Lowest(source.LowPrices, Low2Period); });
 
			#endregion
			// =================================================
			#region Variables
			double MaxPrice; // максимальная цена с момента открытия длинной позиции
			double MinPrice; // минимальная цена с момента открытия короткой позиции
			double LongStopPrice; // цена скользящего стопа длинной позиции
			double ShortStopPrice; // цена скользящего стопа короткой позиции
			
			// серия значений стоп-цены длинной позиции
			IList<double> nLongStopPrice = new List<double>(source.Bars.Count);
			// серия значений стоп-цены короткой позиции
			IList<double> nShortStopPrice = new List<double>(source.Bars.Count);

			#endregion
			//--------------------------------------------------------------------------------
			#region Init vars
			// начальные значения переменным задавать не обязательно
			// при открытии позиции переменным задаются реальные значения
			MaxPrice = source.HighPrices[0];	
			MinPrice = source.LowPrices[0];
			LongStopPrice = MinPrice;
			ShortStopPrice = MaxPrice;
			#endregion
			// =================================================
			#region прорисовка графиков
			// Берем основную панель (Pane).
			IPane mainPane = ctx.First;
		 
			// Отрисовка графиков.
			mainPane.AddList(string.Format("High1({0}) [{1}]", High1Period, source.Symbol), high1, ListStyles.LINE,
			0x00ff00, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList(string.Format("Low1({0}) [{1}]", Low1Period, source.Symbol), low1, ListStyles.LINE,
			0xff0000, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList(string.Format("Low2({0}) [{1}]", Low2Period, source.Symbol), low2, ListStyles.LINE,
			0xff0000, LineStyles.DASH, PaneSides.RIGHT);
			mainPane.AddList(string.Format("High2({0}) [{1}]", High2Period, source.Symbol), high2, ListStyles.LINE,
			0x00ff00, LineStyles.DASH, PaneSides.RIGHT);
 			#endregion
			// =================================================
			#region Основной цикл обработки (торговля).
			
			int barsCount = source.Bars.Count;
			for (int bar = 0; (bar < barsCount); bar++)
			{
				// выполнение сигналов для длинной позиции
				IPosition LongPos = source.Positions.GetLastActiveForSignal("LN");
				if (LongPos == null)
				{
					// Если нет активной длинной позиции, 
					// выдаем условный ордер на открыте новой длинной позиции.
					source.Positions.BuyIfGreater(bar + 1, 1, high1[bar], "LN");
					MaxPrice = source.HighPrices[bar];
				}
				else
				{
					// Если есть активная длинная позиция, 
					// вычисляем стоп-цену по максимуму
					LongStopPrice = MaxPrice * (1 - LongStop * 1.0 / 1000);
					// или по нижнему краю ценового канала
					if (low1[bar] > LongStopPrice) LongStopPrice = low1[bar];
					// выдаем условный ордер на закрыте длинной позиции.
					LongPos.CloseAtStop(bar + 1, LongStopPrice, "LX");
					// сдвигаем максимум после отработки стоп-ордера
					if (source.HighPrices[bar] > MaxPrice) MaxPrice = source.HighPrices[bar];
				}
				//--------------------------------------------------------------------------------
				// выполнение сигналов для короткой позиции
				IPosition ShortPos = source.Positions.GetLastActiveForSignal("SN");
				if (ShortPos == null)
				{
					// Если нет активной короткой позиции, 
					// выдаем условный ордер на открыте новой короткой позиции.
					source.Positions.SellIfLess(bar + 1, 1, low2[bar], "SN");
					MinPrice = source.LowPrices[bar];
				}
				else
				{
					// Если есть активная короткая позиция,
					// вычисляем стоп-цену по минимуму
					ShortStopPrice = MinPrice * (1 + ShortStop * 1.0 / 1000);
					// или по верхнему краю ценового канала
					if (high2[bar] < ShortStopPrice) ShortStopPrice = high2[bar];
					// выдаем условный ордер на закрыте короткой позиции.
					ShortPos.CloseAtStop(bar + 1, ShortStopPrice, "SX");
					// сдвигаем минимум после отработки стоп-ордера
					if (source.LowPrices[bar] < MinPrice) MinPrice = source.LowPrices[bar];
				}
				
				// добавляем значения стопов для текущего бара в соответствующие серии
				nLongStopPrice.Add(LongStopPrice);
				nShortStopPrice.Add(ShortStopPrice);
			}
			#endregion
			// =================================================
			#region прорисовка стопов
			mainPane.AddList("LongStop", nLongStopPrice, ListStyles.LINE, 0xff00a0, LineStyles.SOLID, PaneSides.RIGHT);
			mainPane.AddList("ShortStop", nShortStopPrice, ListStyles.LINE, 0xa000ff, LineStyles.SOLID, PaneSides.RIGHT);
			#endregion
		}
	}
}



Laber, реальное спасибо! За реально хорошо составленные объяснения к каждой строчке!
_________________________
«Существует 3 типа лжи: ложь, наглая ложь и статистика»
Дизраэли.

Наверх
#7467 - Wed Jun 30 2010 04:09 PM Re: High-Low (channel breakout) + скользящий стоп [Re: 777]
serg Offline
Pooh-Bah

Registered: Fri May 14 2010
Записи: 1663
Loc: Россия
Laber! Вы молодец....завидую))))

Наверх
#8708 - Tue Jul 20 2010 09:42 PM Re: High-Low (channel breakout) + скользящий стоп [Re: serg]
Craft Offline
enthusiast

Registered: Thu Jan 21 2010
Записи: 319
Laber, большое спасибо за проделанную работу, с большим интересом и пользой для себя изучаю этот раздел.
При создании алгоритма с использованием API, есть ещё один очень интересный/важный момент - исполнение ордеров риал-тайм, а не по закрытию бара. Не могли бы Вы для примера переделать алгоритм с использованием: TSLab.DataSource.OrderType.Growth и TSLab.DataSource.OrderType.Fall?

Очень прошу создать один пример с использованием этих команд.

Наверх
#8742 - Wed Jul 21 2010 02:01 PM Re: High-Low (channel breakout) + скользящий стоп [Re: Craft]
Laber Offline
journeyman

Registered: Mon Jun 28 2010
Записи: 59
Интересно попробовать. Хотя я этим не пользовался...
Надо будет разобраться как это реализовать.

Наверх


Moderator:  ViL, sar