У вас не стоит Flash Player
Настройки
#40452 - Tue Apr 17 2012 10:47 AM Take Profit и Stop Loss на основе дневного ATR
WD-40 Offline
stranger

Registered: Fri Mar 02 2012
Записи: 8
Здравствуйте. Пытаюсь реализовать технику выхода из позиции на основе тейк профита и стоп лоса построенных на основе дневного ATR, рабочий тайм фрейм час. Для этого набросал простенькую стратегию где вход в сделку осушествляется при пересечении скользяшей средней цены закрытия. Стратегия компилится без ошибок но работает очень странно. Если поставить дату начиная от 01.04.2012 0:00:00 то все работает рис 2. Если же поставить дату 01.03.2012 0:00:00 то вылетает исключение "в экземпляре объекта не задана ссылка на объект" рис 1. Вот код стратегии

Code:
public class ATRExit : IExternalScript
    {
        public OptimProperty SMAPeriodParam = new OptimProperty(27, 10, 30, 1);
        public OptimProperty atrDailyPeriodParam = new OptimProperty(12, 1, 30, 1);
        public OptimProperty atrStopPercentParam = new OptimProperty(50, 10, 100, 5);
        public OptimProperty winLossParam = new OptimProperty(4, 2, 7, 1);

        public void Execute(IContext ctx, ISecurity sec)
        {
            int SMAPeriod = this.SMAPeriodParam;
            int atrDailyPeriod = this.atrDailyPeriodParam;
            int atrStopPercent = this.atrStopPercentParam;
            int winLoss = this.winLossParam;

            IList<double> SMA = ctx.GetData("SMA", new[] { SMAPeriod.ToString() }, delegate { return Series.SMA(sec.ClosePrices, SMAPeriod); });

            var dailySec = sec.CompressTo(1440); //Делаю компрессию до дня

            IList<double> atrDaily = ctx.GetData("atrDaily", new[] { atrDailyPeriod.ToString() }, delegate { return Series.AverageTrueRange(dailySec.Bars, atrDailyPeriod); }); //вычисляю дневной ATR

            IList<double> hourlyATR = dailySec.Decompress(atrDaily, DecompressMethodWithDef.Default);//Синхронизирую дневной ATR с часовым интервалом

            double takeProfit = 0;
            double stopLoss = 0;

            for (int bar = 60; bar < sec.Bars.Count - 1; bar++)
            {
                if (sec.Positions.LastPositionActive != null)
                {
                    if (sec.Positions.LastPositionActive.IsLong)
                    {
                        sec.Positions.LastPositionActive.CloseAtProfit(bar, takeProfit, "Long"); //Выставляю Take Profit
                        sec.Positions.LastPositionActive.CloseAtStop(bar, stopLoss, "Long"); //Выставляю Stop Loss
                    }
                    else
                    {
                        sec.Positions.LastPositionActive.CloseAtProfit(bar, takeProfit, "Short");
                        sec.Positions.LastPositionActive.CloseAtStop(bar, stopLoss, "Short");
                    }
                }
                else
                {
                    if (CrossOver(bar, sec.ClosePrices, SMA)) //Вхожу в длинную позицию
                    {
                        sec.Positions.BuyAtMarket(bar + 1, 1, "Long");
                        takeProfit = sec.ClosePrices[bar] + atrStopPercent * winLoss * hourlyATR[bar] / 100; //Вычисляю Take Profit для Лонга
                        stopLoss = sec.ClosePrices[bar] - atrStopPercent * hourlyATR[bar] / 100; //Вычисляю Stop Loss для Лонга
                        
                    }
                    else if (CrossUnder(bar, sec.ClosePrices, SMA))
                    {
                        sec.Positions.SellAtMarket(bar + 1, 1, "Short");
                        takeProfit = sec.ClosePrices[bar] - atrStopPercent * winLoss * hourlyATR[bar] / 100; //Вычисляю Take Profit для Шорта
                        stopLoss = sec.ClosePrices[bar] + atrStopPercent * hourlyATR[bar] / 100; //Вычисляю Stop Loss для Шорта
                    }
                }
            }
        }

        private bool CrossOver(int bar, IList<double> series1, IList<double> series2)
        {
            return ((series1[bar] >= series2[bar]) && (series1[bar - 1] < series2[bar - 1]));
        }

        private bool CrossUnder(int bar, IList<double> series1, IList<double> series2)
        {
            return ((series1[bar] < series2[bar]) && (series1[bar - 1] >= series2[bar - 1]));
        }
    }




P.S. А как вставить загруженные картинки в сам текст сообшения?


Attachments
2.PNG (290 downloads)
1.PNG (258 downloads)


Наверх
#40459 - Tue Apr 17 2012 02:46 PM Re: Take Profit и Stop Loss на основе дневного ATR [Re: WD-40]
WD-40 Offline
stranger

Registered: Fri Mar 02 2012
Записи: 8
Ну как не у кого нет идей с чем это связанно?

