Работа индикатора вне графика.

Страницы: 1
RSS
Работа индикатора вне графика.
 
Есть простой индикатор по типу parabolic.
на вход принимает свечи и отдает свой результат в виде цены.
function Oncalculate(idx)
— блаблабла
return psar
end

Хочу без добавления индикатора на график, добавить его код в свой скрипт и
скормить ему 20-30 последних свечей и получить ответы.

Подскажите, как можно реализовать?
Понимаю, что нужно делать через CreateDataSource, но навыка не хватает.
 
Вот ссылка на индикатор,  https://forum.quik.ru/messages/forum10/message78143/topic8506/#message78143, на что нужно обратить внимание, это в анонимной функции на передачу ds!
ds  = CreateDataSource, то есть мы передаем методы на которые подписаны, это делается именно для того, чтоб без извинений и переделок можно было индикатор использовать в алгоритмах, через наследование.
 
Цитата
VPM написал:
Вот ссылка на индикатор,   https://forum.quik.ru/messages/forum10/message78143/topic8506/#message78143 , на что нужно обратить внимание, это в анонимной функции на передачу ds!
ds  = CreateDataSource, то есть мы передаем методы на которые подписаны, это делается именно для того, чтоб без извинений и переделок можно было индикатор использовать в алгоритмах, через наследование.
Чисто не понял вас:) По ссылке по-моему вообще о другом пишут.
 
VPM, или может я не правильно высказался.
Мне по сути нужно поменять Oncalculate() индикатора на function psar() и подать уже на эту функцию свечи.
 
Посмотрите это пример, он рабочий подставите свои данный и по выводите.
Код
-- Global settings
local CLASS_CODE = "SPBFUT"         -- Код класса инструмента
local SEC_CODE = "CRM5"             -- Код инструмента
local TRADE_ACCOUNT = "" -- Счет
local LOTS = 1                      -- Количество лотов

-- Инициализация данных
local dailyTrend = "none"
local entryPrice = 0
local sl = 0
local tp = 0

-- Функция получения свечей
function getCandles(ds, count)
    local candles = {}
    local size = ds:Size()
    --message( 'size = ' .. size)
    for i = 0, count do
        if size >= 1 then
            candles[i] = {
                high = ds:H(size - i) or 0,
                low = ds:L(size - i) or 0,
                open = ds:O(size - i) or 0,
                close = ds:C(size - i) or 0
            }
        end
    end
    return candles
end

-- Расчет ATR
function calculateATR(ds, period)
    local sumTR = 0
    local size = ds:Size()
    
    for i = 1, period do
        local prevClose = ds:C(size - i + 1) or 0
        local high = ds:H(size - i) or 0
        local low = ds:L(size - i) or 0
        
        local TR = math.max(
            high - low,
            math.abs(high - prevClose),
            math.abs(low - prevClose)
        )
        sumTR = sumTR + TR
    end
    return sumTR / period
end

-- Функция определения тренда на D1
function getDailyTrend()

    local ds_D1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_D1)

    local dailyCandles = getCandles(ds_D1, 4)
   local atr = calculateATR(ds_D1, 4)

    local o0 = dailyCandles[0].open or ds_D1:O(ds_D1:Size()) or 0
   --message('o0 = ' .. tostring(o0) .. '; dailyCandles[0].open = ' .. tostring(dailyCandles[0].open) )

    local HH = math.max(
        dailyCandles[1].high, 
        dailyCandles[2].high, 
        dailyCandles[3].high
    )
    local LL = math.min(
        dailyCandles[1].low, 
        dailyCandles[2].low, 
        dailyCandles[3].low
    )
    local trend = "range"
    if o0 > HH then trend = "uptrend"
    elseif o0 < LL then trend = "downtrend"
    else trend = "range" 
   end

   local daily = {['trend'] = trend, 
                  ['hh'] = HH, 
               ['ll'] = LL, 
               ['o'] = o0, 
               ['atr'] = atr,
               ['targetB'] = atr + o0,
               ['targetS'] = o0 - atr
               }
   return daily
