Система принятия решений и/или Нечеткая логика(FuzzyLogic)

Страницы: Пред. 1 ... 3 4 5 6 7
RSS
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
А Чудеса продолжаются!
Оказывается, мало того что ADX(Lua) написан с ошибками, так еще и расчеты отличаются от ADX встроенного в терминал?
Накидал свой вариант, но и он выводит другие значения:
Код
function algorithms.getADX()
--[[
    Индикатор ADX с +DI и -DI 
    Среда: QUIK, Lua 5.4
    По методике Уэллса Уайлдера (period = 14)
--]]
-- Вспомогательные функции
local function sum(t, start_idx, end_idx)
    local total = 0
    for i = start_idx, end_idx do total = total + (t[i] or 0) end
    return total
end
local function average(t, start_idx, end_idx)
    return sum(t, start_idx, end_idx)/(end_idx - start_idx + 1)
end
    
   -- Локальные буферы для хранения данных
    local TR, plusDM, minusDM = {}, {}, {}
    local smoothedTR, smoothedPlusDM, smoothedMinusDM = {}, {}, {}
    local plusDI, minusDI, DX, ADX = {}, {}, {}, {}
    local initialized = false  -- Флаг инициализации

    return function (I, Fsettings, ds)
        local Fsettings = Fsettings or {}
        local P = Fsettings.Period or 14  -- Период расчета

        -- Инициализация буферов при первом запуске
        if I == 1 or not initialized then
            TR, plusDM, minusDM = {}, {}, {}
            smoothedTR, smoothedPlusDM, smoothedMinusDM = {}, {}, {}
            plusDI, minusDI, DX, ADX = {}, {}, {}, {}
            initialized = true
            return nil, nil, nil
        end

        -- Получение цен текущего и предыдущего бара
        local high = H(I) or 0
        local low = L(I) or 0
        local closePrev = C(I-1) or 0
        local highPrev = H(I-1) or 0
        local lowPrev = L(I-1) or 0

        -- 1. Расчет True Range (TR)
        TR[I] = math.max(
            high - low,
            math.abs(high - closePrev),
            math.abs(low - closePrev)
        )

        -- 2. Расчет Directional Movement (+DM и -DM)
        local upMove = high - highPrev
        local downMove = lowPrev - low
        plusDM[I] = (upMove > downMove and upMove > 0) and upMove or 0
        minusDM[I] = (downMove > upMove and downMove > 0) and downMove or 0

        -- 3. Сглаживание по методу Уайлдера
        if I == P then
            -- Первичное сглаживание (сумма первых P значений)
            smoothedTR[I] = sum(TR, 2, P)  -- TR начинается с 2-го бара
            smoothedPlusDM[I] = sum(plusDM, 2, P)
            smoothedMinusDM[I] = sum(minusDM, 2, P)
        elseif I > P then
            -- Рекуррентное сглаживание
            smoothedTR[I] = smoothedTR[I-1] - (smoothedTR[I-1]/P) + TR[I]
            smoothedPlusDM[I] = smoothedPlusDM[I-1] - (smoothedPlusDM[I-1]/P) + plusDM[I]
            smoothedMinusDM[I] = smoothedMinusDM[I-1] - (smoothedMinusDM[I-1]/P) + minusDM[I]
        end

        -- 4. Расчет Directional Indicators (+DI и -DI)
        if I >= P and smoothedTR[I] and smoothedTR[I] > 0 then
            plusDI[I] = 100 * (smoothedPlusDM[I]/smoothedTR[I])
            minusDI[I] = 100 * (smoothedMinusDM[I]/smoothedTR[I])
            
            -- 5. Расчет Directional Movement Index (DX)
            local di_sum = plusDI[I] + minusDI[I]
            DX[I] = (di_sum ~= 0) and (100 * math.abs(plusDI[I] - minusDI[I])/di_sum) or 0
        end

        -- 6. Расчет ADX (сглаженный DX)
        if I >= 2*P then
            if I == 2*P then
                -- Начальное значение ADX
                ADX[I] = average(DX, P+1, 2*P)  -- Среднее за P периодов
            else
                -- Сглаживание методом Уайлдера
                ADX[I] = (ADX[I-1]*(P-1) + DX[I])/P
            end
        end

        -- Возврат значений (ADX, +DI, -DI)
        return ADX[I] or nil, plusDI[I] or nil, minusDI[I] or nil
    end
