Отображение на графике индикатора из другого графика

Автор записи: Sergey
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 7, среднее: 5,00 из 5)
Загрузка...

Понадобилось мне видеть на 5-и минутном графике индикатор из другого окна. Вот написал свой индикатор, который загружает данные из любого графика, беря его данные по уникальному идентификатору в QUIK.

Чтобы этот индикатор смог найти искомый индикатор, зайдите в свойства этого индикатора, перейдите на закладку Дополнительно, и в поле Идентификатор укажите уникальное имя этого индикатора. В моем случае это "B4H_20_2" (без кавычек).

Сам файл кода нужно положить в папку QUIK, в поддиректорию "LuaIndicators". Если его нет, то создайте.  После этого при добавлении нового индикатора вы увидите его в общем списке.

Вот код, у меня он назван BBfromOtherPeriod_common.lua :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
-- по умолчанию берет значения болинов из графика 4 часа
-- график должен называться "B_20_2" (в настройках исходного индикатора нужно зайти в поле дополнительно и там указать имя индикатора)
 
-- для получения данных с других графиков, можно создать вызывающий файл из 4х строк в коротом
-- присвоить начальные параметры
-- ======= начало файла (строки надо раскоментировать) ==========
-- Color = RGB(255, 128, 64) -- оранжевый цвет
-- Width = 3
-- NameAndSource = "B_20_2"
-- и вызовом главного
-- dofile (getWorkingFolder().."\\LuaIndicators\\BBfromOtherPeriod_common.lua")
-- ======= конец файла ==========
 
if Color == nil then
   Color = RGB(255, 128, 64) -- оранжевый
end
if Width == nil then
   Width = 3
end
if NameAndSource == nil then
   NameAndSource = "B4H_20_2"
end
 
Settings = {
   Name = NameAndSource,
   line = {{
         Name = NameAndSource.."_c",
         Type = TYPE_LINE,
         Color = Color,
         Width = Width
      },
      {
         Name = NameAndSource.."_h",
         Type = TYPE_LINE,
         Color = Color,
         Width = Width
      },
      {
         Name = NameAndSource.."_l",
         Type = TYPE_LINE,
         Color = Color,
         Width = Width
      }
   }
}
 
function datetimeToSec2(datetime)
   return datetime.year*31104000 + (datetime.month-1)*2592000 + (datetime.day-1) * 86400 + datetime.hour * 3600 + datetime.min * 60
end
 
function toYYYY_MM_DD(DateTime,OtkudaZapusk)
   if type(DateTime) ~= 'table' then
      message("в функцию toYYYY_MM_DD передано неверно значение даты "..tostring(DateTime).. " / "..tostring(OtkudaZapusk))
      return ""
   else
      if otladka_toYYYY_MM_DD then message("toYYYY_MM_DD из ",OtkudaZapusk) end
      local Res = tostring(DateTime.year);
      Res = Res.."/"
      local month = tostring(DateTime.month);
      if #month == 1 then Res = Res.."0"..month; else Res = Res..month; end;
      Res = Res.."/"
      local day = tostring(DateTime.day);
      if #day == 1 then Res = Res.."0"..day; else Res = Res..day; end;
      return Res;
   end
end --toYYYY_MM_DD
 
function toHH_MM(DateTime)
   if type(DateTime) ~= 'table' then
      message("в функцию toHH_MM передано неверно значение даты "..tostring(DateTime))
      return ""
   else
      local Res = ""
      local hour = tostring(DateTime.hour)
      if #hour == 1 then Res = Res.."0"..hour; else Res = Res..hour; end
      Res = Res..":"
      local minute = tostring(DateTime.min)
      if #minute == 1 then Res = Res.."0"..minute; else Res = Res..minute; end
      return Res
   end
end
 
function toYYYY_MM_DD_HH_MM(DateTime)
   return toYYYY_MM_DD(DateTime).." "..toHH_MM(DateTime)
end
 
