/*================================================================================ * Стратегия: Gartley 222 * Платформа: TSLab версия 1.1.8.0 * Дата создания: 15.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.Gartley { //================================================================================ public class Gartley : IExternalScript { // используем переменные-флаги для сигналов public bool bBuy; // флаг сигнала открытия длинной позиции public bool bSell; // флаг сигнала закрытия длинной позиции public bool bShort; // флаг сигнала открытия короткой позиции public bool bCover; // флаг сигнала закрытия короткой позиции public IPosition LongPos, ShortPos; //================================================================================ // функция вычисления PeakPrice (последовательность значений) // Reversal - величина разворота для новой вершины public IList Gen_PeakPrice(ISecurity source, double Reversal) { double vHigh, vLow, vMax, vMin, vUp, vDown, vPeak; bool bUp, bDown; // серия значений IList nPeak = new List(source.Bars.Count); vMax = source.HighPrices[0]; vMin = source.LowPrices[0]; vPeak = vMax; bUp = true; bDown = false; for (int bar = 0; bar < source.Bars.Count; bar++) { vHigh = source.HighPrices[bar]; vLow = source.LowPrices[bar]; if (vHigh > vMax) { vMax = vHigh; if (bUp) vMin = vHigh; } if (vLow < vMin) { vMin = vLow; if (bDown) vMax = vLow; } vUp = (vMax - vMin) / vMin * 100; if (bDown && vUp >= Reversal) { vMin = vHigh; bUp = true; bDown = false; } vDown = (vMax - vLow) / vMax * 100; if (bUp && vDown >= Reversal) { vPeak = vMax; bDown = true; bUp = false; } //-------------------------------------------------------------------------------- // добавление нового значения в последовательность nPeak.Add(vPeak); } return nPeak; } //================================================================================ // функция вычисления PeakBar (последовательность значений) // Reversal - величина разворота для новой вершины public IList Gen_PeakBar(ISecurity source, double Reversal) { double vHigh, vLow, vMax, vMin, vUp, vDown, vPeak; bool bUp, bDown; int MaxBar, PeakBar; // серия значений IList nPeakBar = new List(source.Bars.Count); vMax = source.HighPrices[0]; vMin = source.LowPrices[0]; vPeak = vMax; MaxBar = 0; PeakBar = 0; bUp = true; bDown = false; for (int bar = 0; bar < source.Bars.Count; bar++) { vHigh = source.HighPrices[bar]; vLow = source.LowPrices[bar]; if (vHigh > vMax) { vMax = vHigh; MaxBar = bar; if (bUp) vMin = vHigh; } if (vLow < vMin) { vMin = vLow; if (bDown) vMax = vLow; } vUp = (vMax - vMin) / vMin * 100; if (bDown && vUp >= Reversal) { vMin = vHigh; bUp = true; bDown = false; } vDown = (vMax - vLow) / vMax * 100; if (bUp && vDown >= Reversal) { vPeak = vMax; PeakBar = MaxBar; bDown = true; bUp = false; } //-------------------------------------------------------------------------------- // добавление нового значения в последовательность nPeakBar.Add(PeakBar); } return nPeakBar; } //================================================================================ // функция вычисления TroughPrice (последовательность значений) // Reversal - величина разворота для новой вершины public IList Gen_TroughPrice(ISecurity source, double Reversal) { double vHigh, vLow, vMax, vMin, vUp, vDown, vTrough; bool bUp, bDown; // серия значений IList nTrough = new List(source.Bars.Count); vMax = source.HighPrices[0]; vMin = source.LowPrices[0]; vTrough = vMin; bUp = false; bDown = true; for (int bar = 0; bar < source.Bars.Count; bar++) { vHigh = source.HighPrices[bar]; vLow = source.LowPrices[bar]; if (vHigh > vMax) { vMax = vHigh; if (bUp) vMin = vHigh; } if (vLow < vMin) { vMin = vLow; if (bDown) vMax = vLow; } vDown = (vMax - vLow) / vMax * 100; if (bUp && vDown >= Reversal) { vMax = vLow; bDown = true; bUp = false; } vUp = (vMax - vMin) / vMin * 100; if (bDown && vUp >= Reversal) { vTrough = vMin; bUp = true; bDown = false; } //-------------------------------------------------------------------------------- // добавление нового значения в последовательность nTrough.Add(vTrough); } return nTrough; } //================================================================================ // функция вычисления TroughBar (последовательность значений) // Reversal - величина разворота для новой вершины public IList Gen_TroughBar(ISecurity source, double Reversal) { double vHigh, vLow, vMax, vMin, vUp, vDown, vTrough; bool bUp, bDown; int MinBar, TroughBar; // серия значений IList nTroughBar = new List(source.Bars.Count); vMax = source.HighPrices[0]; vMin = source.LowPrices[0]; vTrough = vMin; MinBar = 0; TroughBar = 0; bUp = false; bDown = true; for (int bar = 0; bar < source.Bars.Count; bar++) { vHigh = source.HighPrices[bar]; vLow = source.LowPrices[bar]; if (vHigh > vMax) { vMax = vHigh; if (bUp) vMin = vHigh; } if (vLow < vMin) { vMin = vLow; MinBar = bar; if (bDown) vMax = vLow; } vDown = (vMax - vLow) / vMax * 100; if (bUp && vDown >= Reversal) { vMax = vLow; bDown = true; bUp = false; } vUp = (vMax - vMin) / vMin * 100; if (bDown && vUp >= Reversal) { vTrough = vMin; TroughBar = MinBar; bUp = true; bDown = false; } //-------------------------------------------------------------------------------- // добавление нового значения в последовательность nTroughBar.Add(TroughBar); } return nTroughBar; } //================================================================================ // Параметры оптимизации // параметра для длинных позиций public OptimProperty LongReversalParam = new OptimProperty(2, 1, 20, 1); public OptimProperty LongPeriodParam = new OptimProperty(8, 1, 20, 1); public OptimProperty LongToleranceParam = new OptimProperty(0.19, 0.05, 0.5, 0.05); // параметра для коротких позиций public OptimProperty ShortReversalParam = new OptimProperty(5, 1, 20, 1); public OptimProperty ShortPeriodParam = new OptimProperty(28, 1, 20, 1); public OptimProperty ShortToleranceParam = new OptimProperty(0.2, 0.05, 0.5, 0.05); //================================================================================ public virtual void Execute(IContext ctx, ISecurity source) { int StartBar = 0; #region Variables // для длинных позиций // период расчета int LongReversal; // величина разворота для новой вершины int LongPeriod; // период нахождения в позиции double LongTolerance; // для коротких позиций // период расчета int ShortReversal; // величина разворота для новой вершины int ShortPeriod; // величина разворота для новой вершины double ShortTolerance; double F1, F2, F3, F4, P1, P2, T1, T2; int P1Bar, P2Bar, T1Bar, T2Bar; double XA, AB, BC, CD, AD, D, ABdXA, BCdAB, CDdBC, ADdXA; bool PTvalid, HLvalid, InZone, C1, C2, C3, C4; bool bSS, bBS; #endregion //-------------------------------------------------------------------------------- #region Obtain parameters LongReversal = LongReversalParam; LongPeriod = LongPeriodParam; LongTolerance = LongToleranceParam; ShortReversal = ShortReversalParam; ShortPeriod = ShortPeriodParam; ShortTolerance = ShortToleranceParam; F1 = 0.618; F2 = 0.786; F3 = 1.27; F4 = 1.618; StartBar = LongPeriod; if (ShortPeriod > StartBar) StartBar = ShortPeriod; // Вычисляем серии значений // Используем GetData для кеширования данных и ускорения оптимизации. // для длинных позиций // пики IList nLongPeak = ctx.GetData("LongPeak", new[] {LongReversal.ToString()}, delegate { return Gen_PeakPrice(source, LongReversal); }); // бары пиков IList nLongPeakBar = ctx.GetData("LongPeakBar", new[] {LongReversal.ToString()}, delegate { return Gen_PeakBar(source, LongReversal); }); // провалы IList nLongTrough = ctx.GetData("LongTrough", new[] {LongReversal.ToString()}, delegate { return Gen_TroughPrice(source, LongReversal); }); // бары провалов IList nLongTroughBar = ctx.GetData("LongTroughBar", new[] {LongReversal.ToString()}, delegate { return Gen_TroughBar(source, LongReversal); }); // с поправкой на число Фибоначи // пики IList nLongFPeak = ctx.GetData("LongFPeak", new[] {LongReversal.ToString()}, delegate { return Gen_PeakPrice(source, F1 * LongReversal); }); // бары пиков IList nLongFPeakBar = ctx.GetData("LongFPeakBar", new[] {LongReversal.ToString()}, delegate { return Gen_PeakBar(source, F1 * LongReversal); }); // провалы IList nLongFTrough = ctx.GetData("LongFTrough", new[] {LongReversal.ToString()}, delegate { return Gen_TroughPrice(source, F1 * LongReversal); }); // бары провалов IList nLongFTroughBar = ctx.GetData("LongFTroughBar", new[] {LongReversal.ToString()}, delegate { return Gen_TroughBar(source, F1 * LongReversal); }); // для коротких позиций // пики IList nShortPeak = ctx.GetData("ShortPeak", new[] {ShortReversal.ToString()}, delegate { return Gen_PeakPrice(source, ShortReversal); }); // бары пиков IList nShortPeakBar = ctx.GetData("ShortPeakBar", new[] {ShortReversal.ToString()}, delegate { return Gen_PeakBar(source, ShortReversal); }); // провалы IList nShortTrough = ctx.GetData("ShortTrough", new[] {ShortReversal.ToString()}, delegate { return Gen_TroughPrice(source, ShortReversal); }); // бары провалов IList nShortTroughBar = ctx.GetData("ShortTroughBar", new[] {ShortReversal.ToString()}, delegate { return Gen_TroughBar(source, ShortReversal); }); // с поправкой на число Фибоначи // пики IList nShortFPeak = ctx.GetData("ShortFPeak", new[] {ShortReversal.ToString()}, delegate { return Gen_PeakPrice(source, F1 * ShortReversal); }); // бары пиков IList nShortFPeakBar = ctx.GetData("ShortFPeakBar", new[] {ShortReversal.ToString()}, delegate { return Gen_PeakBar(source, F1 * ShortReversal); }); // провалы IList nShortFTrough = ctx.GetData("ShortFTrough", new[] {ShortReversal.ToString()}, delegate { return Gen_TroughPrice(source, F1 * ShortReversal); }); // бары провалов IList nShortFTroughBar = ctx.GetData("ShortFTroughBar", new[] {ShortReversal.ToString()}, delegate { return Gen_TroughBar(source, F1 * ShortReversal); }); #endregion //================================================================================ #region основной цикл - проход по барам int barsCount = source.Bars.Count; for (int bar = StartBar; bar < barsCount-1; bar++) { //-------------------------------------------------------------------------------- #region calculate values bSS = false; bBS = false; // определяем пики и провалы для длинных позиций P1 = nLongFPeak[bar]; P1Bar = (int)nLongFPeakBar[bar]; P2 = nLongPeak[P1Bar]; P2Bar = (int)nLongPeakBar[P1Bar]; T1 = nLongFTrough[bar]; T1Bar = (int)nLongFTroughBar[bar]; T2 = nLongTrough[T1Bar]; T2Bar = (int)nLongTroughBar[T1Bar]; // Test for a bullish 222 // Trough X is T2 // Peak A is P2 // Trough B is T1 // Peak C is P1 // D is the buy point D = source.LowPrices[bar]; PTvalid = ((P1Bar > T1Bar) && (T1Bar > P2Bar) && (P2Bar > T2Bar)); HLvalid = ((P1 < P2) && (T1 > T2) && (P1 > T1)); InZone = ((D < T1) && (D > T2)); if (PTvalid && HLvalid && InZone) { XA = P2 - T2; AB = P2 - T1; BC = P1 - T1; CD = P1 - D; AD = P2 - D; ABdXA = AB / XA; // AB should be 61.8% of XA C1 = ((ABdXA > F1 - LongTolerance) && (ABdXA < F1 + LongTolerance)); BCdAB = BC / AB; // BC should be 61.8-78.6% of AB C2 = ((BCdAB > F1 - LongTolerance) && (BCdAB < F2 + LongTolerance)); CDdBC = CD / BC; // CD should be 127-161.8% of BC C3 = ((CDdBC > F3 - LongTolerance) && (CDdBC < F4 + LongTolerance)); ADdXA = AD / XA; // AD should be 78.6% of XA C4 = ((ADdXA > F2 - LongTolerance) && (ADdXA < F2 + LongTolerance)); if (C1 && C2 && C3 && C4) bBS = true; } // определяем пики и провалы для коротких позиций P1 = nShortFPeak[bar]; P1Bar = (int)nShortFPeakBar[bar]; P2 = nShortPeak[P1Bar]; P2Bar = (int)nShortPeakBar[P1Bar]; T1 = nShortFTrough[bar]; T1Bar = (int)nShortFTroughBar[bar]; T2 = nShortTrough[T1Bar]; T2Bar = (int)nShortTroughBar[T1Bar]; // Test for a bearish 222 // Peak X is P2 // Trough A is T2 // Peak B is P1 // Trough C is T1 // D is the short point D = source.HighPrices[bar]; PTvalid = ((T1Bar > P1Bar) && (P1Bar > T2Bar) && (T2Bar > P2Bar)); HLvalid = ((T1 > T2) && (P1 < P2) && (T1 < P1)); InZone = ((D > P1) && (D < P2)); if (PTvalid && HLvalid && InZone) { XA = P2 - T2; AB = P1 - T2; BC = P1 - T1; CD = D - T1; AD = D - T2; ABdXA = AB / XA; // AB should be 61.8% of XA C1 = ((ABdXA > F1 - ShortTolerance) && (ABdXA < F1 + ShortTolerance)); BCdAB = BC / AB; // BC should be 61.8-78.6% of AB C2 = ((BCdAB > F1 - ShortTolerance) && (BCdAB < F2 + ShortTolerance)); CDdBC = CD / BC; // CD should be 127-161.8% of BC C3 = ((CDdBC > F3 - ShortTolerance) && (CDdBC < F4 + ShortTolerance)); ADdXA = AD / XA; // AD should be 78.6% of XA C4 = ((ADdXA > F2 - ShortTolerance) && (ADdXA < F2 + ShortTolerance)); if (C1 && C2 && C3 && C4) bSS = true; } #endregion //-------------------------------------------------------------------------------- #region generate signals // сброс значений сигналов bBuy = false; bSell = false; bShort = false; bCover = false; // установка сигналов по условиям // для длинных позиций if (bBS) bBuy = true; if (LongPos != null) { if ((bar - LongPos.EntryBarNum - 1) >= LongPeriod) bSell = true; } // для коротких позиций if (bSS) bShort = true; if (ShortPos != null) { if ((bar - ShortPos.EntryBarNum - 1) >= ShortPeriod) bCover = true; } #endregion //================================================================================ #region execute signals //-------------------------------------------------------------------------------- // выполнение сигналов для длинной позиции 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"); } } //-------------------------------------------------------------------------------- // выполнение сигналов для короткой позиции 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("LongPeak", nLongPeak, ListStyles.LINE, 0x0000a0, LineStyles.DOT, PaneSides.RIGHT); mainPane.AddList("LongTrough", nLongTrough, ListStyles.LINE, 0x00a0a0, LineStyles.DOT, PaneSides.RIGHT); // для коротких позиций mainPane.AddList("ShortPeak", nShortPeak, ListStyles.LINE, 0xa000a0, LineStyles.DOT, PaneSides.RIGHT); mainPane.AddList("ShortTrough", nShortTrough, ListStyles.LINE, 0xa00000, LineStyles.DOT, PaneSides.RIGHT); #endregion //-------------------------------------------------------------------------------- } } }