Кому стратегию? Много и бесплатно) - страница 58

 
1. I can rewrite the indicators in order to replace float with double.
2. protected static float fMicron = 0.000075f; // Coef used when we compare two floats
3. Indicator Base Constructor:

/// <summary>
/// The default constructor
/// </summary>
public Indicator()
{
    sIndicatorName  = string.Empty;
    bSeparatedChart = false;
    bIsDescreteValues = false;
    afSpecValue     = new float[] { };
    fMinValue       = float.MaxValue;
    fMaxValue       = float.MinValue;
    bIsCalculated   = false;
    parameters      = new IndicatorParam();
    component       = new IndicatorComp[] { };
}




4. Base Price:



/// <summary>
/// Calculates the base price.
/// </summary>
/// <param name="price">The base price type.</param>
/// <returns>Base price.</returns>
protected static float[] Price(BasePrice price)
{
    float[] afPrice = new float[Bars];

    switch(price)
    {
        case BasePrice.Open:
            afPrice = Open;
            break;
        case BasePrice.High:
            afPrice = High;
            break;
        case BasePrice.Low:
            afPrice = Low;
            break;
        case BasePrice.Close:
            afPrice = Close;
            break;
        case BasePrice.Median:
            for (int iBar = 0; iBar < Bars; iBar++)
                afPrice[iBar] = (Low[iBar] + High[iBar]) / 2;
            break;
        case BasePrice.Typical:
            for (int iBar = 0; iBar < Bars; iBar++)
                afPrice[iBar] = (Low[iBar] + High[iBar] + Close[iBar]) / 3;
            break;
        case BasePrice.Weighted:
            for (int iBar = 0; iBar < Bars; iBar++)
                afPrice[iBar] = (Low[iBar] + High[iBar] + 2 * Close[iBar]) / 4;
            break;
        default:
            break;
    }
    return afPrice;
}

6. I have got working NET <-> MT bridge. Its metter of time to make FSB trading through MT. Of course it will be for demo accounts only untill became "rock solid".

 

As I think Aroon indicator only uses: bIsDescreteValues = true;


About RSI, I remember I was wondering about the formula. It was 5-6 years ago. I think I used this formula from a popular TA book. Don't remember exactly which one.

 

"Use previous bar value"

I personally think that this is one of the most important features of FSB.


        /// <summary>
        /// Sets the "Use previous bar value" checkbox
        /// </summary>
        /// <returns>Is any Changes</returns>
        public bool SetUsePrevBarValueCheckBox(int iSlot)
        {
            bool isChanged = false;

            for (int iParam = 0; iParam < Slot[iSlot].IndParam.CheckParam.Length; iParam++)
            {
                if (Slot[iSlot].IndParam.CheckParam[iParam].Caption == "Use previous bar value")
                {
                    bool bOrigChecked = Slot[iSlot].IndParam.CheckParam[iParam].Checked;
                    bool bChecked = true;

                    // Entry slot
                    if (Slot[iSlot].SlotType == SlotTypes.Open)
                    {
                        bChecked = true;
                    }

                    // Open filter slot
                    else if (Slot[iSlot].SlotType == SlotTypes.OpenFilter)
                    {
                        bChecked = EntryExecutionTime != TimeExecution.Closing;
                    }

                    // Close slot
                    else if (Slot[iSlot].SlotType == SlotTypes.Close)
                    {
                        bChecked = true;
                    }

                    // Close filter slot
                    else if (Slot[iSlot].SlotType == SlotTypes.CloseFilter)
                    {
                        bChecked = false;
                    }

                    if (bChecked)
                    {
                        for (int iPar = 0; iPar < Slot[iSlot].IndParam.ListParam.Length; iPar++)
                        {
                            if (Slot[iSlot].IndParam.ListParam[iPar].Caption == "Base price" &&
                                Slot[iSlot].IndParam.ListParam[iPar].Text    == "Open")
                            {
                                bChecked = false;
                            }
                        }
                    }

                    if (bChecked != bOrigChecked)
                    {
                        isChanged = true;
                        Slot[iSlot].IndParam.CheckParam[iParam].Checked = bChecked;
                    }
                }
            }

            return isChanged;
        }
 