end
Люди кто знаком с темой подскажите, что не так?
То что должно занимать пять минут, колупаю который день, чай уже давно закончился, да и видимо чаем тут одним не обойтись. :lol:  
 
Советую забыть про примеры от ARQA. Они уже давно не поддерживаются. Да и в целом, написаны криво.
 
Nikolay, Так и мой вариант не соответствует встроенному в терминал. Вроде все корректно делаю как в букваре? Накладываю один на другой не соответствуют?
 
Значит есть ошибки. Встроенные индикаторы в терминал - это не то же самое, что библиотека индикаторов INDICATORS.zip
Встроенные, работают корректно.
 
Сравнил более внимательно, есть отличие в сглаживании и соответственно в масштабах отражения этих данных. В общем мой вариант рабочий, не читать же с графиков. А с фильтрами по экспериментирую еще, собственно это и была задача.  
 
Идея заключается в том, чтобы заменить стандартные методы сглаживания на более эффективные, обеспечивающие меньшее запаздывание. Сглаживание по методу Уайлдера - Рекуррентное сглаживание, проблема, этого классического сглаживания (фактически EMA с α = 1/N) дает значительный лаг! Возможно это различие и является причиной различий в расчётах индикатора?

Для снижения лага в расчете ADX можно применить следующие типы фильтров, фокусируясь на ключевых этапах его вычислений:
 * фильтры из Swiss Army Knife (SAK), ранее на сайте мною были опубликованы в процедурной версии (как индикатор);
 * фильтры вроде Zero-Lag EMA (ZLEMA);
 * или адаптивные методы сглаживания, которые динамически подстраиваются под рыночные условия (Kalman Filter).

Оптимизация ADX с использованием фильтров Swiss Army Knife (SAK), наиболее любопытный вариант, интеграция фильтров Джона Элерса позволяет значительно снизить задержки ADX, сохранив его основную логику.

Сравнивать буду точки пересечения +DI/-DI в классической и SAK-версиях. Предварительные тесты показывают, что оптимизированная версия должна давать сигналы на 2-3 бара раньше при сопоставимой точности. Много это или мало судите сами, для HFT-стратегий (в рамках HFT-стратеги QUIK) это одна тема, для цикличных рынков совсем другая, ну и конечно для трендоследящих, ради чего все это затевалось (вспомнил хоть и отстал от графика, примерно так стоишь на остановке в ожидании поезда, а его все нет, вот уже вторые сутки нет).
А получить торговый сигнал на 2-3 дня или часа РАНЬШЕ! Каково?

Пару слов о фильтрах, здесь имеет значение практически все, торговый тайм фрейм, период окна данных и так далее, все зависит от задачи что хотим выделить или подчеркнуть.
Например, как вариант применения:
      Для высокочастотной торговли используйте  - EMA или Butterworth_LP
      Для подавления шума в трендах                     - Kalman + Wavelet
      Для цикличных рынков                                     - комбинация BP + HP
Каждый из них вносит свою лепту в вычисления.

Начать можно с адаптивного периода + ZLEMA для сглаживания, для HFT-стратегий можно добавить Kalman Filter.
Примеры стратегий которые хочу проверить:
а) Тренд + Осциллятор: ФНЧ (Butterworth) для тренда + ФВЧ (HP) для сигналов входа.
б) Цикловая торговля:    BP-фильтр для выделения 14-дневного цикла + SMA для подтверждения.
с) ? Арбитраж:                BS-фильтр для подавления рыночного шума + EMA для анализа тренда.

