Общие вопросы по разработке > Индикатор не отрисовывает линию

Общие вопросы по разработке в Альфа-Директ 4. Обсуждение разработки пользовательских индикаторов, стратегий.
spekt
Сообщения: 12
Зарегистрирован: 15 фев 2019, 07:24

Индикатор не отрисовывает линию

Непрочитанное сообщение spekt » 08 июн 2019, 12:17

Столкнулся со странным поведением индикатора.

Вот код:

Код: Выделить всё

function Initialize()

{

   IndicatorName = "EMA_Diff v2";
   PriceStudy = false;

     AddInput("Input", Inputs.Candle);
    
     AddParameter("SMA_P", 384); // SMA индикатора
     AddParameter("EMA_P", 10);
     AddParameter("SMA_H", 384); // SMA для истории

     AddParameter("X_Avg", 4);

     AddGlobalVariable("flag", Types.Int, 1); // Нужен для разового назначения при старте
     AddGlobalVariable("Period", Types.Int, 0); // Период SMA
     AddGlobalVariable("diff_sum", Types.Double, 0.0);
   
   AddSeries("Line", DrawAs.Line, Color.Navy);

}

function Evaluate()

{
   if(flag == 1)
    {
       Period = (int)Math.Round(SMA_H * X_Avg, 0);
       flag = 0;
   }

    var sma_v = SMA(Input.Close, SMA_P);
    var ema_v = EMA(Input.Close, EMA_P);

    double diff = (sma_v[0] >= ema_v[0]) ? ((sma_v[0] / ema_v[0] - 1.0)*10000.0) : ((ema_v[0] / sma_v[0] - 1.0)*10000.0);
    double diff_avg;

   diff_sum = (diff_sum + diff)/(CurrentIndex+1);
       
    Line = diff_sum;
}


Компилятор пропускает, но в области индикатора пусто.