function SavePeremToFile (name, znach) -- возвращает массив всех данных
   local Lines = {}
 
   local level = 0
   local function Rec(a)
      local first = true
      level = level + 1
      local s = '' for i=1,level do s = ' '..s end
      for key, val in pairs(a) do
         if not first then Lines[#Lines] = Lines[#Lines]..',' end
         local k = '[\''..key..'\']'
         if type(key) == 'number' then k = '['..key..']' end
         if type(val) ~= 'table' then
            if type(val) == 'string' then
               val = '\''..val..'\''
            else
               val = tostring(val)
            end
            table.insert(Lines, s..k..'='..val)
            first = false
         else
            table.insert(Lines, s..k..'={')
            first = false
            Rec(val)
            table.insert(Lines, s..'}')
            level = level - 1
         end
      end
   end
 
   -- message("type(znach)="..tostring(type(znach)))
   -- если параметр текстовый, но можно преобразовать в число, то преобразует в число
   if type(znach) == "string" then
      local znach_tmp = tonumber(znach)
      if znach_tmp ~= nil then
         znach = znach_tmp
      end
   end
 
   if type(znach) == "string" then
      table.insert(Lines, name ..' = \"'..znach.."\"")
   elseif type(znach) == "table" then
      -- Lines = TableToArray(znach)
      table.insert(Lines, name.." = {")
      Rec(znach)
      table.insert(Lines, '}')
   else
      table.insert(Lines, name ..' = '..tostring(znach))
   end
 
   local f = io.open(getScriptPath()..'\\params'..NameAndSource, 'w')
   for i=1,#Lines do
      f:write(Lines[i]..'\n')
      f:flush()
   end
   f:close()
   return Lines
end --SavePeremToFile
 
function LoadPeremFromFile ()
   local FPath = getScriptPath()..'\\params'..NameAndSource
   local func, err = loadfile(FPath)
   -- message("err="..tostring(err))
   -- если файл нормально прочитан
   if err == nil then
      if not func then
         message('Ошибка загрузки таблицы из файла: '..err)
         return nil
      else
         return func()
      end
   -- если ошибка чтения из файла
   else
      message("LoadPeremFromFile: не найден файл "..FPath)
   end
end --LoadPeremFromFile
 
function Init()
   message ("Init индикатор "..Settings.Name)
   local source = Settings.Name
   local B_size_now = getNumCandles(source)
   B_20_c, B_20_max_n, l = getCandlesByIndex (source, 0, 0, B_size_now);
   if B_20_max_n == nil or B_20_max_n == 0 then
      message ("Не найден график с меткой, из которого надо брать данные: "..source)
      return
   else
      message ("Подключен к крафику с меткой: "..source)
      message("Есть данные "..tostring(B_20_max_n).." свечей")
      return #Settings.line
   end
end
 
function OnCalculate(index)
   -- if index > 3000 then
   -- if index > 2500 then
   local loking_time = T(index)
   local seconds_which_loking = datetimeToSec2(loking_time)
   local source = Settings.Name
   local B_size_now = getNumCandles(source)
   local B_20_2_h, B_20_max_n, l = getCandlesByIndex (source, 1, 0, B_size_now);
   local B_20_2_l, B_20_max_n, l = getCandlesByIndex (source, 2, 0, B_size_now);
   local B_20_c, B_20_max_n, l = getCandlesByIndex (source, 0, 0, B_size_now);
   local B_20_max_n = B_20_max_n-1
   -- message("при index="..index.." ищем "..tostring(toYYYY_MM_DD_HH_MM(loking_time)))
   -- message("B_20_max_n="..tostring(B_20_max_n))
   -- message(" B_20_c[0]="..toYYYY_MM_DD_HH_MM(B_20_c[0].datetime))
   -- message(" B_20_c[1]="..toYYYY_MM_DD_HH_MM(B_20_c[1].datetime))
   -- message("B_20_c["..B_20_max_n.."]="..toYYYY_MM_DD_HH_MM(B_20_c[B_20_max_n].datetime))
   -- LoadPeremFromFile ()
 
   -- message("finded_interval перед поиском с прошлого раза ="..tostring(finded_interval))
   if finded_interval ~= nil then
      n = finded_interval
      -- если пересекли начало следующего большого интервала, то передвигаем вперед на него
      if seconds_of_next_interval <= seconds_which_loking and finded_interval < B_20_max_n then
         n = finded_interval + 1
      else
         n = finded_interval
      end
   else
      n = B_20_max_n
   end
 
   while n >= 0 and datetimeToSec2(B_20_c[n].datetime) > seconds_which_loking do
      -- message("пропустил B_20_c["..n.."]="..toYYYY_MM_DD_HH_MM(B_20_c[n].datetime).." т.к. ищу"..seconds_which_loking.." а сейчас "..datetimeToSec2(B_20_c[n].datetime))
      n = n - 1
   end
   finded_interval = n
   if finded_interval < B_20_max_n then
      seconds_of_next_interval = datetimeToSec2(B_20_c[finded_interval+1].datetime)
   end
 
   -- message("при index="..index.." ищем "..tostring(toYYYY_MM_DD_HH_MM(loking_time)).." найден B_20_c["..finded_interval.."]="..toYYYY_MM_DD_HH_MM(B_20_c[finded_interval].datetime).." знач."..tostring(B_20_c[finded_interval].open))
   return B_20_c[finded_interval].open, B_20_2_h[finded_interval].open, B_20_2_l[finded_interval].open
   -- else
   -- return nil, nil, nil
   -- end
end

Добавить комментарий

Отображение на графике индикатора из другого графика: 15 комментариев

  1. Не удалось запустить данный индикатор, пишет поток ошибок:
    ---------------------------------------------------------------------------------------------------------------------------
    Init индикатор B4H_20_2
    Подключен к графику с меткой: B4H_20_2
    Есть данные 3174 свечей
    C:\Quik\LuaIndicators\BBfromOtherPeriod_common.lua:220: attempt to index field '?' (a nil value)
    C:\Quik\LuaIndicators\BBfromOtherPeriod_common.lua:220: attempt to index field '?' (a nil value)
    C:\Quik\LuaIndicators\BBfromOtherPeriod_common.lua:220: attempt to index field '?' (a nil value)…..
    ------------------------------------------------------------------------------------------------------------------------------------
    1. Данный индикатор привязан только к определённому таймфрейму 4 часа и 5 минут?
    2. Индикатор «BBfromOtherPeriod_common» дублирует любой индикатор на любом таймфрейме? – в размещённом коде.

    1. Так понимаю Sergey редко посещает данный ресурс.

      Обращаюсь к администратору Дмитрию (Admin) - можно получить комментарий по данной ошибке индикатора. Понимаю это не ваша разработка, но если дадите комментарий по проблеме, буду благодарен.

  2. Попробовал построить график по данным графика из другого окна с помощью коротенького кода:
    [Settings= { Name = "*** Stocs-MICEX", period = 5, line = { { Name = "MA", Color = RGB(0, 255, 0), Type = TYPE_LINE, Width = 1 } } } function Init() return 1 end

    function OnCalculate(index)
    local NumberOfGZ=getNumCandles("GZ")
    SumOfGZ = 0
    local GZ,n,i = getCandlesByIndex ("GZ", 0, NumberOfGZ-2, 1);-- получаем одну (предпоследнюю) свечу в таблицу GZ
    if GZ ~= nil then
    SumOfGZ = (GZ[0].close)
    end
    return SumOfGZ
    end]
    В результате получил горизонтальную линию. Подскажите, пожалуйста, в чем ошибка.

    1. С тех пор, я сильно доработал индикатор, он теперь работает значительно быстрее.

      К тому же добавил индикатор и для MA

      Выложил все целиком одним архивом:

      http://www.denegin.ru/files/BBandMAfromOtherPeriod.zip

      там две папки
      indik-bolinger-band
      LuaIndicators

      с LuaIndicators понятно что сделать - в ней набор всех маленьких файлов, которые содержат настройки под разные таймфреймы.
      А папку indik-bolinger-band положите где-нибудь вне папки LuaIndicators , и пропишите к ней путь в файлах папки LuaIndicators

      Еще одно изменение, чтобы в одном квике можно было "подгружать" графики разных ценных бумаг, теперь идентификатор искомого графика должен выглядеть в таком виде:
      RI_XXXX
      где RI первые две буквы кода бумаги. а ХХХХ это идентификатор графика с бОльшим таймфреймом, который хотите потом импортировать.
      В файлах, которые лежат в папке LuaIndicators не надо добавлять RI_ перед названием индикатора.
      При загрузке индикатора он сам добавит RI_ исходя из того, на графике какой бумаги вы строите индикатор.

      Надеюсь не очень запутал )

      1. Спасибо за комментарий.
        Вроде разобрался, индикаторы-дублёры в данных примерах настроены только на индикаторы «Bollinger Band» и «МА».
        Составил мини инструкцию в картинках для понимания:
        Пример: настройки отображения индикатора "Bollinger Band" график RIZ6- 60 мин. на графике RIZ6 - 15 мин.
        1. QUIK установлен на диске C:\QUIK;
        2. Скачиваем файлы индикатора в папке «BBandMAfromOtherPeriod»;
        3. Копируем папку «indik-bolinger-band» в папку C:\QUIK получается путь папки C:\QUIK\ indik-bolinger-band;
        4. Копируем выбранный индикатор B1H_20_15 из загруженной папки BBandMAfromOtherPeriod\LuaIndicators в папку C:\QUIK\LuaIndicators
        5. Редактируем индикатор B1H_20_15 переписываем путь:

        1
        
         dofile (getWorkingFolder().."\\indik-bolinger-band\\BBfromOtherPeriod.lua")

        Изображение:

        6. Прописываем идентификатор RI_B1H_20_15 индикатора "Bollinger Band" на графике 60 мин.. Открываем окно «Добавить индикатор» на графике 15 мин. , из списка выбираем появившийся индикатор B1H_20_15 , настраиваем параметры линий и цвета, сохраняем, пример на картинке:
        Изображение:

      2. Вопросы:
        1. Задавая параметры в строке NameAndSource = "B1D_20_15", где параметры:

        B1D - таймфрейм графика отправителя данных;
        20 – что обозначает?;
        15 – таймфрейм графика получателя данных.

        B1D_20_1
        B1D_20_2
        B1D_20_3
        B1D_20_6
        B1D_20_10…и так далее, таким образом мы прописываем график отправитель и получатель данных?

        На графике получателе данных, можно устанавливать любой таймфрейм, но не больше чем на графике отправителя данных и данные индикатора-дублёра также будут отображаться.
        2. С меньшего таймфрейма на больший таймфрейм данные индикатора-дублёра тоже передаются, проверил, вроде работает.

        3. В системных сообщения отображается строка:
        LoadPeremFromFile: не найден файл C:\Quik\time_when_connect – что за файл должен быть?

        4. МА-индикатор-дублер «MA5_54», работает, также на Parabolic SAR отображает данные. Прописанные данные:

        NameAndSource = "MA5_54"
        МА5 - таймфрейм графика отправителя данных;
        54 - что обозначает?

        По данным параметрам вроде работает от 1 до 4 часа таймфрейме, дневку и выше не отображает линию. Прописывал "MAD_54" также другие параметры не помогло. Какие параметры необходимо прописывать для дневок и выше?

        5. Прописать под индикаторы Stochastic Oscillator возможно?

        1. Спасибо! Классная инструкция получилась!

          По вопросам:
          ------
          B1D - таймфрейм графика отправителя данных;
          20 – что обозначает?;
          15 – таймфрейм графика получателя данных.
          -----
          В целом не важно, как вы его назовете!
          Главное чтобы вы понимали, что это за график.
          Для себя я выработал маркировку:
          B1D - таймфрейм графика отправителя данных;
          20 – количество интервалов, по которому считается болинджер и средняя
          15 – второй параметр болинджера - отклонение от средней. 15 - это значит 1.5, а 2 - это значит 2
          Я просто использую два с отклонением 1.5 и 2

          ----------
          3. В системных сообщения отображается строка:
          LoadPeremFromFile: не найден файл C:\Quik\time_when_connect – что за файл должен быть?
          --------
          Это у меня небольшой пережито прошлого ) Суть в том, что было оно время, когда
          таких графиков настроено очень много, то во второй половине дня возникала следующая проблема, что квик при восстановлении связи с сервером начинал очень долго думать, и пока думал, снова терял связь с свервером, и потом по новой. Пришлось при коннекте (из другого робота) записывать переменную "когда подключились", и проверять, если с этого момента прошло меньше 30и секунд, то пропускать работу этого индикатора. Это давало квику хотя бы нормально подключиться, а потом можно было в окне зайти в редактирование индикаторов, и сразу его закрыть по кнопке "ОК", и он их перерисовывал.
          В версии квика 7.5 вроде такая проблема пропала.
          Чтобы всю эту надстройку отключить, можно смело удалить текст из файлов:
          BBfromOtherPeriod.lua
          MAfromOtherPeriod.lua
          -------- начало блока ---
          if LoadPeremFromFile (getWorkingFolder().."\\time_when_connect") == false then
          time_when_connect = GetTimeKomp("из AutoLogin")
          end
          local time_now = GetTimeKomp("из AutoLogin")
          -- если с момента соединения прошло меньше 30 секунд, то ничего не делает
          if time_now.seconds < time_when_connect.seconds + 30 then
          -- message(Settings.Name..": пропускаю load_all_data, т.к. с момента соединения не прошло 30 сек.")
          -- return false
          end
          --- конец блока

          ----------- вопрос --------
          4. МА-индикатор-дублер «MA5_54», работает, также на Parabolic SAR отображает данные. Прописанные данные:

          NameAndSource = "MA5_54"
          МА5 - таймфрейм графика отправителя данных;
          54 - что обозначает?
          ----------
          Аналогично Болинджеру, МА5 - таймфрейм, 54 - период расчета.

          По идее этому индикатору без разницы, что за индикатор ему загружать. Разница только в количестве линий. Т.е. для 3х линий, типа болинджера, нужно использовать BBfromOtherPeriod.lua
          Для индикаторов с одной линией, MAfromOtherPeriod.lua
          Для двух не делал, за ненадобностью, да и есть ли такие не знаю.

          Как уже писал, не важно как вы будете называть переменную NameAndSource в файлах, главное, чтобы они совпадали с идентификатором искомого индикатора.

            1. Спасибо, понятно, протестирую, разберусь с настройками.

              В программировании LUA плохо разбираюсь, могу только путь подправить:)))
              Если разметите код «SOfromOtherPeriod» для индикатора Stochastic Oscillator, там как раз две линии, буду благодарен.

              1. Вы прочитали мои мысли) решил написать универсальный индикатор, которому будет все равно, сколько линий в индикаторе, хоть 10 )

                Добавил файлы в тот же архив. Старые файлы сохранил в нем в папке old_version
                Так что все описанное выше для них. Уж очень красиво описано.

                В новой версии вместо двух файлов
                BBfromOtherPeriod.lua
                MAfromOtherPeriod.lua
                стал один файл
                IndikfromOtherPeriod.lua

                А в файлах, которые кладутся в папку LuaIndicators
                добавилось пара новых параметров:
                Interval = "15M"
                KolLines = 3
                Первый указывает период графика, который мы импортируем, варианты:
                "5М", "15М", "1H", "4h", "1D"
                А параметр KolLines обозначает, сколько линий он будет загружать из этого графика.

                1. - Вы писали: ( решил написать универсальный индикатор, которому будет все равно, сколько линий в индикаторе, хоть 10 )

                  Проверил возможность установить более 3-х линии для индикатора (в индикаторе Ichimoku («Ишимоку») 5 линий)
                  KolLines = 5
                  При установки более 3-х линий, индикатор исчезает из списка окна "Добавить индикатор" в QUIK. Нет возможности установить индикатор в котором более 3-х линий.

      3. Отредактировал и сформировал индикаторы для удобства использования, скачать - https://yadi.sk/d/ZBA1SoSPma8jV . Добавил подробную инструкцию по установке и настройке индикаторов. Чтобы не путаться в Вашем архиве со старой версией индикаторов, можно разместить данный архив с Вашего сайта для скачивания.
        P.S.
        У Вас ссылка для скачивания размещена на сайте - http://www.denegin.ru Денегин Сергей – это ВЫ.