To see the indicator values in its full precision press F12 in the chart window.


Another option is to use the "Command Console". ind xxxx shows the indicators for bar xxxx




I don't dig deeply in MT formulas. Probably they are no too much different. Here are the default FSB RSI and MT RSI.







___________________--

Edit:

I tried to calculate RSI without this additional smoothing:

            for (int iBar = 1; iBar < Bars; iBar++)
            {
                if (afBasePrice[iBar] > afBasePrice[iBar - 1]) afPos[iBar] = afBasePrice[iBar] - afBasePrice[iBar - 1];
                if (afBasePrice[iBar] < afBasePrice[iBar - 1]) afNeg[iBar] = afBasePrice[iBar - 1] - afBasePrice[iBar];
            }

            float[] afPosMA = MovingAverage(iPeriod, 0, maMethod, afPos);
            float[] afNegMA = MovingAverage(iPeriod, 0, maMethod, afNeg);

            //for (int iBar = iFirstBar; iBar < Bars; iBar++)
            //{
            //    afPosMA[iBar] = (afPosMA[iBar - 1] * (iPeriod - 1) + afPos[iBar]) / iPeriod;
            //    afNegMA[iBar] = (afNegMA[iBar - 1] * (iPeriod - 1) + afNeg[iBar]) / iPeriod;
            //}

            for (int iBar = iFirstBar; iBar < Bars; iBar++)
            {
                if (afNegMA[iBar] == 0)
                    afRSI[iBar] = 100;
                else
                    afRSI[iBar] = 100 - (100 / (1 + afPosMA[iBar] / afNegMA[iBar]));
            }


But in this case the RSI value for 2009.3.24 jumps to 74.800.



----------------------


Thank you Stellarator for the good words!

I'll not abandon Forex Strategy Builder and just because of people like you. Even in opposite I'm open for discussion in order to make FSb more robust and user friendly.

In that direction I think I can add MT indicators in FSB. Something like MT compatibility mode :)

MT_MACD, MT_RSI, ... These to be with the same parameters as the MT standard ones.


We have to find solution to Bar Opening and Bar closing entry/exit points. They are vital for FSB -> MT integration.


 
Stellarator >>:

.........Совместить их (два буфера) в один не получится (подумывал... там же не только 1/0 может быть (которые можно было бы в битовую маску превратить), еще и ценники). Скорей всего как-то с самими значениями индикатора буду изголяться... Посмотрим... По ходу...

Ну почему же не получиться(?).

Давно уже использую однократный вызов icustom для получения нескольких значений из различных буферов индикаторов, слишком расточительно эту функцию несколько раз в коде использовать, особенно при оптимизации, да еще с "тяжелыми" индюками. По сути, все что нам нужно (по максимуму), это получить направление торговли и уровнии SL & TP..... задача решается простой арифметикой.

Вот фрагмент кода индикатора с одним лишь дополнительным буфером (Signal):

// в самом кончике start такой фрагмент

      
   if (Direction[0] !=0)
      {
      if (Direction[0] > 0) Signal[0]=Set_TP[0]/Point*1000000 + Set_SL[0]/Point;
      if (Direction[0] < 0) Signal[0]=-(Set_TP[0]/Point*1000000 + Set_SL[0]/Point);
      }
   return(0);

А вот обратное преобразование в коде эксперта:

