Блог им. autotrade

Рассказ о том как написать свой индикатор в Quik

1. Сначала придумываем идею.
Ну, например, у нас будет какая-то загадочная кривая пересекаться с ценой и таким образом будет давать сигнал на покупку или продажу.
Делаем для нее функцию: my_function

Пример скрипта:
--[[
Название индикатора на русском для справки
--]]
Settings={
Name="my_ind",
prf=0, -- =1 - показать профит		
sign=0,	-- =1 - показать сигнал	
SLP = 1.0, -- стоплосс 
tar = 0.03, -- тариф %
Param=10, -- Параметр индикатора
    line=                                     
                {  
					{  
                        Name = "cur1",
                        Type =TYPE_LINE,
                        Width = 2,
                        Color = RGB(0,0, 0)
                    },
					{  
                        Name = "cur2",
                        Type =TYPE_LINE,
                        Width = 2,
                        Color = RGB(255,0, 0)
                    },					
					{  
                        Name = "TRIANGLE_DOWN",
                        Type =TYPE_TRIANGLE_DOWN,
                        Width = 5,
                        Color = RGB(255, 0, 0)
                    },
					{  
                        Name = "TRIANGLE_UP",
                        Type =TYPE_TRIANGLE_UP,
                        Width = 5,
                        Color = RGB(0, 0, 255)
                    },
					{  
                        Name = "cur5",
                        Type =TYPE_POINT,
                        Width = 5,
                        Color = RGB(255, 0, 255)
                    },
					{  
                        Name = "cur6",
                        Type =TYPE_POINT,
                        Width = 5,
                        Color = RGB(0, 0, 255)
                    }				
                }
}


function my_function(index)

 val = math.random(Settings.Param) - Settings.Param/2
 
 val = O(index) + val

 return val

end


function Init()  

       
  return 6
  
end

function OnCalculate(index)

  


  SLP = Settings.SLP 	
  -- trades   
   if index == 1 then
    prof = {}
	pos = {}
	SLV = {}
	deal = {}
	dealx = {}
	prof[index] = 0  
	pos[index] = 0  
	SLV[index] = 0
	deal[index] = 0
	dealx[index] = 1
	value = {}
	value[index] = O(index)
  else 	
	prof[index] = prof[index-1] 
	pos[index] = pos[index-1]
	SLV[index] = SLV[index-1]
	deal[index] = deal[index-1]
	dealx[index] = dealx[index-1]
		
	value[index] = my_function(index)
	
	if 
	
        pos[index] ~= 1 and 
		O(index) > value[index] and
		O(index-1) <= value[index-1] and
		dealx[index] ~= index 
		
	then -- long 

		  pos[index] = 1
		  deal[index] = O(index)
		  dealx[index] = index
		  SLV[index] = SLP*O(index)/100 
 
	else   
		if 	
		
        pos[index] ~= -1 and 
		O(index) < value[index] and
		O(index-1) >= value[index-1] and
		dealx[index] ~= index

		then -- short	

		  pos[index] = -1
		  deal[index] = O(index)
		  dealx[index] = index
		  SLV[index] = SLP*O(index)/100 
 
		end 
	end  

	  if deal[index] ~= 0 and pos[index] == 1 and 
	    deal[index] - O(index) > SLV[index]
	  then -- cash
		pos[index] = 0
		deal[index] = 0
		dealx[index] = 1
	  else   
		if deal[index] ~= 0 and pos[index] == -1 and 
	      O(index) - deal[index] > SLV[index]
		then -- cash
		  pos[index] = 0    
		  deal[index] = 0
		  dealx[index] = 1
		end 
	  end 	
	
  end 


  

  if index == Size() then 
   if Settings.sign == 1 then   
    for i = 2, Size() do 
	  if pos[i] ~= nil and pos[i-1] ~= nil then 
	    if pos[i-1] ~= 1 and pos[i] == 1 then
	        SetValue(i, 4, O(i))		  
	    else	  
	     if pos[i-1] ~= -1 and pos[i] == -1 then
	        SetValue(i, 3, O(i))				  
	     else
	       SetValue(i, 3, nil)	
	       SetValue(i, 4, nil)	
	     end 
         if pos[i] ~= pos[i-1] and pos[i] == 0 then  
		   if pos[i-1] == 1 then 
				SetValue(i, 5, O(i))					  
           else 	
				SetValue(i, 6, O(i))				  
           end 			 
         end  
	    end 
	  end 
    end 
   end	
  end  

	
  -- profit 
  if Settings.prf==1 then  
    if pos[index-1] ~= nil then 
      if pos[index-1] == 1 then  
          prof[index] = prof[index-1] +	(O(index) - O(index-1))	  
	  end 
      if pos[index-1] == -1 then         	  
          prof[index] = prof[index-1] +	(O(index-1) - O(index))
	  end 	
	  if pos[index-1] == 0 then 
	    prof[index] = prof[index-1]
	  end 
	  if pos[index] ~= pos[index-1] then    
        if pos[index] == 0 or pos[index-1] == 0 then    	  
		  prof[index] = prof[index] - Settings.tar*O(index)/100		
		else 
		  prof[index] = prof[index] - 2*Settings.tar*O(index)/100		
		end
	  end	
    end  
	
	
	return prof[index] 
  else   
    if Settings.sign == 1 then   
      return value[index]
	else   
	  return nil
	end 
  end    
 
 
  
