Блог им. kurd
Settings = { Name = "_Zigzag" ,Delta = 0.0 -- Абсолютная сила тренда в пунктах ,Rate = 0.001 -- Относительная сила тренда ,Log = "D:\\Zigzag.csv" -- лог-файл сделок ,line = { {Name = "Zigzag" ,Color = RGB(255,255,0) -- Жёлтый ,Type = TYPE_LINE ,Width = 1} ,{Name = "Lwr" ,Color = RGB (255,255,0) -- Жёлтый ,Type = TYPE_TRIANGLE_DOWN ,Width = 1} ,{Name = "Upr" ,Color = RGB (0,128,255) -- Тёмно-Голубой ,Type = TYPE_TRIANGLE_UP ,Width = 1} } -- BadConditions, CurSize, ClosePrev = nil } -- DataSourceInfo, Xtrs, DummyXtr, ScanNo = nil function Msg() return Title() .." - параметры:" .."\nDelta - абсолютная сила тренда или 0;" .."\nRate - относительная сила тренда или 0." .."\nLog - лог-файл сделок на поворотах." .."\nСила - минимальный уход от экстремума" .."\n для смены направления тренда." end --------- function AddXtr (bar) -- bar > #Xtrs[n].FinIdx -- Код возврата: 0 - ничего не изменилось; -- ±2 - замена последнего экстремума более сильным; -- ±3 - добавление экстремума, противоположного. local node = Xtrs[#Xtrs] local xtr = node.FinVal if Trend() > 0 then local mn = Lwr (xtr) if L(bar) <= mn then node = NewNode (bar, L(bar)) node.IniVal = math.min (mn, O(bar)) table.insert (Xtrs, node) return -3 end if H(bar) >= node.FinVal then node.FinIdx = bar node.FinVal = H(bar) return 2 end else -- Trend() < 0 local mx = Upr (xtr) if H(bar) >= mx then node = NewNode (bar, H(bar)) node.IniVal = math.max (mx, O(bar)) table.insert (Xtrs, node) return 3 end if L(bar) <= node.FinVal then node.FinIdx = bar node.FinVal = L(bar) return -2 end end -- if Trend() > 0 return 0 end -- AddXtr() function DateAndTime (i) -- в баре котировок return DataSourceInfo and DataSourceInfo.interval < 0 and string.format ("%04d.%02d.%02d", T(i).year, T(i).month, T(i).day) or string.format ("%04d.%02d.%02d %02d:%02d" ,T(i).year, T(i).month, T(i).day, T(i).hour, T(i).min) end function Lwr (val) return Settings.Delta > 0 and val - Settings.Delta or val * (1 - Settings.Rate) end function MakeDummy() -- Вместо нового экстремума или усиления старого local dummyXtr = NewNode ( Size(), C(Size())) SetValue (Size(), 1, C(Size())) local finVal = Xtrs[#Xtrs].FinVal -- IniVal - будущий поворот dummyXtr.IniVal = Trend() > 0 and Lwr (finVal) or Upr (finVal) SetValue (Size(), Trend() > 0 and 2 or 3, dummyXtr.IniVal) return dummyXtr end function NewNode (bar, val) return { IniIdx = bar, IniVal = val, FinIdx = bar, FinVal = val } end function Title() return getDataSourceInfo().sec_code .."[".. Settings.Name .."]" end function ToString (no) -- параметры узла Зигзага if not no then no = #Xtrs end return "Xtrs[".. no .."]" .."\nIni ".. DateAndTime (Xtrs[no].IniIdx) .." ".. Xtrs[no].IniVal .."\nFin ".. DateAndTime (Xtrs[no].FinIdx) .." ".. Xtrs[no].FinVal end function Trend (idx) idx = idx or #Xtrs return Xtrs[idx].IniVal > Xtrs[idx-1].FinVal and 1 or -1 end function Upr (val) return Settings.Delta > 0 and val + Settings.Delta or val * (1 + Settings.Rate) end ------------ function Init() message (Msg()) return #Settings.line end function OnCalculate (index) if BadConditions then return nil end if index == 1 then ScanNo = not ScanNo and 1 or ScanNo + 1 if not Sub1() then -- BadConditions, CurSize, Xtrs, return nil -- DummyXtr, DataSourceInfo end elseif C(index) == ClosePrev then elseif index >= CurSize then Sub2() end ClosePrev = C(index) return GetValue (index, 1), GetValue (index, 2), GetValue (index, 3) end -- OnCalculate() function OnChangeSettings() BadConditions, ClosePrev, DataSourceInfo, ScanNo = nil if Settings.Delta > 0 and Settings.Rate > 0 or Settings.Delta <= 0 and Settings.Rate <= 0 then BadConditions = true message (Msg()) end end function Sub1() BadConditions = true CurSize = Size() for i = 1, 3 do SetRangeValue (i, 1, CurSize, nil) end local validIdx = 1 while validIdx <= CurSize and not CandleExist (validIdx) do validIdx = validIdx + 1 end if validIdx >= CurSize then message (Title() ..": мало данных 1.") return false end local cur = {} cur.Hi = H(validIdx); cur.Lo = L(validIdx) cur.Mx = Upr (cur.Hi); cur.Mn = Lwr (cur.Lo) local firstRegularIdx local bar = validIdx + 1 while bar <= CurSize do while not CandleExist (bar) or H(bar) >= cur.Hi and L(bar) <= cur.Lo or H(bar) < cur.Hi and L(bar) > cur.Lo do if CandleExist (bar) then cur.Hi = H(bar); cur.Lo = L(bar) cur.Mx = math.max (cur.Mx, cur.Hi) cur.Mn = math.min (cur.Mn, cur.Lo) end bar = bar + 1 if bar > CurSize then message (Title() ..": мало данных 2.") return false end end -- while not H(bar) or not L(bar) Xtrs = {} if H(bar) > cur.Mx then table.insert (Xtrs, NewNode (validIdx, H(validIdx))) table.insert (Xtrs, NewNode (bar, H(bar))) firstRegularIdx = bar + 1 break elseif L(bar) < cur.Mn then table.insert (Xtrs, NewNode (validIdx, L(validIdx))) table.insert (Xtrs, NewNode (bar, L(bar))) firstRegularIdx = bar + 1 break end bar = bar + 1 end -- while bar <= CurSize if not firstRegularIdx then message (Title() ..": мало данных 3.") return false end BadConditions = false for bar = firstRegularIdx, CurSize do if CandleExist (bar) then AddXtr (bar) end end DataSourceInfo = getDataSourceInfo () local logFile = ScanNo == 1 and io.open (Settings.Log, "w") or nil if logFile then local fmt = DataSourceInfo and DataSourceInfo.interval < 0 and "%-10s; %-10s; %-10s; %-10s; %-8s; %-10s\n" or "%-16s; %-10s; %-16s; %-10s; %-10s; %-12s\n" logFile:write (string.format (fmt ,"nDateTime", "nPrice", "xDateTime", "xPrice", "profit", "equity")) end local ttl, n, d0, p0, d1, p1 = 0, #Xtrs for i = 1, n do SetValue (Xtrs[i].FinIdx, 1, Xtrs[i].FinVal) if i > 2 then d1 = DateAndTime (Xtrs[i].IniIdx) if Trend(i) < 0 then p1 = Xtrs[i].IniVal; SetValue (Xtrs[i].IniIdx, 2, p1) else p1 = Xtrs[i].IniVal SetValue (Xtrs[i].IniIdx, 3, p1); p1 = -p1 end if i > 3 then ttl = ttl + p0 + p1 if logFile then logFile:write ( string.format ("%s; %10.2f; %10s; %10.2f; %10.2f; %12.2f\n" ,d0, p0, d1, p1, p0 + p1, ttl)) end end d0, p0 = d1, p1 end end -- for i = 1, n if logFile then logFile:close() end local s = Title() .."\nttl ".. string.format ("%.2f", ttl) .."\n".. ToString() local n1, n2, n3 = Xtrs[#Xtrs-2], Xtrs[#Xtrs-1], Xtrs[#Xtrs] Xtrs = {}; Xtrs[1], Xtrs[2], Xtrs[3] = n1, n2, n3 DummyXtr = CurSize > n3.FinIdx and MakeDummy() or nil if ScanNo == 1 then message (s .."\nDummyXtr ".. (DummyXtr and DateAndTime (DummyXtr.FinIdx) or "not-not")) end return true end -- Sub1() function Sub2() if DummyXtr then SetValue (DummyXtr.FinIdx, 1, nil) SetValue (DummyXtr.IniIdx, Trend() > 0 and 2 or 3, nil) DummyXtr = nil end local n = #Xtrs SetValue (Xtrs[n].FinIdx, 1, nil) SetValue (Xtrs[n].IniIdx, Trend() < 0 and 2 or 3, nil) table.remove (Xtrs) CurSize = Xtrs[#Xtrs].FinIdx while CurSize < Size() do CurSize = CurSize + 1 AddXtr (CurSize) end for k = n, #Xtrs do local node = Xtrs[k] SetValue (node.FinIdx, 1, node.FinVal) SetValue (node.IniIdx, Trend(k) < 0 and 2 or 3, node.IniVal) end if Xtrs[#Xtrs].FinIdx < Size() then DummyXtr = MakeDummy() end end -- Sub2()
А объективно, он не лучше и не хуже стандартных скользяшек. Сам по себе не работает, нуждается в дополнительной обвязке, чтобы получить систему.
— Вы совершенно заблуждаетесь с этим выводом…
Ещё в 90 было много вариантов построения этого индикатора и попыток формализовать системы торговли на основе его… Простых решений, позволяющих получить нормальную статистику на выходе нет..
О некоторых вопросах по этому индикатору написано выше…