Если поставить Line = diff, то линия есть. Если поставить diff_sum = (diff_sum + 1)/(CurrentIndex+1) линия есть. А складывать два значения double отказывается в принципе :(

Кто-нибудь знает что не так?

Аватара пользователя
evge
Администратор
Сообщения: 1807
Зарегистрирован: 04 фев 2016, 09:46
Откуда: Млечный путь, планета Земля
Благодарил (а): 83 раза
Поблагодарили: 361 раз
Контактная информация:

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение evge » 09 июн 2019, 10:03

В самом начале скрипта

Код: Выделить всё

function Evaluate()
{
   if (CurrentIndex < Math.Max(SMA_P, EMA_P)) return;
//...
никогда такого не было и вот опять

spekt
Сообщения: 12
Зарегистрирован: 15 фев 2019, 07:24

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение spekt » 14 июн 2019, 08:30

evge писал(а):В самом начале скрипта

Код: Выделить всё

function Evaluate()
{
   if (CurrentIndex < Math.Max(SMA_P, EMA_P)) return;
//...



Не помогло :( Пробую это вот в таком варианте:

Код: Выделить всё

function Initialize()

{

   IndicatorName = "Diff_SMA";
   PriceStudy = false;

   AddInput("Input", Inputs.Price);
    
   AddParameter("SMA_P", 384, 1); // SMA индикатора
   AddParameter("EMA_P", 12, 1);

    AddParameter("Diff_Avg", 10);

    AddGlobalVariable("sum", Types.Double,0); // Период SMA
    AddSeries("EMA_Diff", DrawAs.Line, Color.Red);
   
}

function Evaluate()

{
    if (CurrentIndex < Math.Max(SMA_P, EMA_P)){return;}

    var diff = MY.ES_Diff(Input, EMA_P, SMA_P);

    if(CurrentIndex < Diff_Avg){

        sum = sum + diff[0];
    }
    else
    {
        sum = sum + diff[0] - diff[-Diff_Avg];
    }

    EMA_Diff = sum / Diff_Avg;

}

Аватара пользователя
evge
Администратор
Сообщения: 1807
Зарегистрирован: 04 фев 2016, 09:46
Откуда: Млечный путь, планета Земля
Благодарил (а): 83 раза
Поблагодарили: 361 раз
Контактная информация:

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение evge » 14 июн 2019, 09:31

Вы пробовали предложенное решение для вашего первоначального вопроса (кода)?

Ещё раз проверил.
Взял код из вашего первого сообщения и добавил в него код из моего ответа.
Результат: Индикатор заработал, линия отображается.

spekt писал(а):Не помогло :( Пробую это вот в таком варианте:

:?:

Если хотите ответ на второй вопрос, то нужен код индикатора ES_Diff.
никогда такого не было и вот опять

spekt
Сообщения: 12
Зарегистрирован: 15 фев 2019, 07:24

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение spekt » 14 июн 2019, 14:53

evge писал(а):Вы пробовали предложенное решение для вашего первоначального вопроса (кода)?

Ещё раз проверил.
Взял код из вашего первого сообщения и добавил в него код из моего ответа.
Результат: Индикатор заработал, линия отображается.

spekt писал(а):Не помогло :( Пробую это вот в таком варианте:

:?:

Если хотите ответ на второй вопрос, то нужен код индикатора ES_Diff.


Евгений, спасибо, я тут не прав :( в изначальном варианте все работает, ошибка где-то еще. Чтобы не тратить ваше время я написал финальный вариант индикатора, ради которого все затевалось. Но он, естественно, не отрисовывает линии :(

Можете его посмотреть пожалуйста?

Код: Выделить всё

function Initialize()

{

   IndicatorName = "Diff_Agg_PieAvg";
   PriceStudy = false;

     AddInput("Input", Inputs.Price);
    
   AddParameter("SMA_P", 384, 1); // SMA индикатора
   AddParameter("EMA_P", 12, 1);
   AddParameter("SMA_H", 384, 1); // SMA для истории

    AddParameter("Diff_Avg", 12);
   AddParameter("X_Avg", 4);
    AddParameter("Percent_Avg", 50);
    AddParameter("Percent_High", 50);

    AddGlobalVariable("flag", Types.Int, 1); // Нужен для разового назначения при старте
    AddGlobalVariable("Period", Types.Int, 0); // Период SMA
    AddGlobalVariable("diff_sma", Types.DoubleList);
    AddGlobalVariable("sum", Types.DoubleList);

    AddSeries("EMA_Diff", DrawAs.Line, Color.Red);
    AddSeries("EMA_Diff_Avg_Line", DrawAs.Line, Color.Navy);
    AddSeries("EMA_Diff_Max_Avg_Line", DrawAs.Line, Color.Green);
}

function Evaluate()

{
    List<double> max = new List<double> ();


    // Ограничения пока не накопилась статистика
    if (
       
        CurrentIndex < Math.Max(SMA_P, EMA_P)
       
        ){
            EMA_Diff = 0;
            EMA_Diff_Avg_Line = 0;
            EMA_Diff_Max_Avg_Line = 0;
            return;
        }
    else
    {
        if(flag == 1)
        {
            Period = (int)Math.Round(SMA_H * X_Avg, 0);
            flag = 0;
        }

        // Сначала считаем разлёт
            var sma_v = SMA(Input.Close, SMA_P);
            var ema_v = EMA(Input.Close, EMA_P);

            double diff = (sma_v[0] >= ema_v[0]) ? ((sma_v[0] / ema_v[0] - 1.0)*10000.0) : ((ema_v[0] / sma_v[0] - 1.0)*10000.0);
       
        // Сглаживаем разлет

            diff_sma.Add(diff);

            if(diff_sma.Count > Diff_Avg)
            {
                diff_sma.RemoveAt(0);
            }

            if(diff_sma.Count > 1)
            {
                diff = diff_sma.Average();
            }

        // Затем добавляем разлет к сумме

            sum.Add(diff);
       
        // Убираем из суммы лишний период

            if(sum.Count > Period)
            {
                sum.RemoveAt(0);
            }

        // Наполняем массив максимумов

            if(sum.Count > 2)
            {

                foreach(double d in sum){
                    if(d > sum.Average()){
                        max.Add(d);
                    }
                }

            }
       
        int r_z_s, r_z_m;

        // Определяем количество отсечения

            if(sum.Count > 3)
            {
               
                r_z_s = (int)Math.Round((100-(double)Percent_Avg)/2/100 * sum.Count, 0);

                if(r_z_s > (sum.Count - 2)/2){ r_z_s = (sum.Count - 2)/2; }

            } else
            {
                r_z_s = 0;
            }
           
            if(max.Count > 3)
            {
               
                r_z_m = (int)Math.Round((100-(double)Percent_High)/2/100 * max.Count, 0);
               
                if(r_z_m > (max.Count-2)/2){ r_z_m = (max.Count - 2)/2; }

            } else
            {
             
                r_z_m = 0;

            }
       
        // Получаем область по всем разлетам

            double avg_diff, max_diff;
            List<double> diff_area = new List<double> (sum);
            List<double> max_area = new List<double> (max);

            diff_area.Sort();
            max_area.Sort();

            // Отсечение средних

                if(r_z_s > 0)
                {
                    for(int i=0;i<r_z_s;i++){
                        diff_area.RemoveAt(i);
                    }

                    for(int i=(diff_area.Count-1);i>(diff_area.Count-1) - r_z_s;i--)
                    {
                        diff_area.RemoveAt(i);
                    }

                    avg_diff = diff_area.Average();
                }
                else
                {
                    if(diff_area.Count > 1)
                    {
                    avg_diff = diff_area.Average();
                    } else avg_diff = diff_area[0];
                }

               if(r_z_m > 0)
                {
                    for(int i=0;i<r_z_m;i++){
                        max_area.RemoveAt(i);
                    }

                    for(int i=(max_area.Count-1);i>(max_area.Count-1) - r_z_m;i--)
                    {
                        max_area.RemoveAt(i);
                    }

                    max_diff = max_area.Average();
                }
                else
                {
                    if(max_area.Count > 1)
                    {
                        max_diff = max_area.Average();
                    }
                    else
                    {
                        max_diff = avg_diff;
                    }
                }

        EMA_Diff = diff;
        EMA_Diff_Avg_Line = avg_diff;
        EMA_Diff_Max_Avg_Line = max_diff;

    }
}



Задача в том, чтобы сначала собрать расхождения EMA и SMA за период, потом собрать второй список с расхождениями выше среднего. Далее в обоих списках исключить Х% минимальных и максимальных значений (поровну), чтобы убрать экстреммумы. После исключения получить среднее значение и передать в индикатор.

Аватара пользователя
evge
Администратор
Сообщения: 1807
Зарегистрирован: 04 фев 2016, 09:46
Откуда: Млечный путь, планета Земля
Благодарил (а): 83 раза
Поблагодарили: 361 раз
Контактная информация:

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение evge » 15 июн 2019, 09:08

Могу сказать, что здесь сразу ряд ошибок мешает работе индикатора:

1. Меняем

Код: Выделить всё

     AddInput("Input", Inputs.Price);

на

Код: Выделить всё

     AddInput("Input", Inputs.Candle);


т.к. иначе не сработает это:

Код: Выделить всё

            var sma_v = SMA(Input.Close, SMA_P);
            var ema_v = EMA(Input.Close, EMA_P);


В Input (Inputs.Price) нет Close

Или вариант 2:
меняем только вызов индикаторов, убрав .Close у Input

Код: Выделить всё

            var sma_v = SMA(Input, SMA_P);
            var ema_v = EMA(Input, EMA_P);

2. Это

Код: Выделить всё

            if(sum.Count > 2)
            {
                foreach(double d in sum){
                    if(d > sum.Average()){
                        max.Add(d);
                    }
                }
            }

работает крайне медленно т.к. постоянно вычисляется средняя (Average) в цикле.
меняем на

Код: Выделить всё

            if(sum.Count > 2)
            {
            double sumA = sum.Average();
                foreach(double d in sum)
                    if(d > sumA) max.Add(d);
            }

заодно убрал лишние "египетские скобки" { }

3. Вот это удаляем

Код: Выделить всё

            // Отсечение средних

                if(r_z_s > 0)
                {
                    for(int i=0;i<r_z_s;i++){
                        diff_area.RemoveAt(i);
                    }

                    for(int i=(diff_area.Count-1);i>(diff_area.Count-1) - r_z_s;i--)
                    {
                        diff_area.RemoveAt(i);
                    }

                    avg_diff = diff_area.Average();
                }

и меняем на

Код: Выделить всё

            // Отсечение средних

                if(r_z_s > 0)
                {
                    diff_area.RemoveRange(0, r_z_s);
                    diff_area.RemoveRange(diff_area.Count - r_z_s, r_z_s);
                    avg_diff = diff_area.Average();
                }

4. Аналогично поступаем с этим

Код: Выделить всё

               if(r_z_m > 0)
                {
                    for(int i=0;i<r_z_m;i++){
                        max_area.RemoveAt(i);
                    }

                    for(int i=(max_area.Count-1);i>(max_area.Count-1) - r_z_m;i--)
                    {
                        max_area.RemoveAt(i);
                    }

                    max_diff = max_area.Average();
                }

меняем на

Код: Выделить всё

               if(r_z_m > 0)
                {
                    max_area.RemoveRange(0, r_z_m);
                    max_area.RemoveRange(max_area.Count - r_z_m, r_z_m);
                    max_diff = max_area.Average();
                }


В итоге получаем следующее (полный код):

Код: Выделить всё

function Initialize()

{

   IndicatorName = "Diff_Agg_PieAvg";
   PriceStudy = false;

     AddInput("Input", Inputs.Candle);
     
   AddParameter("SMA_P", 384, 1); // SMA индикатора
   AddParameter("EMA_P", 12, 1);
   AddParameter("SMA_H", 384, 1); // SMA для истории

    AddParameter("Diff_Avg", 12);
   AddParameter("X_Avg", 4);
    AddParameter("Percent_Avg", 50);
    AddParameter("Percent_High", 50);

    AddGlobalVariable("flag", Types.Int, 1); // Нужен для разового назначения при старте
    AddGlobalVariable("Period", Types.Int, 0); // Период SMA
    AddGlobalVariable("diff_sma", Types.DoubleList);
    AddGlobalVariable("sum", Types.DoubleList);

    AddSeries("EMA_Diff", DrawAs.Line, Color.Red);
    AddSeries("EMA_Diff_Avg_Line", DrawAs.Line, Color.Navy);
    AddSeries("EMA_Diff_Max_Avg_Line", DrawAs.Line, Color.Green);
}

function Evaluate()

{
    List<double> max = new List<double> ();


    // Ограничения пока не накопилась статистика
    if (
       
        CurrentIndex < Math.Max(SMA_P, EMA_P)
       
        ){
            EMA_Diff = 0;
            EMA_Diff_Avg_Line = 0;
            EMA_Diff_Max_Avg_Line = 0;
            return;
        }
    else
    {
        if(flag == 1)
        {
            Period = (int)Math.Round(SMA_H * X_Avg, 0);
            flag = 0;
        }

        // Сначала считаем разлёт
            var sma_v = SMA(Input.Close, SMA_P);
            var ema_v = EMA(Input.Close, EMA_P);
                       
            double diff = (sma_v[0] >= ema_v[0]) ? ((sma_v[0] / ema_v[0] - 1.0)*10000.0) : ((ema_v[0] / sma_v[0] - 1.0)*10000.0);
                       
       
        // Сглаживаем разлет

            diff_sma.Add(diff);

            if(diff_sma.Count > Diff_Avg)
            {
                diff_sma.RemoveAt(0);
            }

            if(diff_sma.Count > 1)
            {
                diff = diff_sma.Average();
            }           

        // Затем добавляем разлет к сумме

            sum.Add(diff);
       
        // Убираем из суммы лишний период

            if(sum.Count > Period)
            {
                sum.RemoveAt(0);
            }

        // Наполняем массив максимумов

            if(sum.Count > 2)
            {
            double sumA = sum.Average();
                foreach(double d in sum)
                    if(d > sumA) max.Add(d);

            }
                   
        int r_z_s, r_z_m;

        // Определяем количество отсечения

            if(sum.Count > 3)
            {
               
                r_z_s = (int)Math.Round((100-(double)Percent_Avg)/2/100 * sum.Count, 0);

                if(r_z_s > (sum.Count - 2)/2){ r_z_s = (sum.Count - 2)/2; }

            } else
            {
                r_z_s = 0;
            }
           
            if(max.Count > 3)
            {
               
                r_z_m = (int)Math.Round((100-(double)Percent_High)/2/100 * max.Count, 0);
               
                if(r_z_m > (max.Count-2)/2){ r_z_m = (max.Count - 2)/2; }

            } else
            {
             
                r_z_m = 0;

            }
       
        // Получаем область по всем разлетам

            double avg_diff, max_diff;
            List<double> diff_area = new List<double> (sum);
            List<double> max_area = new List<double> (max);

            diff_area.Sort();
            max_area.Sort();

            // Отсечение средних

                if(r_z_s > 0)
                {
                    diff_area.RemoveRange(0, r_z_s);
                    diff_area.RemoveRange(diff_area.Count - r_z_s, r_z_s);
                    avg_diff = diff_area.Average();
                }
                else
                {
                    if(diff_area.Count > 1)
                    {
                    avg_diff = diff_area.Average();
                    } else avg_diff = diff_area[0];
                }               

               if(r_z_m > 0)
                {
                    max_area.RemoveRange(0, r_z_m);
                    max_area.RemoveRange(max_area.Count - r_z_m, r_z_m);
                    max_diff = max_area.Average();
                }
                else
                {
                    if(max_area.Count > 1)
                    {
                        max_diff = max_area.Average();
                    }
                    else
                    {
                        max_diff = avg_diff;
                    }
                }

        EMA_Diff = diff;
        EMA_Diff_Avg_Line = avg_diff;
        EMA_Diff_Max_Avg_Line = max_diff;

    }
}


Diff_Agg_PieAvg-01.png
Diff_Agg_PieAvg-01.png (34.86 КБ) 15412 просмотров


Я не вникал в логику работы индикатора полностью, а лишь исправлял нерабочий код и местами оптимизировал, доведя до работающего индикатора.
Возможно, могут быть ещё проблемы. Проверяйте.
никогда такого не было и вот опять

spekt
Сообщения: 12
Зарегистрирован: 15 фев 2019, 07:24

Re: Индикатор не отрисовывает линию

Непрочитанное сообщение spekt » 15 июн 2019, 13:30

Огромное спасибо!


Вернуться в «Общие вопросы по разработке»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 20 гостей