end

В первой области ставим значение парамеnра sign = 1 для отображения сигналов:
Рассказ о том как написать свой индикатор в Quik

Дорабатываем индикатор до того чтоб он показал нормальную доходность.

Доходность можно вывести в отдельной области указав параметр prf=1:
Рассказ о том как написать свой индикатор в Quik

В результате получаем картинку типа такой:
Рассказ о том как написать свой индикатор в Quik

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

2. Чтоб проверить как работает индикатор в онлайн, выбираем таймфрейм 1 минута, минимальные параметры, чтоб часто срабатывал и ждем пока не набегут сигналы. потом нажимаем правой клавишей «Скопировать». Окно копируется и индикатор за всю эту историю перестраивается как бы делает расчет в офлайне. И смотрим, совпадают ли сигналы в первом окне и в новом. Если совпадают то в офлайне он работает как в онлайне, чего нам и нужно.

Другой вариант когда функция рассчитывает среднее значение, длина = 100, так же в индикатор уже внедрен функционал по стоплоссу:
--[[
Название индикатора на русском для справки
--]]
Settings={
Name="my_ind",
prf=0, -- =1 - показать профит		
sign=0,	-- =1 - показать сигнал	
SLP = 1.0, -- стоплосс 
tar = 0.03, -- тариф %
Param=100, -- Параметр индикатора
    line=                                     
                {  
					{  
                        Name = "cur1",
                        Type =TYPE_LINE,
                        Width = 2,
                        Color = RGB(0,0, 0)
                    },
					{  
                        Name = "cur2",
                        Type =TYPE_LINE,
                        Width = 2,
                        Color = RGB(255,0, 0)
                    },					
					{  
                        Name = "TRIANGLE_DOWN",
                        Type =TYPE_TRIANGLE_DOWN,
                        Width = 5,
                        Color = RGB(255, 0, 0)
                    },
					{  
                        Name = "TRIANGLE_UP",
                        Type =TYPE_TRIANGLE_UP,
                        Width = 5,
                        Color = RGB(0, 0, 255)
                    },
					{  
                        Name = "cur5",
                        Type =TYPE_POINT,
                        Width = 5,
                        Color = RGB(255, 0, 255)
                    },
					{  
                        Name = "cur6",
                        Type =TYPE_POINT,
                        Width = 5,
                        Color = RGB(0, 0, 255)
                    }				
                }
}


function my_function(index)

 if index == 1 then 
   ma = {}
   mas = {}
   ma[index] = nil
   mas[index] = O(index)
 else 
   mas[index] = mas[index-1] + O(index)
   ma[index] = nil
 end
 
 if index > Settings.Param and Settings.Param ~= 0 then 
   ma[index] = (mas[index] - mas[index - Settings.Param])/Settings.Param 
 end 

 return ma[index]

end


function Init()  

       
  return 6
  
end