end

-- Проверка структуры на H1
function checkH1Structure(trend)
    local ds_H1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_H1)
    local h1Candles = getCandles(ds_H1, 5)
   local atr = calculateATR(ds_H1, 14)
    local currentClose = ds_H1:C(ds_H1:Size()) or 0
    
    if trend == "uptrend" then
        return h1Candles[1].high > h1Candles[2].high and
               h1Candles[2].low < h1Candles[3].low and
               currentClose > h1Candles[1].high
    elseif trend == "downtrend" then
        return h1Candles[1].low < h1Candles[2].low and
               h1Candles[2].high > h1Candles[3].high and
               currentClose < h1Candles[1].low
    end
    return false
end

-- Поиск точки входа на M1
function checkM1Entry(trend)
    local ds_M1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_M1)
    local m1Candles = getCandles(ds_M1, 20)
    local atr = calculateATR(ds_M1, 14)
    local currentClose = ds_M1:C(ds_M1:Size()) or 0
    
    if trend == "uptrend" then
        if currentClose > m1Candles[0].high then
            entryPrice = currentClose
            sl = entryPrice - atr
            tp = entryPrice + 2*atr
            return true
        end
    elseif trend == "downtrend" then
        if currentClose < m1Candles[0].low then
            entryPrice = currentClose
            sl = entryPrice + atr
            tp = entryPrice - 2*atr
            return true
        end
    end
    return false
end

-- Отправка ордера
function placeOrder(direction)
    local transaction = {
        ACTION = "NEW_ORDER",
        CLASSCODE = CLASS_CODE,
        SECCODE = SEC_CODE,
        ACCOUNT = TRADE_ACCOUNT,
        OPERATION = direction == "uptrend" and "B" or "S",
        PRICE = entryPrice,
        QUANTITY = tostring(LOTS),
        STOPPRICE = tostring(sl),
        EXPIRY = "GTC"
    }
    
    local res = SendTransaction(transaction)
    if res then
        message("Order placed: "..direction..
                " | Price: "..entryPrice..
                " | SL: "..sl..
                " | TP: "..tp)
    else
        message("Error placing order!")
    end
end
local is_run
function OnInit()
    --strategy = Strategy:new(config)
    --strategy:start()
    is_run = true
   message('Стратегия 3ТФ инициализирована')
end
function OnStop()
    --strategy:stop()
    is_run = false
   message('Стратегия 3ТФ остановлена')
end
function OnTransReply(r)
    --strategy:handle_transaction_reply(r)
end
function OnTrade(t)
    --strategy:handle_trade(t)
end
function OnOrder(o)
    --strategy:handle_order(o)
end
-- Основной обработчик
function main()
    message('Стратегия 3ТФ запущена')
    local daily = getDailyTrend()
    message( 'Стратегия 3ТФ dailyTrend = ' .. tostring(daily.trend) 
         ..'; HH = '.. tostring(daily.hh) 
         ..'; LL = '.. tostring(daily.ll)
         ..'; o0 = '.. tostring(daily.o) 
         ..'; atr = '.. tostring(daily.atr)
         ..'; targetB = '.. tostring(daily.targetB)
         ..'; targetS = '.. tostring(daily.targetS)
         )
    daily.trend = "uptrend"

    while is_run do

      if daily.trend ~= "range" then
        if  checkH1Structure(daily.trend) then
            if checkM1Entry(daily.trend) then
                placeOrder(daily.trend)
            end
        end
      end
        sleep(1000)
    end
end
 
