Блок кода QLua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | -- ПРОВЕРКА ВЫСТАВЛЕНИЯ ЗАЯВКИ ПО ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ -- для примера отправляется транзакция на выставление лимитированной заявки на покупку по определенной цене ACCOUNT = "SPBFUT00k59" -- Код счета CLASS_CODE = "SPBFUT" -- Код класса SEC_CODE = "RIH6" -- Код инструмента OpenPrice = 73000 -- Цена выставления заявки run = true -- Флаг работы цикла while в функции main trans_id = os.time() -- Текущие дата и время в секундах хорошо подходят для уникальных номеров транзакций LastStatus = nil -- Последний статус транзакции, который был выведен в сообщении -- Основная функция скрипта, пока работает эта функция, работает скрипт function main() -- Отправляет транзакцию на открытие позиции TransOpenPos() -- Пока работает данный цикл, работает скрипт while run do sleep(1) end end -- Срабатывает при остановке скрипта function OnStop() run = false end -- Отправляет транзакцию на открытие позиции function TransOpenPos() -- Выставляет заявку на открытие позиции -- Получает ID для следующей транзакции trans_id = trans_id + 1 -- Заполняет структуру для отправки транзакции local Transaction={ ['TRANS_ID'] = tostring(trans_id), -- Номер транзакции ['ACCOUNT'] = ACCOUNT, -- Код счета ['CLASSCODE'] = CLASS_CODE, -- Код класса ['SECCODE'] = SEC_CODE, -- Код инструмента ['ACTION'] = 'NEW_ORDER', -- Тип транзакции ('NEW_ORDER' - новая заявка) ['OPERATION'] = 'B', -- Операция ('B' - buy, или 'S' - sell) ['TYPE'] = 'L', -- Тип ('L' - лимитированная, 'M' - рыночная) ['QUANTITY'] = '1', -- Количество ['PRICE'] = tostring(OpenPrice) -- Цена } -- Отправляет транзакцию local Res = sendTransaction(Transaction) if Res ~= '' then message('TransOpenPos(): Ошибка отправки транзакции: '..Res) else message('TransOpenPos(): Транзакция отправлена') end end -- Функция вызывается терминалом, когда с сервера приходит новая информация о транзакциях function OnTransReply(trans_reply) -- Если пришла информация по нашей транзакции if trans_reply.trans_id == trans_id then -- Если данный статус уже был обработан, выходит из функции, иначе запоминает статус, чтобы не обрабатывать его повторно if trans_reply.status == LastStatus then return else LastStatus = trans_reply.status end -- Выводит в сообщении статусы выполнения транзакции if trans_reply.status < 2 then -- Статусы меньше 2 являются промежуточными (0 - транзакция отправлена серверу, 1 - транзакция получена на сервер QUIK от клиента), -- при появлении такого статуса делать ничего не нужно, а ждать появления значащего статуса -- Выходит из функции return elseif trans_reply.status == 3 then -- транзакция выполнена message('OnTransReply(): По транзакции №'..trans_reply.trans_id..' УСПЕШНО ВЫСТАВЛЕНА заявка №'..trans_reply.order_num..' по цене '..trans_reply.price..' объемом '..trans_reply.quantity) elseif trans_reply.status > 3 then -- произошла ошибка message('OnTransReply(): ОШИБКА выставления заявки по транзакции №'..trans_reply.trans_id..', текст ошибки: '..trans_reply.result_msg) end end end |
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Доброго времени суток.
Не могли бы вы подсказать, где можно найти перечисление возможных значений, таких параметров транзакции как ACTION и TYPE?
Здравствуйте! Файл справки (находится в папке с терминалом квик) info.chm: "Раздел 6. Совместная работа с другими приложениями" - "Импорт транзакций" - "Формат .tri-файла с параметрами транзакций" и "Примеры строк, которые могут содержаться в файле"
Приветствую Вас!
А так ли необходима функция OnTransReply()? Не достаточно ли того что написано тут :
Здравствуйте!
Смысл в том, что в Res появится ошибка только если сам терминал ее обнаружит, еще до отправки на сервер брокера. И если биржа отклонит данную транзакцию по какой-то причине, то мы об этом сможем только догадываться, ожидая результата. OnTransReply() решает эту проблему.
Вот так ловчее, по моему:
а вообще, на мой взгляд, OnTransReply нужна только для получения ошибки, обработки этой ошибки и коррекции заявки для повторного выставления, если ошибки нет, то и нечего в ней (функции) делать.
Я ее тоже только для отлова ошибок использую, но видел роботы, которые используют ее, как основную функцию скрипта.
Красиво использование:
local OldTransReply = {}
Но почему объявлено локально, не понял.
Все переменные хранятся в таблицах lua, таблица с локальными переменными меньше, чем с глобальными (ровно такого размера, сколько вы объявили локальных переменных у себя в коде) и доступ к ним быстрее. Главное с областью видимости не перепутать.
Т.е.:
При частом использовании будет работать медленнее, чем:
Спасибо.
Т.е. раз интерпретатор, то и доступ к переменным не прямой, а последовательный, следовательно чем переменных больше, тем медленней выборка адреса для операции (производится поиск адреса по имени переменной в таблице переменных)?
Скажем компилятор "С" вместо "math.floor(10/3)" влепит сразу адрес функции и загонит параметры с стек, а "перевалка" адреса функции в переменную может и удлинить бег кода.
Но кажется где-то читал, что lua таки делает какую-то предкомпиляцию перед выполнением...
Делает конечно - переводит написанные вами инструкции в двоичный код
local OldTransReply = {} объявлен локальной переменной в теле всего кода? И тогда по сути является глобальной переменной?
Локальная переменная по своей сути локальна и храниться в таблице локальных переменных, вопрос где она объявлена, если в начале кода, то доступ к ней есть у всего кода, если внутри кода, то блоки написанные выше переменной ее не будут видеть, если внутри блока - то забывается сразу после выхода из блока (удаляется из таблицы локальных переменных).
Глобальная переменная видна везде, т.к. заноситься в таблицу глобальных переменных на этапе компиляции.
Разница понятна между локальной и глобальной переменной?
Да. Получается что для функций, которые могут быть помещены где угодно в коде т.к. вызываются по мере необходимости, это правило так же справедливо. И локальную переменную, необходимую именно этой функции, нужно поставить поближе сверху к ней. Так?
Да, с локальными переменными, а тем более локальными функциями надо быть оч. внимательным.
Если функция объявлена локально и должна быть видна во всем коде, то пишем ее в начале кода.
Если эта локальная функция хочет использовать внешние локальные переменные, то эти переменные надо поместить выше этой функции.
Все просто.
Здравствуйте! Подскажите пожалуйста, таблица local OldTransReply = {} должна быть объявлена в main?
Здравствуйте, нет, должна быть объявлена выше main и функций, которые используют OldTransReply.
Пользуйтесь вот таким шаблоном:
после
until parseevent(table.sremove(events, 1)) or exitflag
нужна проверка
if exitflag then break end
Дмитрий, привет! Поправь, если не сложно.
Поправил, надеюсь правильно)
Спасибо, да правильно, иначе при срабатывании OnStop квик зависнет секунд на несколько
Спасибо за оперативный ответ ! Тоже к этому пришел, но решил уточнить 🙂
А шаблон - это как раз то, чего и не хватало !
Но пока сходу не разобрался. Вероятно, буду еще вопросы задавать, так что не обессудьте..)
Большое Спасибо автору сайта за великолепный сайт - просто класс !!!
Добрый вечер!
Пытаюсь осмыслить Ваш шаблон. Предложенная Вами событийная модель меня сильно заинтересовала но, к сожалению, знаний в этой области не хватает.
Хотелось бы посмотреть пример какого-либо простенького скрипта по данному шаблону (как описываются события, обработка событий, колбеки). Могли бы Вы его показать?
есть модель более удобная, но принцип примерно тот же.
https://quik2dde.ru/viewtopic.php?pid=2526#p2526
Скачивайте и разбирайтесь, комментарии есть.
таблица events это очередь. в нее кладется имя функции и таблица - параметр функции. в main из этой очереди достается значение, дальше в таблице handlerevent по имени ищется функция, и потом она вызывается с параметром:
events = { {'a', {1, 2, 3}}, {'b', {4, 5, 6}}}
handleevent = {a = function(tbl) ... end, b = function(tbl) ... end}
чтобы добавить обработчики нужно добавить в таблицу handleent своих функций, чтобы их вызвать - в таблицу events нужно добавить элемент-таблицу состоящую из имени обработчика и таблицы-параметра для этого обработчика. что такое table.sinsert и table.sremove я не знаю, но подозреваю это "добавить в конец таблицы" и "достать из начала таблицы и удалить".
ничего особенного в таком подходе нет, кроме того, что все обработчики вызываются в контексте функции main(). так навскидку - в этом примере нет проверок на существование обработчиков и можно было бы поизящнее сделать саму очередь и передачу параметров функции-обработчику. но есть опасность, связанная с тем, что эта очередь может расти быстрее, чем будут исполняться ваши обработчики, впрочем, все зависит от того, что вы в них напишите.
какой-то не правильный код, Дмитрий
Что в нем неправильно? 🙂
Веселый вы человек, Дмитрий))
OnTransReply(trans_reply) - не гарантирует, что можно уже выставлять заявку обратного направления, например - купил, и после получения ответа от биржи, что заявка исполнена - нельзя сразу выставить заявку на продажу. Соответственно, сама по себе функция OnTransReply() является чисто информативной и не белее
и не более, опечатка, сори
Разве "заявка исполнена" не означает, что совершена сделка? Понятно, что она может быть частично исполнена
дело не в сделке, а в том, чтобы пересчитались лимиты, а это не одно и тоже
Я сейчас посмотрел заголовок статьи "ПРОВЕРКА ВЫСТАВЛЕНИЯ ЗАЯВКИ ПО ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ " 🙂
Да дело не в этом, я посмотрел практически все ваши примеры, и многие рады и этому, но - это не правильно - значит вы намеренно вгоняете не опытных программистов в блуд, что само по себе - не хорошо)).
Намеренно я точно никого никуда не вгоняю 🙂 Давайте конструктивную критику, с удовольствием внесу правки в статьи, я нигде не заявлял, что я отец-основатель терминала QUIK и что знаю все его потайные комнаты 🙂
На почту пишите сами, когда Вам будет удобно, с удовольствием пообщаюсь с Вами, если по делу.
Задача у данного кода лишь одна: понять прошла ли транзакция и выставилась ли заявка, или нет, лимиты это уже другая история.
А как все-таки правильно?
Я так думаю каждый решает сам. Я пытаюсь проверять без OnTransReply(). Если здесь ошибки нет, то есть терминал не ругнулся
, то действую по схеме: если баланс в таблице заявок меньше рабочего (посланного транзакцией) объёма, то значит хоть одна заявка удовлетворена и далее в таблице сделок отслеживаем сколько же бумаг нам по этой заявке отдали и тут же смотрим полностью удовлетворён наш рабочий объём или сколько не добрали до него. Вот как-то так.
Я тоже считаю сделку совершённой только тогда, когда она появилась в OnTrade(), но все предыдущие шаги тоже отслеживаю (OnTransReply(), OnStopOrder(), OnOrder()), чтобы отлавливать возможные ошибки. Но как и написано в данной статье, для того, чтобы понять выставлена ли заявка (не сделка) по транзакции, достаточно OnTransReply().
Про лимиты спасибо, важное замечание!
не за что, мы уже с вами общались, хочу продолжить общение, напишите на мыло после праздников. И с праздниками вас))
Спасибо, и Вас с праздниками!
Здравствуйте я новичек не подскажите где копать , взял простой скрипт на QLua попытался запустить на демку в квик выдает ошибку в окне (Ошибка TransOpt: Не найдено поле ,, Проверять лимиты ,, для транзакции ,, Ввод заявки ,, по классу ,,Опционы FORTS ,,
) смотреть в коде скрипта или в квике ? хотя бы подсказку .
С ув.Андрей
Здравствуйте! В скрипте создается структура (массив) транзакции для отправки на сервер брокера, в ней должно быть поле проверки лимитов, а его там у Вас нет, потому квик и ругается перед отправкой. О том, какие поля и значения должны быть в транзакции читайте в файле справки info.chm (находится в папке с терминалом) в разделе "Совместная работа с другими приложениями" , подразделы: "Формат .tri-файла с параметрами транзакций", "Примеры строк, которые могут содержаться в файле"