Для тестирования в стратегии планирую сравнивать:
1) Задержку сигналов;
2) Количество ложных срабатываний;
3) Ну и можно рассчитывать соотношение Sharpe до/после оптимизации.
Но для этого нужна торговая стратегия, но это уже совсем другая тема.  :wink:  

Тема фильтрации обширна, пишите свои идеи будем разбираться вместе.
 
Идея сглаживания - это борьба с выбросами.  Как только Вы начинаете бороться с запаздыванием, то сразу возникает вопрос: а зачем тогда сглаживать? Тогда лучший - это просто сам график. Запаздывания нет.
Ну и прежде чем браться за идею, стоит понять к чему приводит сглаживание. Это хорошо видно при преобразовании Фурье. Вот здесь очень наглядно про это https://rutube.ru/video/beeb00abb33061f14a37f54d3536a10b/

Т.е. если браться за фильтрацию сигнала, то сначала необходимо определиться для чего.
 
Nikolay,  Отличное видео, прекрасная демонстрация, автору и Nikolay, - огромное спасибо за популяризирование и просвещение.
К видео только одно замечание, преобразование Фурье вносит тоже запаздывание и его тоже нужно учитывать. У себя я просто держу напоминалочку, типа

Описание методов фильтрации в индикаторе Swiss Army Knife (John Ehlers):
1. EMA (Exponential Moving Average)
- Тип: Однополюсный фильтр низких частот (ФНЧ).
- Формула:  Output = a * Price + (1 - a) * Previous_Output
- Применение:  Сглаживание ценовых данных, подавление высокочастотного шума.  
 - Подходит для трендовых рынков.  
 - Используется для определения направления тренда.  
 - Пример: Выявление долгосрочных тенденций на дневных графиках.

2. SMA (Simple Moving Average)**
- Тип: Равновесный ФНЧ.  
- Формула:  Output = (Price + Price[1] + ... + Price[n]) / (n + 1)
- Применение:    Устранение рыночного шума с линейным сглаживанием.  
 - Идеален для фильтрации "белого шума".  
 - Используется в стратегиях пересечения средних.  
 - Пример: Сигналы при пересечении 50- и 200-периодной SMA.
....

Условно тех. анализ делят на две основные группы.
▪ Графический анализ: Поддержка и сопротивление, Модели разворота и продолжения, Свечной анализ;
▪ Индикаторный анализ: Индикаторы тренда (сигналы продолжения), Осцилляторы (сигналы разворота), Анализ объема (дополнительные фильтры).

Я только сейчас рассуждаю про Индикаторный анализ, так как это просто математика, в рамках одной широко распространённой стратегии ADX RSI (в рамках 60% инвестиционного дохода).
Для реальной торговли конечно нужен Графический анализ, у себя еще прикручиваю Анализ реального времени, но сейчас я не про это.
Задачу ставлю разобраться и показать,  что давно забытые стратегии прекрасно работают, в современных условиях.

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

И последнее, просто напомню, что обратная величина частоте, это тот самый период, который мы просто можем адаптировать, с помощь математики. А значит и фильтры применять с этими периодами каждый по назначению.
 
Цитата
VPM написал:
И последнее, просто напомню, что обратная величина частоте, это тот самый период, который мы просто можем адаптировать, с помощь математики. А значит и фильтры применять с этими периодами каждый по назначению.
Это Вы может делать только если данные независимы. А если окно скользящее, с зависимостью, что изменяя "на лету" окно ничего хорошего ожидать не стоит.
 
Не понял, поясните?
 
Например ema - фильтр, где используется прошлое значение, полученное на текущем окне. Хотя да, это уже строго говоря не скользящее окно.
На скользящем окне Вы каждый раз рассчитываете результат по данным этого окна, не смотря дальше. Но с другой стороны, если окно изменить, то можно получить резкий скачок в данных. Было окно 100, стало 10. Результат уже явно другой. Т.е. цель изменения окна - это изменить работу фильтра для всего сигнала. А если изменять его туда-обратно, то как такой сигнал потом интерпретировать.