int start()
  {
   // Получение значений из буфера индикатора в последней фазе формирования бара
   if (TimeCurrent() > (Time[0]+CP60)
      {
      Signal=iCustom(NULL, 0, "_iK_tay_v01M1",Discret,6,0)
      }     

   if(Time[0] != prevtime)
      { 
      Calcul();
      //if (Tral !=0) CalcLevel();
      prevtime = Time[0];
      }
   else return;

.........

void Calcul()
  {
   OpenSell=0; OpenBuy=0; CloseBuy=0; CloseSell=0;
   
   if(Signal > 0) 
      {
      OpenBuy=1; CloseSell=1;
      TP=NormalizeDouble (Signal*Point/1000000, Digits-1);      
      SL=(Signal-TP/Point*1000000)*Point;   
      }
   if(Signal < 0) 
      {
      CloseBuy=1; OpenSell=1;
      TP=NormalizeDouble (MathAbs(Signal)*Point/1000000, Digits-1);      
      SL=(MathAbs(Signal)-TP/Point*1000000)*Point;   
      }   
   return;
  }

Таким образом мы получаем 3 значения индикатора (направление, TP и SL) всего лишь однократным вызовом индикатора. Полученными результатами дальше можно распоряжаться как угодно :)

Принцип, надеюсь, понятен.

 

С добрым утром всем!


Miroslav_Popov писал(а) >>

1. I can rewrite the indicators in order to replace float with double.

Мирослав - это важно! Часть причин уже приводил в своих сообщениях. Но я прекрасно понимаю и трудозатраты... И то, что сейчас (скорей всего) Вы работаете над искомым bridge'ом или чем существенным еще.


Но время нужно найти. По моим прогнозам - не более какого-то количества часов (в пределах одних суток). Т.к. дело не только в простой замене одного на другое при декларировании переменных (что тоже повлечет хотя бы визуальную проверку и визуальную корректировку "для красоты" (где переменные описываются с табуляцией, например и т.п.) :) - хотя это и не принципиально).

Во первых - вполне возможны случаи, где float используется целенаправленно (для принудительного понижения точности). Тут нужно видеть весь код, в целом.

Во вторых - вопрос сравнения таких ("новых") чисел и их отображения в FSB (об этом ниже, в п.2)

Короче - будет нужно аккуратно пробежаться по всему коду и хотя бы прикинуть возможные drawbacks, связанные с переходом вещественной математики на double.


Miroslav_Popov писал(а) >>

2. protected static float fMicron = 0.000075f; // Coef used when we compare two floats


(и чуть ниже):

To see the indicator values in its full precision press F12 in the chart window.

И это одна из проблем! Почему именно 0.000075? А не 0.00005? Или 0.000001? (как у меня)

Развернутая проблема (для интересующихся) и вопрос:

Как известно, сравнение двух вещественных чисел на предмет равенства никогда не стоит осуществлять подобными конструкциями:

double Value1, Value2;

if (Value1 == Value2) {
  // Some useful code there
}

Это связанно с тем, что после результатов некоторых вычислений (особенно вариаций на тему умножить/разделить), значения данных переменных могут быть визуально похожи (1.0 и 1.0, например), но реально НЕ совпадать. (1.000001 и 1.000000, на самом деле). Данное свойство проистекает из некоторой дискретности представления вещественных числе в компьютерах и с некоторой (конечной) дискретностью (точностью) вычислений. В общем случае, сравнение на предмет равенства осуществляется по вариациям на классическую тему (которую, кстати, использует Мирослав):

if (Math.Abs(afIndValue[iCurrBar] - afIndValue[iBaseBar]) < fMicron) {
  // Some code there
}

Это "классика" сравнения двух вещественных чисел на предмет равенства с какой-то конечной точностью, определяемой fMicron, в данном случае.


И вот тут кроется одна из потенциальных проблем. Как, кто и для каких случаев должен определять значение этой самой fMicron? Всегда ли хороша константа, как у Мирослава (вопрос о значении которой еще тоже - обсуждаем)?


В общем, если интригу не нагонять - сторонник следующей теории:

1. В общем случае существуют два типа сравнения таких переменных, на предмет равенства и на предмет неравенства (<, >).

2. Существуют два типа самих переменных: переменные с гарантированной фиксированной точностью (цены, лоты и т.п.), и абстрактные значения, без какой-то определенной точности (вроде значений индикаторов).

