Никогда не пользовался колбеком OnInit. Обычно я инициализирую переменные до начала main как то так:
Код
stop_loss_pc=3
MAsteps=1
is_run = true
send_order=false
for sec in string.gmatch(ticker_list,"%a+") do
lot[sec]=getParamEx(class,sec,"lotsize").param_value
step[sec]=getParamEx(class,sec,"SEC_PRICE_STEP").param_value
--задаём первоначальные бид, аск и ласт
last_price[sec]=tonumber(getParamEx(class,sec,"last").param_value)
if last_price[sec]==0 or last_price[sec]==nil then
last_price[sec]=tonumber(getParamEx(class,sec,"prevprice").param_value)
toLog (log, sec.." при запуске нет цены последней сделки "..type(last_price[sec]))
end
tablebid = getParamEx(class, sec, "bid") --получаем таблицу "bid"
bid_best[sec]=tonumber(toPrice(sec, tablebid.param_value)) --из таблицы берЄм значение
tableoffer = getParamEx(class, sec, "offer") --получаем таблицу "offer"
offer_best[sec]=tonumber(toPrice(sec, tableoffer.param_value)) --из таблицы берЄм значение
end
Зачем нужен OnInit? В него помещается такой же кусок кода? В чём преимущество? Спасибо.
По-моему были какие-то функцииQLua, которые корректно работают только в Init(), просто в теле скрипта не работают (что-то про источники данных, да?). Если речь про инициализацию переменных/открытие файлов и т.п. - то разницы нет никакой.
Космонавт написал: Зачем у Oninit в скобках параметр (script_path)? У меня работает и без него: OnInit ()
имеется в виду, что нужно делать так?
Код
script_path = getScriptPath ()
function OnInit (script_path)
--задаём переменные
end
Если память мне не врет, то вроде бы раньше вызов getScriptPath () в начале подвешивал скрипт и еще были глюки вызова функций QLUA вне колбеков или main.
Космонавт написал: Зачем у Oninit в скобках параметр (script_path)? У меня работает и без него: OnInit ()
имеется в виду, что нужно делать так?Кодscript_path=getScriptPath() function OnInit (script_path) --задаём переменные end
Имеется ввиду, что quik уже за Вас вызвал getScriptPath() и результат Вам подсовывает в качестве параметра при вызове OnInit(script_path). А уж будете Вы использовать этот "подарок" внутри OnInit или нет, дело Ваше
Небольшая поправка: В script_path Вы получаете не просто полной путь к папке запускаемого скрипта (как при вызове getScriptPath()), а полный путь, включая имя файла самого скрипта.
Ziveleos написал: Всё же, хотелось бы получить комментарий разработчика, в чем сакральный смысл функции OnInit?
В том, что это этот колбек вызывается раньше всех других колбеков и раньше функции main. Без него у Вас колбеки будут вызываться раньше, чем будет вызвана функция main.
в итоге если вы параметры торговли определяете в main, то колбеки начнут работу без параметров и могут такого вам наторговать, что будет мучительно стыдно за такой скрипт.
вообще-то ответ есть в документации: ------------- OnInit Функция вызывается терминалом QUIK перед вызовом функции main(). В качестве параметра принимает значение полного пути к запускаемому скрипту.
Формат вызова:
OnInit(STRING script_path)
В данной функции пользователь имеет возможность инициализировать все необходимые переменные и библиотеки перед запуском основного потока main().
Необходимые переменные и библиотеки перед запуском основного потока main() возможно инициализировать и в BODY. Если скрипт не HFT, или вообще без коллбэков, получается OnInit не сильно нужен.
Ziveleos, OnInit нафиг не нужен. Как и весь этот маразм с двумя потоками. Лично я выбросил OnInit если не в первой, то во второй версии своего скрипта. Думаю, это наследие С++ - там тоже какие-то идиотские трепыхания идут ещё до main.
Владимир, Второй поток все-таки нужен, иначе QUIK замрёт, пока работает скрипт. А вот, что касается:
Цитата
nikolz написал: В том, что это этот колбек вызывается раньше всех других колбеков и раньше функции main.Без него у Вас колбеки будут вызываться раньше, чем будет вызвана функция main.
коллбэки начинают работать только вместе с main.
Код
qtes = {}
function OnQuote(class, sec )
ql2 = getQuoteLevel2(class, sec)
table.insert(qtes, ql2)
end
sleep(10000)
function main()
--sleep(10000)
message(tostring(#qtes))
end
Ziveleos, Второй поток нафиг не нужен, работа скрипта - это работа интерпретатора. По крайней мере, в нормальной реализации. Я в своё время потратил довольно много времени, чтобы переместить всё, что можно, в поток main, и с тех пор практически забыл про все глюки. Для эмуляции прерываний по таймеру использую sleep, а единственное "настоящее" прерывание - OnTrade.
Объясняю, тем кто не понял. -------------- Если у Вас скрипт запускается одновременно с запуском QUIK, то нет особой разницы, где Вы устанавливаете и загружаете начальные параметры скрипта. ------------------------- Но если Вы запускаете скрипт при работающем QUIK, т е в реальном времени торговли, то возможны следующие последствия в зависимости от места , где вы устанавливаете переменные. Рассмотрим эти варианты: ------------------ 1) В начале скрипта присваиваем значения. В этом случае присвоение происходит до полной загрузки скрипта и запуска функции main. присвоение произойдет лишь при загрузке скрипта. При этом могут быть еще не определены Ваши функции, которые Вы используете для назначения параметров. ------------------- 2) В начале функции main В этом случае весь скрипт уже загружен и все функции определены. Но так как main - это отдельный поток, то при длительной процедуре инициализации переменных могут поступить данные по колбекам и эти данные могут оказать влияние на установку переменных. Вот пример теста main c установкой параметров:
Код
local beg=os.clock();
local x={}
local function sig(i) return i end
function main()
Log:write("main начинаем устанавливать начальные значения"..os.clock()-beg.."\n"); --Log:flush();
for i=1,10000 do x[i]=math.sin(i); Log2:write("X="..x[i].."\n"); Log2:flush();
end;
Log:write("закончили установку нач значений\n"); Log:flush();
while true do
-- nkevent.wait(event); --ждем события
Log:write("main основной цикл="..os.clock()-beg.."\n"); Log:flush();
sleep(10);
end
end
а вот результат работы этого скрипта с колбеками
Код
OnI nit=0.0
main начинаем устанавливать начальные значения0.0010000000002037
On All=0.0020000000004075
On All=0.0020000000004075
On All=0.0020000000004075
...
On All=0.0060000000003129
On All=0.0060000000003129
On All=0.0060000000003129
...
On All=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
закончили установку нач значений
main основной цикл=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
On All=0.029999999999745
Внутри цикла установки параметров в функции main вызывается колбек OnAllTrade в основном потоке . ---------------------- 3) Установка параметров в колбеке OnInit() это самый безопасный и предсказуемый способ установки. OnInit вызывается ,когда весь скрипт загружен и определены все наши функции. OnInit вызывается в основном потоке, когда поток main еще не запущен. Так как все колбеки вызываются в основном потоке, то они не могут быть вызваны пока OnInit не завершит работу. =================== Т е все переменные будут определены и загружены без каких-либо неожиданностей. ==================== Приведу для наглядности аналогию. На перекрестке есть светофор. Особо буйные могут ходить через перекресток не взирая на сигналы светофора. Особо продвинутые могут даже ходить с закрытыми глазами. Особо осторожные будут ходить лишь на зеленый. --------------------- Выбор за Вами.
nikolz, В ЛЮБОМ случае "нет особой разницы, где Вы устанавливаете и загружаете начальные параметры скрипта". Я миллион раз запускал скрипт и во время торговли, и когда её нет, и НИ МАЛЕЙШИХ "последствий в зависимости от места , где вы устанавливаете переменные" не наблюдалось.
Ладно уж, "рассмотрим эти варианты": 1) Да, именно "в начале скрипта присваиваем значения". Я лично полагаю, что в этом случае присвоение происходит ПОСЛЕ полной загрузки скрипта, но ДО запуска функции main. Впрочем, допускаю, что и ДО полной загрузки, но это при условии, что системную математику писали клинические дебилы. В любом случае, это примерно одна секунда.
2) Да, "в начале функции main" ТОЖЕ производятся кое-какие присвоения. И в середине тоже. Более того, они могут присваиваться даже из внешних файлов - например, номер счёта, код клиента, состояние портфеля и кошелька. Но мне и в страшном сне не может присниться ни "длительная процедура инициализации переменных, ни, тем более, чтобы в это время могли поступить данные по колбекам, и уж совсем невозможно, чтобы эти данные хоть как-то могли "оказать влияние на установку переменных". Это нужен ТАЛАНТИЩЕ, чтобы такого добиться. Просто программировать нужно уметь, хоть немножко.
3) Установка параметров в колбеке OnInit нафиг не нужна, как и сам OnInit. Лично у меня этого дерьма нет, не было и не будет. Точнее, было в самом начале моего знакомства с Луа в тренировочном скрипте, где я пытался понять, за каким хреном эта бредятина может быть кому-то понадобиться.
Ziveleos, Я разве называл вторым потоком? Впрочем, неважно: поток main - он обязательный, так что первый и единственный, а всё остальное - это второй: прорисовка таблиц, коллбеки, и прочая лабуда. Прорисовка у меня вообще отключаемая - так называемый "спящий режим", всех коллбеков один OnTrade, так что в этом "основном потоке QUIK" мой скрипт находится дай бог сотую долю процента.
зря ругаете, функция необходима и ключевое здесь OnInit(STRING script_path) В данной функции пользователь имеет возможность инициализировать все необходимые переменные и библиотеки перед запуском основного потока main().
К примеру если обрабатываете колбек OnAllTrade() без нее и не обойтись.
VPM, НА КОЙ "функция необходима"? Я прекрасно могу инициализировать все необходимые переменные и без этого дерьма, как и без каких-либо библиотек - и перед запуском основного потока main, и после него, и во время него. OnAllTrade также нафиг не нужен.
Вопрос в организации переменных Вашего скрипта их локализации и видимости.
К примеру, "перед запуском основного потока main" всего 200 локальных переменных я постоянно выхожу за это число. Если как у Космонавта то сам lua ругается порой.
VPM, А тут не о чем спорить, задача организации торговли настолько проста, что её можно реализовать даже на чистом Луа, даже при полной ущербности системной математики Квика.
Какие могут быть ЛОКАЛЬНЫЕ переменные "перед запуском основного потока main" - то мне неведомо. У меня их... ну, пара десятков, наверное, наберётся. Впрочем, сейчас посчитаю... ого, аж 34 штуки.
Я смотрел Ваши посты Как понимаю у Вас свой подход вы не пользуетесь историей данных. А локализация в луа нужна чтоб не засорять для видимости и быстродействия.
Нет, я как раз прекрасно знаю, что никакая локализация в луа не нужна, и ничего не засоряется для видимости и быстродействия, если специально этим не заниматься.
Я не обсуждаю язык, бессмысленно другого нет. Я лишь прислушиваюсь к рекомендациям авторов. Проверить видимость легко, быстродействие скрипта легко с локальными и глобальными. SciTe одно нажатие.
А вот со сбором мусора сложней. Оказывается nil запускает сборщик.
На Ваш вопрос - В чём преимущество? Хотел сделать поправку на пост. Если скрипт небольшой, не требует особого быстродействия, не затратен по памяти. Вас все устраивает - То ни каких.
Если хотите оптимизировать Вас скрипт посмотрите "Програмирование на Lua" сэкономит много времени. Проверено!
Видимо, единственное преимущество OnInit в том, что в отличии от body, из неё можно вызывать функции не объявленные ранее. Ну, и " В качестве параметра принимает значение полного пути к запускаемому скрипту."
Скрытый текст
Код
file = io.open(getScriptPath() .. "\\Environment.txt", "w+")
local len = 0
for k, v in pairs(_ENV) do
file:write(string.format("%s\t %s \n",k,(tostring (v))))
len = len + 1
end
file:write("\n Окружение BODY: ", len, "\n\n" )
function OnInit()
local len = 0
for k, v in pairs(_ENV) do
file:write(string.format("%s\t %s \n",k,(tostring (v))))
len = len + 1
end
file:write("\n Окружение OnInit: ", len, "\n\n" )
end
function main()
file:seek("set")
local log = file:read("a")
local b_log = string.match(log, "(.-)\n\n")
local i_log = string.match(log, "Окруж.-\n\n(.-)\n\n")
file:write(" Нет в BODY: ")
for s in string.gmatch(i_log, "(.-)\t.-\n") do
if not string.match(b_log, s) then
file:write("\n", s)
end
end
file:write("\n\n Разница: ")
for s in string.gmatch(i_log, "(.-)\n") do
if not string.match(b_log, s) then
file:write("\n", s)
end
end
file:flush()
file:close()
end
--file:write("Чудо-юдо рыба-кит \n")
function tableLog(t)
for k, v in pairs(t) do
file:write(string.format("%s %s \n",k,(tostring (v))))
end
end
Владимир, переменные окружения показывают разницу между body и OnInit. Получается, если до зарезу необходимо сделать что-то до начала работы коллбэков, и в этом "что-то" используются функции объявляемые позже, то без OnInit не обойтись. В остальном он на фиг не нужен.
Ziveleos написал: Владимир, переменные окружения показывают разницу между body и OnInit. Получается, если до зарезу необходимо сделать что-то до начала работы коллбэков, и в этом "что-то" используются функции объявляемые позже, то без OnInit не обойтись. В остальном он на фиг не нужен.
Body скрипта выполняется в потоке терминала. Так что служебные переменные вполне себе инициализируются там.
Читаем документацию:
Цитата
Как и в предыдущей структуре скрипта Lua, после его запуска первоначально выполняются сценарии, описанные в <BODY>, если они присутствуют. Далее происходит вызов обработчика с именем OnInit(), если он присутствует. В обработчике OnInit() пользователь имеет возможность инициализировать все необходимые переменные и библиотеки перед запуском отдельного потока. После завершения функции OnInit() происходит создание отдельного потока РМ QUIK, и в этом потоке начинает выполнение функция main(), которая обязательно должна присутствовать в скрипте.
Так что тело скрипта вполне себе достаточно. OnInit вполне можно использовать для каких-то действий после выполнения служебных процедур, например проверить, что запуск возможен. А если нет - отказ. Но все это можно делать так или иначе.
Речь же про колбеки звучит странно, т.к. я слабо себе представляю использование колбеков в алгоритме, если они не обработаны все. Например, запуск в середине торгового дня. Половина колбеков уже прошла, надо читать прошедшие события из таблиц, и здесь уже не важно как инициализировать. Поэтому колбеки - это вспомогательный инструмент, не более. "Прибивать гвоздями" их к логике - не самая лучшая затея. Он может и не прийти, в конечном итоге. Гарантированной доставки в документации не декларируется.
Ziveleos, Я же спросил: ДЛЯ ТОРГОВЛИ на кой эта хрень нужна? ЗА КАКИМ ХРЕНОМ кому-то "до зарезу необходимо сделать что-то до начала работы коллбэков"? И кому нужно такое говно как Луа, КРОМЕ организации торговле на бирже?
Nikolay написал: Речь же про колбеки звучит странно, т.к. я слабо себе представляю использование колбеков в алгоритме, если они не обработаны все. Например, запуск в середине торгового дня. Половина колбеков уже прошла, надо читать прошедшие события из таблиц, и здесь уже не важно как инициализировать. Поэтому колбеки - это вспомогательный инструмент, не более. "Прибивать гвоздями" их к логике - не самая лучшая затея. Он может и не прийти, в конечном итоге. Гарантированной доставки в документации не декларируется.
Просто из собственного опыта при запуске от колбека пришло а основной цикл еще не запущен. Прошедшие события читаю и из таблиц перед за основного цикла, после запуска беру из колбека. А какие еще варианты обработать т. всех сделок?
Nikolay написал: Body скрипта выполняется в потоке терминала. Так что служебные переменные вполне себе инициализируются там.
А я что сказал?
Цитата
if до зарезу необходимо сделать что-то до начала работы коллбэков, and в этом "что-то" используются функции объявляемые позже, then без OnInit не обойтись. end В остальном он на фиг не нужен.
Цитата
Nikolay написал: Речь же про колбеки звучит странно, т.к. я слабо себе представляю использование колбеков в алгоритме, если они не обработаны все.
Если в самой функции коллбэка используется нечто не объявленное ранее, и он сработает, возникнет ошибка. Поэтому это "нечто" нужно объявить до запуска main.