В этом плане самый простой и понятный фильтр для финансовых данных - это WVAP. Есть веса от объема. Его можно даже доработать, добавив веса от позиции данных в окне выборки, снижая вес дальних индексов в окне.
А просто фильтры основанные на математике из стационарных рядов - ещё надо объяснить почему это должно работать на финансовых данных.
 
Согласен, проблема тут есть, но ведь и задача  при определении тренда стоит выделить несущею частоту, а значит незначительные изменения в значениях периода. А что смущает в использовании фильтра или индикатора, на мой взгляд так наиболее информативный подход, при графическом анализе все равно сохраняется не кая интуитивность. А в индикаторном поймал тренд так и сиди в нем, мне думается что много ошибок именно в применении. Еще один момент в рассуждениях о ценовых рядах, часто умалчивают, что сама экономика построена так что капитал дисконтируется, а активы дорожают. А что объем, посмотри те какие дисбалансы и гэпы (про срочный рынок). WaPrice подкачиваю посматриваю, очень часто дневная свеча меняет на переходах свой цвет. Насчет использования индикаторов, так а что тут объяснять, на мой взгляд все предельно просто, волновая структура применима ко всему, отображение цены на графике колебательный процесс, значить имеем полное право использовать амплитудно-частотные преобразования. Доказательством правомерности может служить мат. ожидание системы.
 
Странное определение тренда через частоту. Раз частота, значит колебательные движения. А если тренд, то какие тогда колебания. Тренд - это линейная зависимость.
 
Нет здесь странностей. просто ставим все на свои места.
1) Колебательные движения значит частота или волновой процесс. Поведение цены можно представить как сумму волн разной частоты и амплитуды (гармоники).
2) С точки зрения технического анализа, Тренд — это направленное движение цены (вверх или вниз). Он часто выглядит как линейная зависимость. Внутри тренда происходят колебательные (волатильные) движения: импульсы, откаты, коррекции.

Кстати у Вас есть прекрасный индикатор регрессионного анализа, выделяющий тренд 3 видов с использованием волатильности. Я его активно использую, пользуясь случаем хочу Вас попросить посмотреть его затирает текущие значения.

Наглядный пример моего подхода, как модели тренда, это синусоида, если взять от  от мах до минимума и наоборот, чем не трендовое движении. функция распределения плотности в экстремальных диапазонах имеет максимальные значения, вот уже и Вайкофф появился с зонами распределения и накопления. Кстати функция распределения плотности цены на длительном интервале больше похожа как у синусоиды.
 
Да, если есть колебательный процесс, то есть соблазн представить поступательные движения тренда как фазы волны с большим периодом. А внутренние колебания (по сути шум) как гармоники.
Эта идея не нова, а у же с середины 90-х заезжена вдоль и поперек. Помню как радиофизики тогда с придыханием говорили, что вот сейчас придём и научим всех как надо.
Доля смысла есть в этом подходе, но только пока процесс не изменится. И сразу всё ломается, т.к. цена не обязана идти по ряду Фурье. Если бы временной ценовой ряд можно было представить аналитически, то, наверно, это уже давно бы сделали. Так что да, такой подход возможен, но тогда необходимо постоянно пересчитывать модель.
Цитата
VPM написал:
Кстати у Вас есть прекрасный индикатор регрессионного анализа, выделяющий тренд 3 видов с использованием волатильности. Я его активно использую, пользуясь случаем хочу Вас попросить посмотреть его затирает текущие значения.
Я не понял смысл этой фразы, сути проблемы.
 
Nikolay,  Индикатор Reg() при появлении нового индекса рассчитывает значение и выводит на график, А между сменой индексов, при дёргании функции обратного вызова, он удаляет с графика значения, На больших интервалах допустим на часовом моргнула и сразу затерла, то есть целый час нет визуализации значения на текущей свече, В идеале конечно, чтоб еще в прогнозную зону отрисовывал линии, Я тему с прогнозной зоной поднимал, но она интереса не вызвала.
 