3. На предмет неравенства переменные (любого типа) сравниваются (в общем случае) тупо "в лоб" (if (Value1 < Value2) { ...}). Если здесь необходимо ограничить точность (что бывает достаточно редко), можно использовать конструкцию, как у Мирослава:

if (afIndValue[iBaseBar] < afIndValue[iCurrBar] - fMicron) {
  // Some code there
}

4. А вот на предмет равенства к проблеме (обычно) подходят по разному, в зависимости от оперируемых данных.

4.1. Если необходимо сравнить два числа с фиксированной точностью (например, два значения цены, чтобы принять решение о том, нужно ли модифицировать ордер или нет (чтобы на напороться на "No Result")), делается обычно так (тоже, "классика"):

int ComparePriceInt(double Value1, double Value2) {
   Value1 -= Value2;
   Value2 = Point / 2.0;
   if (Value1 > Value2)
      return(1);
   if (Value1 < -Value2)
      return(-1);
   return(0);
}

Функция избыточна, для нашего случая, но суть не в том. Ключевая конструкция в ней Point / 2.0. Именно такое fMicron дает нам нужную, корректную и достаточную точность вычислений... В ДАННОМ КОНКРЕТНОМ СЛУЧАЕ! Когда сравниваются две цены (с одними и теми-же Digits и, как следствие, Point ) Т.е. для случая, например (Point = 0.0001):

fMicron = 0.00005

и сравнивая 1.2345 (цена ордера) с 1.23451 (значение индикатора) - мы получим равенство, а 1.2345 с 1.23456 - неравенство... Отгадайте, что будет в последнем случае при fMicron = 0.000075? ;) Можно, конечно, предварительно нормализовывать переменные до одной (меньшей) точности. Но это не наш метод :D...

Еще раз - выбор этого параметра важен, и для каждого конкретного случая "немножко уникален" :)1


Я бы предложил следующую парадигму:

1. Переменные с фиксированной точностью сравниваются расчитываемым значением fMicron (Point / 2, например, для случая с ценами)

2. Значения индикаторов и прочей подобной "бесконечно точной мелочи" :), сравниваются с константой fMicron равной минимальному значению Point, используемых инструментов, деленному на 10. Т.е. в случае с инструментами, где Digits не превышает значения 4 - fMicron = 0.00001, если Digits = 5, fMicron = 0.000001 и аналогично.

Мирослав - требуется мнение эксперта :)?!


Теперь вопрос к общественности:

ПОЧЕМУ во всяких DataWindow (в MT или в FSB (Indicator Charts)) - значения индикаторов всегда показываются с фиксированной точностью (Digits = 4)? А почему не 3 знака после запятой? Или 5, 6, 7, ...? :)?! Нет, ну в самом деле?

У Мирослава оказалась "заначка" (hidden feature? ;)) - я про F12! А в MT что нажимать?

И вообще, ну кто определил эту константу? (4 знака после запятой)

Я догадываюсь, что она почти непосредственно связана с размерностью приходящих котировок (1.2345), для большинства инструментов (кто-то просто ее зашил). Но ведь не секрет, что многие ДЦ переходят на большие разрядности (5, например). Так почему действительно не показывать значения индикаторов в размерности, совпадающей с размерностью котировок инструмента (Digits)?

Или я что-то принципиально не "догоняю" в теме (пожалуйста - объясните кто-нибудь, может это "так надо" потому-что...)?!


Miroslav_Popov писал(а) >>

3. Indicator Base Constructor:

4. Base Price:

Мирослав, я очень хорошо разобрался в коде, представленном на страничке Source :). И что делает protected static float[] Price(BasePrice price) я прекрасно понимаю. Если это намек на громоздкость моего кода - отвечу, что я намеренно отказался от использования дополнительных буферов для хранения (в общем случае, либо копий ценовых буферов, либо вычисляемых копий оных (Typical и прочее)). И место экономится, а там, где всякие Typical - ИХ ВСЕ РАВНО нужно вычислять!