Все равно мало что понял. Код индикатора:
Код
function OnCalculate(idx)
   if idx<Settings.Period_ATR then
   return nil
   else
      if idx==Settings.Period_ATR  then
         psar={}
         psar[idx]=L(idx)
         long=true
         hmax=H(idx)
         per_ATR=Settings.Period_ATR
         local TR=0
         for js=(idx-per_ATR+1),idx do
            TR=(TR+H(js)-L(js))
         end
         Old_ATR=TR/per_ATR
         revers=true
      else
         if idx~=old_idx then
            local TR=0
            for js=(idx-per_ATR+1),idx do
            TR=(TR+H(js)-L(js))
            end
            local ATR=TR/per_ATR
            af=ATR/(Old_ATR+ATR)
            af=af/10
            Old_ATR=ATR
            if long then
            if hmax<H(idx-1) then
            hmax=H(idx-1)
            end
            psar[idx]=psar[idx-1]+af*(hmax-psar[idx-1])
            end
            if short then
            if lmin>L(idx-1) then
            lmin=L(idx-1)
            end
            psar[idx]=psar[idx-1]+af*(lmin-psar[idx-1])
            end
            revers=true
         end
         if long and L(idx)<psar[idx] and revers then
            psar[idx]=hmax
            short=true
            long=false
            lmin=L(idx)
            af=Step
            revers=false
         end
         if short and H(idx)>psar[idx] and revers then
            psar[idx]=lmin
            long=true
            short=false
            hmax=H(idx)
            af=Step
            revers=false
         end
      end

   old_idx=idx

   return psar[idx]
   end

Дальше я хочу поместить его в свой скрипт, чтобы получилось примерно следующее:
Код
function OnInit() 
function PSAR(idx)   
if idx<Settings.Period_ATR then
   return nil
   else
      if idx==Settings.Period_ATR  then
         psar={}
         psar[idx]=L(idx)
         long=true
         hmax=H(idx)
         per_ATR=Settings.Period_ATR
         local TR=0
         for js=(idx-per_ATR+1),idx do
            TR=(TR+H(js)-L(js))
         end
         Old_ATR=TR/per_ATR
         revers=true
      else
         if idx~=old_idx then
            local TR=0
            for js=(idx-per_ATR+1),idx do
            TR=(TR+H(js)-L(js))
            end
            local ATR=TR/per_ATR
            af=ATR/(Old_ATR+ATR)
            af=af/10
            Old_ATR=ATR
            if long then
            if hmax<H(idx-1) then
            hmax=H(idx-1)
            end
            psar[idx]=psar[idx-1]+af*(hmax-psar[idx-1])
            end
            if short then
            if lmin>L(idx-1) then
            lmin=L(idx-1)
            end
            psar[idx]=psar[idx-1]+af*(lmin-psar[idx-1])
            end
            revers=true
         end
         if long and L(idx)<psar[idx] and revers then
            psar[idx]=hmax
            short=true
            long=false
            lmin=L(idx)
            af=Step
            revers=false
         end
         if short and H(idx)>psar[idx] and revers then
            psar[idx]=lmin
            long=true
            short=false
            hmax=H(idx)
            af=Step
            revers=false
         end
      end

   old_idx=idx

   return psar[idx]
   end
end
function main() 

function getCandles(ds, count)    local candles = {}
    local size = ds:Size()
    for i = 0, count do
        if size >= 1 then
            candles[i] = {
                high = ds:H(size - i) or 0,
                low = ds:L(size - i) or 0,
                open = ds:O(size - i) or 0,
                close = ds:C(size - i) or 0
            }
        end
    end
    return candles
end
local ds_H1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_H1)    
local h1Candles = getCandles(ds_H1, 5)

psar=PSAR(h1Candles) --только в цикле по количеству свечей

end

Но,  не понимаю как передавать свечи в функцию индикатора, да еще и в цикле получается.
 