function OnCalculate(index)

  


  SLP = Settings.SLP 	
  -- trades   
   if index == 1 then
    prof = {}
	pos = {}
	SLV = {}
	deal = {}
	dealx = {}
	prof[index] = 0  
	pos[index] = 0  
	SLV[index] = 0
	deal[index] = 0
	dealx[index] = 1
	value = {}
	value[index] = my_function(index)
  else 	
	prof[index] = prof[index-1] 
	pos[index] = pos[index-1]
	SLV[index] = SLV[index-1]
	deal[index] = deal[index-1]
	dealx[index] = dealx[index-1]
		
	value[index] = my_function(index)
	
	if value[index-1] ~= nil then 
	
	 if 
	
		O(index) > value[index] and
		O(index-1) <= value[index-1] and
		dealx[index] ~= index and
		(
		  ( 
		    O(index) < deal[index] or 
		    O(index) > deal[index] + SLV[index]
		  ) and pos[index] == -1
		  or
		  pos[index] == 0
		) 
		
	 then -- long 

		  pos[index] = 1
		  deal[index] = O(index)
		  dealx[index] = index
		  SLV[index] = SLP*O(index)/100 
 
	 else   
		if 	
		
		O(index) < value[index] and
		O(index-1) >= value[index-1] and
		dealx[index] ~= index and
		(
		  ( 
		    O(index) > deal[index] or 
		    O(index) < deal[index] - SLV[index]
		  ) and pos[index] == 1
		  or
		  pos[index] == 0
		)

		then -- short	

		  pos[index] = -1
		  deal[index] = O(index)
		  dealx[index] = index
		  SLV[index] = SLP*O(index)/100 
 
		end 
	 end  
	end

	  if deal[index] ~= 0 and pos[index] == 1 and 
	    deal[index] - O(index) > SLV[index]
	  then -- cash
		pos[index] = 0
		deal[index] = 0
		dealx[index] = 1
	  else   
		if deal[index] ~= 0 and pos[index] == -1 and 
	      O(index) - deal[index] > SLV[index]
		then -- cash
		  pos[index] = 0    
		  deal[index] = 0
		  dealx[index] = 1
		end 
	  end 	
	
  end 


  

  if index == Size() then 
   if Settings.sign == 1 then   
    for i = 2, Size() do 
	  if pos[i] ~= nil and pos[i-1] ~= nil then 
	    if pos[i-1] ~= 1 and pos[i] == 1 then
	        SetValue(i, 4, O(i))		  
	    else	  
	     if pos[i-1] ~= -1 and pos[i] == -1 then
	        SetValue(i, 3, O(i))				  
	     else
	       SetValue(i, 3, nil)	
	       SetValue(i, 4, nil)	
	     end 
         if pos[i] ~= pos[i-1] and pos[i] == 0 then  
		   if pos[i-1] == 1 then 
				SetValue(i, 5, O(i))					  
           else 	
				SetValue(i, 6, O(i))				  
           end 			 
         end  
	    end 
	  end 
    end 
   end	
  end  

	
  -- profit 
  if Settings.prf==1 then  
    if pos[index-1] ~= nil then 
      if pos[index-1] == 1 then  
          prof[index] = prof[index-1] +	(O(index) - O(index-1))	  
	  end 
      if pos[index-1] == -1 then         	  
          prof[index] = prof[index-1] +	(O(index-1) - O(index))
	  end 	
	  if pos[index-1] == 0 then 
	    prof[index] = prof[index-1]
	  end 
	  if pos[index] ~= pos[index-1] then    
        if pos[index] == 0 or pos[index-1] == 0 then    	  
		  prof[index] = prof[index] - Settings.tar*O(index)/100		
		else 
		  prof[index] = prof[index] - 2*Settings.tar*O(index)/100		
		end
	  end	
    end  
	
	
	return prof[index] 
  else   
    if Settings.sign == 1 then   
      return value[index]
	else   
	  return nil
	end 
  end    
 
 
  
end

Получаем такой индикатор:
Рассказ о том как написать свой индикатор в Quik
В индикаторе так же используется такой параметр как тариф, что приближает к реальным условиям торгов.

Мой телеграм:
https://t.me/autotradering
  • обсудить на форуме:
  • Quik Lua
4.6К | ★10

Читайте на SMART-LAB:
Технологии как новый драйвер: ключевые идеи инвестиционного форума ВТБ «РОССИЯ ЗОВЕТ!»
🧮 Главный тренд 2026 года — стабилизация и технологический поворот Руководитель департамента по работе с клиентами рыночных отраслей...
ВТБ обещал миноритариям обойтись без допэмиссии
Акции ВТБ в ходе торгов 20 февраля, проходивших на российском рынке в умеренном плюсе, вышли в лидеры роста, подорожав на 3,4%, до 88,42...
Фото
Как инвестирует Ярослав Кабаков
Поговорили с директором по стратегии ФГ «Финам» Ярославом Кабаковым — обсудили вредные инвестпривычки, выбор стратегии, использование ИИ и...
Фото
Россети Центр. Отчет об исполнении инвестпрограммы за Q4 2025г. Ожидаемо снизилась дивидендная база по РСБУ.
Компания Россети Центр опубликовала отчет об исполнении инвестпрограммы за Q4 2025г., где показаны финансовые показатели компании по РСБУ в...

теги блога autotrade

....все тэги



UPDONW
Новый дизайн