Нет, такого нет в этом индикаторе. Если приходит тот же индекс, где уже был расчёт, то происходит возврат уже рассчитанных значений.

if calculated_buffer[index] ~= nil then
 
Я пользуюсь этой версией, посмотрел у Вас уже ее и нет.
Код
--logfile=io.open("C:\\SBERBANK\\QUIK_SMS\\LuaIndicators\\qlua_log.txt", "w")

Settings = {Name = "*iReg",
      bars = 182,
      kstd=2,
      degree = 3, -- 1 linear, 2 parabolic, 3 third-power 
      barsshift=0
   }
-- Пользовательcкие функции
function WriteLog(text)

   logfile:write(tostring(os.date("%c",os.time())).." "..text.."\n")
   logfile:flush()
   LASTLOGSTRING = text

end
----------------------------------------------------------
----------------------------------------------------------
----------------------------------------------------------
function Reg()
            
   local sql_buffer={}
    local sqh_buffer={}
    local fx_buffer={}
   local sx={}
   local calculated_buffer={}
           
    return function(ind, Fsettings)
      
      local Fsettings=(Fsettings or {})
      local index = ind
      local bars = Fsettings.bars or 182
      local kstd = Fsettings.kstd or 2
      local barsshift = Fsettings.barsshift or 0
      local degree = Fsettings.degree or 1
      local index = ind

      local out1 = nil
      local out2 = nil
      local out3 = nil
      
      local p = 0
      local n = 0
      local f = 0
      local qq = 0
      local mm = 0
      local tt = 0
      local ii = 0
      local jj = 0
      local kk = 0
      local ll = 0
      local nn = 0
      local sq = 0
      local i0 = 0
      
      local mi = 0
       local ai={{1,2,3,4}, {1,2,3,4}, {1,2,3,4}, {1,2,3,4}}      
      local b={}
      local x={}
      
      p = bars 
      nn = degree+1
 
      if index == 1 then
         sql_buffer = {}
         sqh_buffer = {}
         fx_buffer = {}
         calculated_buffer = {}
         
         sql_buffer[index]= 0
         sqh_buffer[index]= 0
         fx_buffer[index]= 0

         --- sx 
         sx={}
         sx[1] = p+1
         
         for mi=1, nn*2-2 do
            sum=0
            for n=i0, i0+p do
               sum = sum + math.pow(n,mi)
            end
         sx[mi+1]=sum
         end
         
         return nil
      end
            
      sql_buffer[index] = sql_buffer[index-1]   
      sqh_buffer[index] = sqh_buffer[index-1]   
      fx_buffer[index] = fx_buffer[index-1]
       
      out1 = fx_buffer[bars]
      out2 = sqh_buffer[bars]
      out3 = sql_buffer[bars]

      SetValue(index-bars-barsshift, 1, nil)
        SetValue(index-bars-barsshift, 2, nil)
        SetValue(index-bars-barsshift, 3, nil)
       
      if not CandleExist(index) or index <= bars then
         return nil
      end
        if index < (Size() - barsshift) then return nil end
      if index > (Size() - barsshift) then return nil end
        if calculated_buffer[index] ~= nil then return out1, out2, out3 end
      
       
      --- syx 
      for mi=1, nn do
         sum = 0
         for n=i0, i0+p do
            if CandleExist(index+n-bars) then
               if mi==1 then
                  sum = sum + C(index+n-bars)
               else
                  sum = sum + C(index+n-bars)*math.pow(n,mi-1)
               end
            end
         end
      b[mi]=sum
      end
          
      --- Matrix 
      for jj=1, nn do
         for ii=1, nn do
            kk=ii+jj-1
            ai[ii][jj]=sx[kk]
         end
      end
          
      --- Gauss 
      for kk=1, nn-1 do
         ll=0
         mm=0
         for ii=kk, nn do
            if math.abs(ai[ii][kk])>mm then
               mm=math.abs(ai[ii][kk])
               ll=ii
            end
         end
            
         if ll==0 then
            return nil
         end
         if ll~=kk then

            for jj=1, nn do
               tt=ai[kk][jj]
               ai[kk][jj]=ai[ll][jj]
               ai[ll][jj]=tt
            end
            tt=b[kk]
            b[kk]=b[ll]
            b[ll]=tt
         end
         for ii=kk+1, nn do
            qq=ai[ii][kk]/ai[kk][kk]
            for jj=1, nn do
               if jj==kk then
                  ai[ii][jj]=0
               else
                  ai[ii][jj]=ai[ii][jj]-qq*ai[kk][jj]
               end
            end
            b[ii]=b[ii]-qq*b[kk]
         end
      end
         
       x[nn]=b[nn]/ai[nn][nn]
         
      for ii=nn-1, 1, -1 do
         tt=0
         for jj=1, nn-ii do
            tt=tt+ai[ii][ii+jj]*x[ii+jj]
            x[ii]=(1/ai[ii][ii])*(b[ii]-tt)
         end
      end
         
      ---
      for n=i0, i0+p do
         sum=0
         for kk=1, degree do
            sum = sum + x[kk+1]*math.pow(n,kk)
         end
         fx_buffer[n]=x[1]+sum
            SetValue(index+n-bars, 1, fx_buffer[n])
      end
          
      --- Std 
      sq=0.0
      for n=i0, i0+p do
         if CandleExist(index+n-bars) then
            sq = sq + math.pow(C(index+n-bars)-fx_buffer[n],2)
         end
      end
         
      sq = math.sqrt(sq/(p+1))*kstd

      for n=i0, i0+p do
         sqh_buffer[n]=fx_buffer[n]+sq
         sql_buffer[n]=fx_buffer[n]-sq
            SetValue(index+n-bars, 2, sqh_buffer[n])
            SetValue(index+n-bars, 3, sql_buffer[n])
      end
                  
      SetValue(index-bars, 1, nil)
        SetValue(index-bars, 2, nil)
        SetValue(index-bars, 3, nil)
      
      calculated_buffer[index] = true
      out1 = fx_buffer[bars]
      out2 = sqh_buffer[bars]
      out3 = sql_buffer[bars]
      
      return out1, out2, out3
   
   end
   