Вот сделал так, но естественно получаю ошибку(test2.lua:9: attempt to compare nil with number):
Код
function OnInit()

   Period_ATR=14
   old_idx=0
   long=false
   short=false
   revers=false
   function PSAR(idx)
      if idx<Period_ATR then
      return nil
      else
         if idx==Period_ATR  then
            psar={}
            psar[idx]=L(idx)
            long=true
            hmax=H(idx)
            per_ATR=Period_ATR
            local TR=0
            for js=(idx-per_ATR+1),idx do
               TR=(TR+H(js)-L(js))
            end
            Old_ATR=TR/per_ATR
            revers=true
         else
            if idx~=old_idx then
               local TR=0
               for js=(idx-per_ATR+1),idx do
               TR=(TR+H(js)-L(js))
               end
               local ATR=TR/per_ATR
               af=ATR/(Old_ATR+ATR)
               af=af/10
               Old_ATR=ATR
               if long then
               if hmax<H(idx-1) then
               hmax=H(idx-1)
               end
               psar[idx]=psar[idx-1]+af*(hmax-psar[idx-1])
               end
               if short then
               if lmin>L(idx-1) then
               lmin=L(idx-1)
               end
               psar[idx]=psar[idx-1]+af*(lmin-psar[idx-1])
               end
               revers=true
            end
            if long and L(idx)<psar[idx] and revers then
               psar[idx]=hmax
               short=true
               long=false
               lmin=L(idx)
               af=Step
               revers=false
            end
            if short and H(idx)>psar[idx] and revers then
               psar[idx]=lmin
               long=true
               short=false
               hmax=H(idx)
               af=Step
               revers=false
            end
         end

      old_idx=idx

      return psar[idx]
      end
   end
end
   
function getCandles(ds, count)
    local candles = {}
    local size = ds:Size()
    for i = 0, count do
        if size >= 1 then
            candles[i] = {
                high = ds:H(size - i) or 0,
                low = ds:L(size - i) or 0,
                open = ds:O(size - i) or 0,
                close = ds:C(size - i) or 0
            }
        end
    end
    return candles
end   
   
function main()

   ds = CreateDataSource('TQBR', 'SBER', INTERVAL_M5)
   local Candles = getCandles(ds, 20)
   
   for i=1,ds:Size() do
      message("Значение индикатора:" ..tostring(PSAR()))
   end 

end
 
Ну хорошо давайте, по порядку.  OnCalculate(idx) это функция обратного вызова, специальная для создания индикаторов, все что она делает передает idx. Передавать ее некуда нельзя.
Но можно вынести из нее алгоритм расчет в отдельную функцию PSAR(idx) и уже работать с ней. Вот для индикатора.
function OnCalculate(idx)
PSAR(idx)
end
Для работы с ней в main(), нужно подписаться на источник вот этот момент из моего примера.

local ds_D1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_D1)
затем передаем,  а  здесь получаем свечи    local dailyCandles = getCandles(ds_D1, 4)
далее расчет индикатора  local atr = calculateATR(ds_D1, 4)

Вместо расчета АТР поставьте расчет собственного по аналогии. Удачи.  
 
Добавьте в пример вот эту функцию получения цены.

local string_upper,string_sub=string.upper,string.sub;
function Value(I,VType,ds)
   
   local Out = nil
   local VType=(VType and string_upper(string_sub(VType,1,1))) or "A"
   if VType == "O" then        --Open
       Out = (O and O(I)) or (ds and ds:O(I))
   elseif VType == "H" then     --High
       Out = (H and H(I)) or (ds and ds:H(I))
   elseif VType == "L" then    --Low
       Out = (L and L(I)) or (ds and ds:L(I))
   elseif VType == "C" then    --Close
       Out = (C and C(I)) or (ds and ds:C(I))
   elseif VType == "V" then    --Volume
       Out = (V and V(I)) or (ds and ds:V(I))
   elseif VType == "X" then    --DateTime
       Out = (T and T(I)) or (ds and ds:T(I))
   elseif VType == "A" then    --Any
       if ds then Out = ds[I] end
   end
return Out
end
 
В OnInit() нельзя расчеты вести, она запускается до создания потока в main и предназначена для инициализации!
Страницы: 1
Читают тему
Наверх