Наверх
#40471 - Tue Apr 17 2012 04:42 PM Re: Take Profit и Stop Loss на основе дневного ATR [Re: WD-40]
Nektodron Offline

Carpal Tunnel

Registered: Thu Oct 23 2008
Записи: 5492
1. все операции с заявкой должны идти bar+1, иначе это заглядывание в будущее
2. запоминать внутри цикла при открытии позиции ничего нельзя, т.к. это работает только в лаборатории, а в реале вам придет уже готовый список открытых позиций и этот код не исполнится.
3. для того чтобы понять где ошибка, включить опцию "Отладка скриптов" в настройках программы.

Наверх
#40487 - Tue Apr 17 2012 06:46 PM Re: Take Profit и Stop Loss на основе дневного ATR [Re: Nektodron]
WD-40 Offline
stranger

Registered: Fri Mar 02 2012
Записи: 8
Спасибо за подсказку в пофиксил багу. Вот код
Code:
public void Execute(IContext ctx, ISecurity sec)
        {
            int SMAPeriod = this.SMAPeriodParam;
            int atrDailyPeriod = this.atrDailyPeriodParam;
            int atrStopPercent = this.atrStopPercentParam;
            int winLoss = this.winLossParam;

            IList<double> SMA = ctx.GetData("SMA", new[] { SMAPeriod.ToString() }, delegate { return Series.SMA(sec.ClosePrices, SMAPeriod); });

            var dailySec = sec.CompressTo(1440); //Делаю компрессию до дня

            IList<double> atrDaily = ctx.GetData("atrDaily", new[] { atrDailyPeriod.ToString() }, delegate { return Series.AverageTrueRange(dailySec.Bars, atrDailyPeriod); }); //вычисляю дневной ATR

            IList<double> hourlyATR = dailySec.Decompress(atrDaily, DecompressMethodWithDef.Default);//Синхронизирую дневной ATR с часовым интервалом

            for (int bar = 60; bar < sec.Bars.Count - 1; bar++)
            {
                IPosition lastActivePosition = sec.Positions.LastPositionActive;

                if (lastActivePosition != null)
                {
                    if (sec.Positions.LastPositionActive.IsLong)
                    {
                        double takeProfit = lastActivePosition.EntryPrice + atrStopPercent * winLoss * hourlyATR[lastActivePosition.EntryBarNum] / 100;
                        double stopLoss = lastActivePosition.EntryPrice - atrStopPercent * hourlyATR[lastActivePosition.EntryBarNum] / 100;

                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtProfit(bar + 1, takeProfit, "Long"); //Выставляю Take Profit
                        }
                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtStop(bar + 1, stopLoss, "Long"); //Выставляю Stop Loss
                        }
                    }
                    else
                    {
                        double takeProfit = lastActivePosition.EntryPrice - atrStopPercent * winLoss * hourlyATR[lastActivePosition.EntryBarNum] / 100;
                        double stopLoss = lastActivePosition.EntryPrice + atrStopPercent * hourlyATR[lastActivePosition.EntryBarNum] / 100;

                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtProfit(bar + 1, takeProfit, "Short");
                        }
                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtStop(bar + 1, stopLoss, "Short");
                        }
                    }
                }
                else
                {
                    if (CrossOver(bar, sec.ClosePrices, SMA)) //Вхожу в длинную позицию
                    {
                        sec.Positions.BuyAtMarket(bar + 1, 1, "Long");
                    }
                    else if (CrossUnder(bar, sec.ClosePrices, SMA))
                    {
                        sec.Positions.SellAtMarket(bar + 1, 1, "Short");
                    }
                }
            }
        }


Мне правда не нравится большое количество проверок, но пока не придумал как можно отрефакторить. У меня по этому коду ещё пара вопросов есть.
1.Правильно ли я понимаю, что при закрытие позиции через CloseAtProfit и CloseAtStop когда цена коснется цены указанной в заявке, то будет сгенерирован рыночный приказ. То есть, к примеру, я купил сбербанк за 100 рублей тэйк профит поставил на 110, а стоп лосс установил на 90. Когда на рынке совершится первая сделка с ценой к примеру 110.1р. то моя заявка будет исполнена по рынку?
2.Будут ли у меня проблемы при реальной торговле при теперешних модификациях кода. Я имею в виду то что я рассчитываю тейк и стоп каждый раз а не запоминаю значение.
Code:
                        double takeProfit = lastActivePosition.EntryPrice + atrStopPercent * winLoss * hourlyATR[lastActivePosition.EntryBarNum] / 100;
                        double stopLoss = lastActivePosition.EntryPrice - atrStopPercent * hourlyATR[lastActivePosition.EntryBarNum] / 100;

                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtProfit(bar + 1, takeProfit, "Long"); //Выставляю Take Profit
                        }
                        if (lastActivePosition.IsActive)
                        {
                            lastActivePosition.CloseAtStop(bar + 1, stopLoss, "Long"); //Выставляю Stop Loss
                        }

Наверх


Moderator:  ViL, sar