Тут нужно упомянуть критическую разность в подходе вычислений значений индикаторов в FSB и в MT:

1. Во первых, по крайней мере в данный момент - котировки, загружаемые в FSB для самого FSB статичны, т.е. он один раз их загрузил, расчитал ОДИН РАЗ значения требуемых индикаторов ДЛЯ всего диапазона баров и дальше просто "едет" по ним, эмулируя поведение торгового робота. Т.е. еще раз - значения индикаторов расчитываются один раз, ДО запуска виртуализации торгового робота. Этим, в частности, объясняется скорость эмуляции торговых сделок. Котировки же в MT приходят постоянно и родной тестер стратегий НЕ видит будущее, т.е. мы вынужденны расчитывать значение индикатора каждый раз. И если тупо применить подход Мирослава (расчет всего буфера целиком)... меня просто закидают тухлыми яйцами :). Поэтому особое внимание уделено использованию IndicatorCounted()! Индикаторы расчитываются почти с максимально возможной скоростью в каждом конкретном случае (если все бары нужно считать, или только один). Кое где, кое что - еще можно пооптимизировать, но на досуге...

2. Соотв. каждый раз (при приходе новго тика) в дополнительных буферах генерировать значения цен - избыточно. ИХ ВСЕ РАВНО вычислять, так пусть это делают сами функции (тот-же MovingAverage и т.д.). Экономится место, упрощается логика (не нужно каждый раз анализировать, какие бары пересчитывать в этих буферах), сохраняется скорость (даже где-то выше, в общем случае). "По моему - так" (с) Винни-Пух


Если еще раз затронуть мою конвертацию индикаторов - то важно, наверное, то - что я полностью сохраняю логику работы функций (и самих индикаторов), просто немного ее модифицирую под конкретный случай использования в MT. Как, впрочем, сохраняю порядок и названия параметров, для управлением самим индикатором.

Ребята - посмотрите исходники, все-таки. Я старался сделать "красиво" :).


Конечный смысл моей конвертации в следующем. Например, у нас есть Opening Point of the Position и три индикатора для дополнительной логики. Вот как будет выглядеть код для размещения ордера (ну, грубо, конечно):

if ( IsSignal(iCustom(NULL, 0, "fsbIndicator1", SLOT_TYPE_LC, Param2, Param3, ..., 0, 0))
    && IsSignal(iCustom(NULL, 0, "fsbIndicator2", SLOT_TYPE_LC, Param2, Param3, ..., 0, 0))
    && IsSignal(iCustom(NULL, 0, "fsbIndicator3", SLOT_TYPE_LC, Param2, Param3, ..., 0, 0)) )
{    
// Открываем длинную позицию (предпоследний 0 в значениях индикаторов - указатель на буфер логики длинных позиций (1, соотв. - на буфер логики коротких))
    // Если у нас значение POP берется из еще одного индикатора, то это значение берется аналогично, только меняется логика поведения индикатора:
    // iCustom(NULL, 0, "fsbIndicator", SLOT_TYPE_POP, Param2, Param3, ..., 0, 0)
}

Как-то так. Подсовываете iCustom свои значения параметров и ждете, когда они все подадут сигнал. Все. Никакого анализа самих значений индикаторов... зачем?

По моему красиво... или нет :)?

 

Про индикаторы:

Насчет (Aroon и bIsDescreteValues = true;) учту.


Насчет RSI...

Мирослав - искомая конструкция запутала как раз Вас :). Не поленитесь еще раз поставить комментарии вокруг нее и ПРАВИЛЬНО воспользоваться КОРРЕКТНО ЗАРАБОТАВШИМ индикатором для получения "совпадающих" значений :). Напомню - классическая формула расчета RSI базируется на экспоненциальной разновидности MA (smoothed, конкретно). ТАК УКАЖИТЕ в параметрах индикатора этот режим сглаживания (smoothed)... и результаты Вас "приятно удивят" :) (по умолчанию, напомню, используется Simple, который и дает расхождения с классикой)! Я не могу сам проделать указанную процедуру - но уверен в своих словах на 100%. Разубедите меня :)?