end
----------------------------    ----------------------------    ----------------------------
----------------------------    ----------------------------    ----------------------------
----------------------------    ----------------------------    ----------------------------
function FindExistCandle(I)

   local out = I
   
   while not CandleExist(out) and out > 0 do
      out = out -1
   end   
   
   return out
 
end

local myfunc
function Init()
   myfunc = Reg()
   Settings.line=
         {
            {
               Name = "iReg",
               Color = RGB(0, 0, 255),
               Type = TYPE_LINE,
               Width = 2
            },
            {
               Name = "+iReg",
               Color = RGB(0, 128, 0),
               Type = TYPE_LINE,
               Width = 2
            },
            {
               Name = "-iReg",
               Color = RGB(192, 0, 0),
               Type = TYPE_LINE,
               Width = 2
            }
         }
   return #Settings.line
 end
 
function OnCalculate(index)
   
   --WriteLog ("OnCalc() ".."CandleExist("..index.."): "..tostring(CandleExist(index)))

   if Settings.degree > 3 then
      return nil
   end
   
   return myfunc(index, Settings)
 end
 
Ну это очень древний вариант.

Надо тогда сдвинуть очистку данных ниже проверок.

SetValue(index-bars-barsshift, 1, nil)
 
Древний не значит ненадежный! Спасибо, разобрался исходную версию, перевел на луа 5.4, оказывается все отрисовывает, видимо была какая то моя уже модернизация. Отличный индикатор!
Страницы: Пред. 1 ... 3 4 5 6 7
Читают тему
Наверх