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

07.04.2025 palmax

Рассказ о том как написать свой индикатор в 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 для отображения сигналов:

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

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

В результате получаем картинку типа такой:

В данном случае функция генерит случайное значение от -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

Получаем такой индикатор:

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

Мой телеграм: https://t.me/autotradering