По итогам испытаний будет следующее предложение, искомый код убрать и сделать значение по умолчанию параметра maMethod в Smoothed во всех индикаторах, использующих RSI (и самом RSI, соотв.). Чтобы по умолчанию же не возникало вот таких вопросов у пользователей. НО тем самым сделать РАБОТОСПОСОБНЫМ выбор этого параметра в индикаторах! (я для примера сконвертировал RSI MA Oscillator, которому, опираясь на результат вычислений RSI, тоже, с текущим поведением самого RSI - все-равно, что там указывается в соотв. параметре)

 
Miroslav_Popov >>:

"Use previous bar value"

I personally think that this is one of the most important features of FSB.

О, ДА!

Это действительно - одна из важнейших возможностей FSB. И я постарался уделить должное внимание тестированию корректной работы логики индикаторов, учитывая данную features.

Спасибо за код, показывающий подсчет значения "по умолчанию"! Учтем...

 
rider >>:

Ну почему же не получиться(?).

Давно уже использую однократный вызов icustom для получения нескольких значений из различных буферов индикаторов, слишком расточительно эту функцию несколько раз в коде использовать, особенно при оптимизации, да еще с "тяжелыми" индюками. По сути, все что нам нужно (по максимуму), это получить направление торговли и уровнии SL & TP..... задача решается простой арифметикой.

...

Принцип, надеюсь, понятен.




:), да конечно получится (я намеренно "огрубил" свое выссказывание в прошлый раз), с проблемой свертывания значений в один параметр я знаком :). И спасибо за приведенный код (сразу вопрос - а были-ли когда-нибудь расхождения в исходных значениях и "в последствии развернутых"? все-таки double...)

Ключевой вопрос... НУЖНО ЛИ ЭТО В ДАННОМ КОНКРЕТНОМ СЛУЧАЕ.

Причины могут быть две:

1. Утилизация дополнительного буфера (для меня существенно именно это) - все-таки у индикаторов их не так много. НО ПОКА мне хватает (видимо пора взяться за Ishimoku уже наконец - и все станет понятно :)))

2. Скорость вызова индикатора из своего кода (Ваш пример)... Мой ответ - не существенно! Заявляю со всей ответственностью. Мотивация:

При каждом новом тике - в индикатор лезть все-равно приходится (придется). Так? (ну там - искомые цены брать или еще что) Пусть даже не при каждом, а когда Вам там нужно. Основной намек, видимо, на то, что многократный вызов iCustom впределах одной итерации советника порождает многократный пересчет индикатора? Вынужден разубедить! Ключевой нюанс - "предел одной итерации советника". Так вот - в этих пределах индикатор расчитывается ОДНОКРАТНО (при первом своем вызове)! Заявляю со 100% уверенностью. Все дальнейшие вызовы вообще не запускают его start(), а просто берут нужные значения из нужных буферов. Условие 100% при неизменности входных параметров (за исключением буфера и смещения). Правило действует при вычислениях в пределах одного инструмента. Но, думаю, принцип сохраняется даже тогда, когда iCustom обращается к другим TF и инструментам.


В общем - сегодня вечером гляну на Ishimoku - там уже точно определюсь, все-таки два буфера под логику... или один :)

 

В общем, всем до вечера (пошел на работу).

Про проблему

We have to find solution to Bar Opening and Bar closing entry/exit points. They are vital for FSB -> MT integration.

подумаю.


Но скорей всего (учитывая отсутствие сигналов от МТ на эту тему) - приведенный выше код (шаблон на пред-предыдущей странице) более-менее оптимален (возможно немножко доработать его потребуется... вечером постараюсь "углубиться" в проблему)

Причина обращения: