Есть простой индикатор по типу 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, то есть мы передаем методы на которые подписаны, это делается именно для того, чтоб без извинений и переделок можно было индикатор использовать в алгоритмах, через наследование.
Чисто не понял вас:) По ссылке по-моему вообще о другом пишут.
Посмотрите это пример, он рабочий подставите свои данный и по выводите.
Код
-- 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