/*================================================================================
* Стратегия: High-Low с фильтром на основе NRMA
* Платформа: TSLab версия 1.1.7.0
* Дата создания: 21.06.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.High_Low_NRMA
{
public class System_High_Low_NRMA : IExternalScript
{
//================================================================================
// функция вычисления индикатора NRMA (последовательность значений)
// kShift - коэффициент смещения
// kSharp - степень для усиления выраженности индикатора (2-3)
public IList<double> GenNRMA(ISecurity source, double kShift, double kSharp)
{
#region Variables
int Dir; // нарпавление индикатора NRTR (+1 вверх, -1 вниз)
int MinPeriod; // минимальное значение периода для скользящей средней
double MaxPrice, MinPrice, UpPrice, DownPrice;
double vNRTR, vRatio, vNRMA;
double vOSC, vOSC1, vOSC2; // последовательные значения для вычисления среднего
IList<double> nNRMA = new List<double>(source.Bars.Count);
#endregion
//--------------------------------------------------------------------------------
#region Init vars
Dir = 0;
MinPeriod = 2;
vOSC = 0;
vOSC1 = 0;
vOSC2 = 0;
vNRMA = 0;
#endregion
//--------------------------------------------------------------------------------
#region значения для первой свечи
MaxPrice = source.HighPrices[0];
MinPrice = source.LowPrices[0];
UpPrice = MinPrice * (1 + kShift / 100);
DownPrice = MaxPrice * (1 - kShift / 100);
#endregion
for (int bar = 0; bar < source.Bars.Count; bar++)
{
//--------------------------------------------------------------------------------
#region calculate values
int NewDir = Dir;
double NewUpPrice = source.LowPrices[bar] * (1 + kShift / 100);
double NewDownPrice = source.HighPrices[bar] * (1 - kShift / 100);
// разворот последовательности
// при движении вверх
if (Dir > -1)
{
if (source.LowPrices[bar] < DownPrice)
{
NewDir = -1;
UpPrice = NewUpPrice;
}
}
// при движении вниз
if (Dir < 1)
{
if (source.HighPrices[bar] > UpPrice)
{
NewDir = 1;
DownPrice = NewDownPrice;
}
}
Dir = NewDir;
if ((Dir > -1) && (NewDownPrice > DownPrice)) DownPrice = NewDownPrice;
if ((Dir < 1) && (NewUpPrice < UpPrice)) UpPrice = NewUpPrice;
// значение индикатора NRTR
// (принцип по аналогии с параболиком)
vNRTR = DownPrice;
if (Dir < 1) vNRTR = UpPrice;
// значение vRatio - усреднение осцилятора (на 3 бара) и возведение в степень kSharp
vOSC2 = vOSC1;
vOSC1 = vOSC;
vOSC = (100 * Math.Abs(source.ClosePrices[bar] - vNRTR) / source.ClosePrices[bar]) / kShift;
if (bar == 0)
{
vOSC1 = vOSC;
vOSC2 = vOSC;
vNRMA = source.ClosePrices[bar];
}
vRatio = Math.Pow((vOSC + vOSC1 + vOSC2) / 3, kSharp);
// значение NRMA
double Factor = 2.0 / (1 + MinPeriod);
vNRMA = vNRMA + vRatio * Factor * (source.ClosePrices[bar] - vNRMA);
#endregion
//--------------------------------------------------------------------------------
// добавление нового значения в последовательность
nNRMA.Add(vNRMA);
}
return nNRMA;
}
//================================================================================
// Параметры оптимизации задаются при помощи типа OptimProperty.
// Параметры оптимизации для длинных позиций
public OptimProperty High1Period = new OptimProperty(85, 10, 100, 5);
public OptimProperty Low1Period = new OptimProperty(60, 10, 100, 5);
// Параметры оптимизации для коротких позици
public OptimProperty Low2Period = new OptimProperty(70, 10, 100, 5);
public OptimProperty High2Period = new OptimProperty(85, 10, 100, 5);
// Параметры оптимизации для расчета индикатора NRMA
// также могут быть заданы другие параметры (kShift, kSharp и т.д.)
// ShiftParam - параметр оптимизации для коэффицента смещения на вход
public OptimProperty ShiftParam = new OptimProperty(9.8, 0.2, 20, 0.2);
//================================================================================
public virtual void Execute(IContext ctx, ISecurity source)
{
#region Variables
int MDir; // напраление адаптивной скользящей средней (+1 вверх, -1 вниз)
double kShift; // коэффициент смещения для расчета NRMA
double kSharp; // степень для усиления выраженности индикатора NRTR
double vNRMA; // значение NRMA для текущего бара
double vPrevNRMA; // значение NRMA для предыдущего бара
#endregion
//--------------------------------------------------------------------------------
#region Init vars
MDir = 0;
kShift = 10;
kSharp = 2;
#endregion
//--------------------------------------------------------------------------------
// Obtain parameters
kShift = ShiftParam;
// серия значений индикатора NRMA
// кэширование с учетом параметров kShift и kSharp
IList<double> nNRMA = ctx.GetData("NRMA", new[] {kShift.ToString()+"_"+kSharp.ToString()},
delegate { return GenNRMA(source, kShift, kSharp); });
// серия значений для направления скользящей средней
IList<double> nMDir = new List<double>(source.Bars.Count);
//================================================================================
#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 прорисовка графиков
// Берем основную панель (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);
mainPane.AddList("NRMA", nNRMA, ListStyles.LINE, 0xa000a0, LineStyles.SOLID, PaneSides.RIGHT);
#endregion
// =================================================
#region Основной цикл обработки (торговля).
int barsCount = source.Bars.Count;
vNRMA = nNRMA[0];
for (int bar = 0; (bar < barsCount); bar++)
{
//--------------------------------------------------------------------------------
#region calculate values
// значение NRMA
vPrevNRMA = vNRMA;
vNRMA = nNRMA[bar];
// изменение направления индикатора NRMA
if ((MDir > -1) && (vNRMA < vPrevNRMA)) MDir = -1;
if ((MDir < 1) && (vNRMA > vPrevNRMA)) MDir = 1;
// добавление новых значений в последовательность
nMDir.Add(MDir);
#endregion
//--------------------------------------------------------------------------------
#region execute signals
//--------------------------------------------------------------------------------
// выполнение сигналов для длинной позиции
IPosition LongPos = source.Positions.GetLastActiveForSignal("LN");
if (LongPos == null)
{
// Если нет активной длинной позиции,
if (MDir > 0)
{
// если направление индикатора NRMA вверх
// выдаем условный ордер на открыте новой длинной позиции.
source.Positions.BuyIfGreater(bar + 1, 1, high1[bar], "LN");
}
}
else
{
// Если есть активная длинная позиция,
// выдаем условный ордер на закрыте длинной позиции.
LongPos.CloseAtStop(bar + 1, low1[bar], "LX");
}
//--------------------------------------------------------------------------------
// выполнение сигналов для короткой позиции
IPosition ShortPos = source.Positions.GetLastActiveForSignal("SN");
if (ShortPos == null)
{
// Если нет активной короткой позиции,
if (MDir < 0)
{
// если направление индикатора NRMA вниз
// выдаем условный ордер на открыте новой короткой позиции.
source.Positions.SellIfLess(bar + 1, 1, low2[bar], "SN");
}
}
else
{
// Если есть активная короткая позиция,
// выдаем условный ордер на закрыте короткой позиции.
ShortPos.CloseAtStop(bar + 1, high2[bar], "SX");
}
#endregion
}
#endregion
//================================================================================
#region прорисовка графиков
// Создаем дополнительную панель.
IPane FilterPane = ctx.CreatePane("Filtr", 10, false, false);
// Отрисовка графика фильтра позиции
FilterPane.AddList(string.Format("Filter NRMA"), nMDir, ListStyles.LINE,
0x00ff00, LineStyles.SOLID, PaneSides.RIGHT);
#endregion
// =================================================
}
}
}