в каких случаях order_date_time == nil в таблице orders
Пользователь
Сообщений: Регистрация: 31.01.2015
03.04.2018 10:34:14
Потому, что вместо order_date_time надо писать datetime. В документации QLua об этом сказано.
order_num == nil и status == 3 в ответ на NEW_ORDER
Пользователь
Сообщений: Регистрация: 31.01.2015
03.04.2018 06:00:49
Подтверждаю, что OnTransReply может не придти. Хотя это бывает очень редко, при сетевых проблемах, но проектировать логику отслеживания статусов заявок надо с учётом этого.
Порядок прихода коллбэков может быть любым. Это тоже надо учитывать.
Расчет стоимости фьючерсов, Как определить программно стоимость позиции или лота "сложных" фьючерсов на индексы и биржевые товары (Ri, BR и др.)
Правда на метод InfoSecurities.isFuturesClass у меня квик что-то ругается : attempt to index global 'InfoSecurities' (a nil value)
Это моя собственная разработка для отделения фьючерсов от всего остального. Можно написать просто classCode == "SPBFUT".
Расчет стоимости фьючерсов, Как определить программно стоимость позиции или лота "сложных" фьючерсов на индексы и биржевые товары (Ri, BR и др.)
Пользователь
Сообщений: Регистрация: 31.01.2015
02.04.2018 10:24:43
Может, я что-то не так понял, но у меня используется код такого типа:
Код
local NaN = 0 / 0
local function getPointsToRublesMultiplier(classCode, secCode)
if InfoSecurities.isFuturesClass(classCode) then
local stepPrice = getParamEx(classCode, secCode, "STEPPRICE")
local secPriceStep = getParamEx(classCode, secCode, "SEC_PRICE_STEP")
if type(stepPrice) ~= "table" or type(secPriceStep) ~= "table" then
return NaN
end
stepPrice = stepPrice.param_value
secPriceStep = secPriceStep.param_value
if stepPrice == nil or secPriceStep == nil then
return NaN
end
local stepPriceInRub = tonumber(stepPrice)
local priceStepInPts = tonumber(secPriceStep)
if stepPriceInRub > 0 and priceStepInPts > 0 then
return stepPriceInRub / priceStepInPts
else
return NaN
end
else
return 1
end
end
Внешний вид диаграмм и настройки шрифтов
Пользователь
Сообщений: Регистрация: 31.01.2015
30.03.2018 05:48:35
Я имел в виду, что настройки шрифта ПО УМОЛЧАНИЮ для диаграмм можно дать в диалоге "Настройки клиентского места". Например, хочет пользователь, чтобы все НОВЫЕ диаграммы были с шрифтом Segoe UI размера 10, а у него каждый раз вылезает Arial 8 и непонятно, где установить такую настройку. Придётся КАЖДЫЙ РАЗ редактировать КАЖДЫЙ новый график.
Как узнать приостановленны ли торги по инструемнту ?
Пользователь
Сообщений: Регистрация: 31.01.2015
29.03.2018 13:42:20
По нормальному и надёжно -- никак. У МосБиржи и есть параметр, транслируемый в ТТП в колонке "Статус" ("status"), где пишется "торгуется" или "приостановлено", бывает (при авариях на бирже), что этот статус остаётся "торгуется", хотя реально всё встало. И биржа особенно не заботится об этом. Если вы влетите на штраф за ошибочные транзакции -- это уже ваши проблемы.
Если инструмент ликвидный и сделки идут часто, можно смотреть, сколько прошло времени с момента последней сделки. Если более, скажем, 60 секунд, значит при выставлении своей заявки надо задуматься, а стоит ли.
В случаях аварий на бирже можно вести аналогичные измерения для классов инструментов. Скажем, если по SPBFUT более минуты нет сделок, а должны быть, то это либо клиринг, либо авария какая-то.
У меня в скриптах отслеживаются как статус, так и таймауты. Отлажено на реальных событиях :)
Внешний вид диаграмм и настройки шрифтов
Пользователь
Сообщений: Регистрация: 31.01.2015
29.03.2018 09:11:21
Берём терминал 7.16.3.14, нажимаем F9 и получаем окно с настройками клиентского места. Там есть пункты Программа -> шрифты, где можно указать шрифты для заголовков столбцов, строк, числовых данных и текстовых данных, а также для окон диалогов. Кнопка "Стандартные" устанавливает везде шрифт Segoe UI.
Однако, тут нет пункта для установки шрифта для диаграмм. У меня диаграммы создаются со шрифтом Arial, который потом можно заменить на Segoe UI.
Кажется, что здесь некоторая недоделка. По-хорошему, шрифт диаграмм также должен быть в настройках клиентского места.
Горячие клавиши
Пользователь
Сообщений: Регистрация: 31.01.2015
23.03.2018 08:38:47
Раз уж QPILE больше не развивается и его всё больше заменяет QLua, давайте перенесём комбинацию Ctrl+F11 с пункта меню "QPILE скрипты" на пункт меню "Lua скрипты". Полагаю, что пользователей, довольных этим нововведением, будет больше, чем недовольных, а реализация от разработчиков терминала практически не потребует усилий.
Один компьютер и несколько брокеров
Пользователь
Сообщений: Регистрация: 31.01.2015
22.03.2018 06:57:27
Создаёте несколько папок типа
Код
D:\QUIK_BROKER1
D:\QUIK_BROKER2
D:\QUIK_BROKER3
В каждую из папок устанавливаете соответствующий дистрибутив программы, рекомендованный каждым из брокеров (версии могут быть разными в зависимости от брокера).
Пользуетесь терминалами независимо друг от друга, возможно одновременно.
Для старта этого достаточно. Если хочется одинаковые настройки в каждом из терминалов, придётся делать дополнительные действия и рисковать несовместимостью wnd-файлов настроек из-за разных версий терминалов.
Размеры окон, создаваемых скриптом
Пользователь
Сообщений: Регистрация: 31.01.2015
19.03.2018 12:09:51
Это не сообщение о какой-то ошибке или проблеме, наоборот, это сообщение, которое может помочь программирующим на qlua скрипты роботов.
Допустим, что Ваш скрипт создаёт одно или несколько окон на своей вкладке. Если не прилагать усилий и просто создавать окна через CreateWindow, эти окна получают некоторый размер и местоположение, определяемые автоматически. Не всегда это удобно. Можно после создания указать конкретное местоположение и размеры окна с помощью функции SetWindowPos(tableId, x, y, dx, dy). Однако, откуда взять значения x, y, dx, dy? Их можно подбирать методом последовательных приближений, но ведь это неудобно!
Предлагается следующий подход. Сначала Вы располагаете графики, окна Вашего скрипта и прочие элементы так, чтобы было удобно. Потом запускаете предлагаемый ниже код. Он создаёт пустое окно, которое можно перемещать и изменять его размер с помощью мышки, накладывая это окно ровно поверх каждого окна Вашего скрипта. При этом в заголовке накладываемого окна динамически обновляются параметры x, y, dx, dy, которые нужно будет подставить в функцию SetWindowPos(tableId, x, y, dx, dy) в Вашем скрипте. При этом подбор параметров можно осуществить сразу, а не методом последовательных приближений.
Вот такой вот калибровщик положения и размеров окон получается.
Если я изобрёл велосипед, а все нормальные программисты пользуются подобными штуками, отнесусь к этому с пониманием.
Код
--
-- Подгонка размеров окна.
--
local interrupted = false
function OnStop()
interrupted = true
end
function main()
local tId = AllocTable()
CreateWindow(tId)
local topPrev, leftPrev, bottomPrev, rightPrev = 0, 0, 0, 0
while not interrupted do
if IsWindowClosed(tId) then
break
end
local top, left, bottom, right = GetWindowRect(tId)
if top == nil or left == nil or bottom == nil or right == nil then
break
end
if topPrev ~= top or leftPrev ~= left or bottomPrev ~= bottom or rightPrev ~= right then
SetWindowCaption(tId, "x=" .. tostring(left)
.. ",y=" .. tostring(top)
.. ",dx=" .. tostring(right - left)
.. ",dy=" .. tostring(bottom - top))
topPrev = top
leftPrev = left
bottomPrev = bottom
rightPrev = right
else
sleep(50)
end
end
end
Обращение к DataSource в main-потоке
Пользователь
Сообщений: Регистрация: 31.01.2015
05.03.2018 11:21:22
Цитата
Делайте через ssort, работает стабильно.
Спасибо за подсказку!
Прикольно наблюдать за тем, как мы, пользователи, натыкаемся на проблемы многопоточности и решаем их, обнаруживая нетривиальные обходные пути.
Цитата
хотя мне бы тоже хотелось функционала из коробки
Солидарен.
Обращение к DataSource в main-потоке
Пользователь
Сообщений: Регистрация: 31.01.2015
05.03.2018 09:35:52
В принципе, ничего не мешает в каждом коллбэке написать проверку типа: если очередь на выполнение, пополняемая из потока main непуста, выполнить функции из неё. У этого подхода есть недостатки: 1) придётся написать в каждом коллбэке строчку, вызывающую работу с очередью функций; 2) если рыночных коллбэков не происходит (например, торги остановились), main не получит требуемый результат, хотя поток коллбэков свободен.
Обращение к DataSource в main-потоке
Пользователь
Сообщений: Регистрация: 31.01.2015
05.03.2018 08:48:34
Просьба к разработчикам терминала обратить внимание на это сообщение и дать свои конструктивные комментарии.
Допустим, что у нас есть экземпляр DataSource, который содержит в себе 5-минутные свечки:
Код
local ds = CreateDataSource(classCode, secCode, INTERVAL_M5)
Если ds используется в потоке коллбэков, то есть гарантия, что пока в коде коллбэка идёт работа с этим экземпляром (например, итерирование по индексу от 1 до ds:Size()), данные внутри него (количество свечей, их high, low, close, volume) не меняются.
Вопрос в том, как добиться стабильности внутреннего состояния в main-потоке? Ведь если я запомню в переменной размер DataSource
Код
local size = ds:Size()
перед началом цикла, то в процессе итерирования могут как добавиться новые свечи, так и обновиться старые (скажем, сначала обновилась последняя свеча, а потом добавилась новая). При этом могут возникать неприятные эффекты типа в потоке main прочитали high последней свечи, потом поток коллбэков обновил свечу так, что новое значение close стало больше уже прочитанного значения high, а потом поток main увидел последнее значение close, которое больше прочитанного ранее high.
Не уверен, что будет происходить с содержимым DataSource при смене торговой сессии, скорее всего, ничего хорошего.
Чтобы гарантированно иметь консистентные данные, можно, например, использовать ds:SetUpdateCallback, в котором заранее производить копирование состояния ds или его изменений в другой объект, и складывать в очередь, разгребая которую из потока main до опустошения, можно всегда получить последнее консистентное состояние ds. Сейчас у меня реализован этот вариант, но кажется, что он излишне нагружает скрипт, т.к. свечки нужны в потоке main раз в 5 минут, а обновление свечей в потоке коллбэков идёт постоянно.
Не уверен, что у меня есть 100% рабочий рецепт получения консистентных данных из DataSource в потоке main, но можно пытаться делать многократное чтение данных, когда параметры каждой свечи с номером i читаются до тех пор, пока не окажется, что ds:Size() не изменился и ds:T(i), ..., ds:C(i) совпадают с прочитанными ранее, после чего полагаем, что свеча i актуальна и можно переходить к следующей.
В более сложных ситуациях подобного рода проблему полностью решил бы следующий подход, когда есть возможность запуска функции в потоке коллбэков с API типа следующего:
Код
ExecuteCallback(function()
-- обращение к данным ds, которое будет произведено в потоке коллбэков
end)
В языке программирования Java в GUI-приложениях на Swing аналогом является вызов
Код
SwingUtilities.invokeLater(Runnable doRun)
Вопросы/пожелания к разработчикам: 1) рассмотреть возможность введения подобной возможности в терминал; 2) либо отказать, либо реализовать в сжатые сроки.
Последняя доступная версия QUIK
Пользователь
Сообщений: Регистрация: 31.01.2015
02.03.2018 07:18:02
Терминал 7.16.3.14:
Разные бары в QUIK и на сайте биржи (MOEX) на фьючерсах на таймфрейме D1.
Пользователь
Сообщений: Регистрация: 31.01.2015
01.03.2018 11:39:46
и самое главное, что делать?
Главное -- понять, что дневная свеча по фьючерсу на Мосбирже строится с 19:00 (вечерняя торговая сессия) до 18:45 следующего дня, и чем это отличается от терминала (с 10:00 по 23:50 в течение суток).
QUIK виснет из-за Таблица изменений параметров
Пользователь
Сообщений: Регистрация: 31.01.2015
17.02.2018 07:32:31
У меня такая же фигня. Если в этой таблице установить курсор на первую строку, то всё нормально. Если же смотреть на последние строки, то получается как у Вас. Я как-то видео этого безобразия записывал и разработчикам отсылал. Только они ничего поделать не смогли.
Если по теме, то кажется, что с рендерингом этой таблицы истории изменения параметров какие-то реальные проблемы.
CreateDataSource, не грузятся данные при формир. через CreateDataSource
Пользователь
Сообщений: Регистрация: 31.01.2015
15.02.2018 12:13:27
Логика ожидания полученных данных из ds (объект datasource, для которого был успешен вызов CreateDataSource), но не более timeout секунд, может быть примерно такая:
Код
local function init(ds, timeout)
local deadline = os.time() + timeout
while os.time() < deadline do
if ds:Size() > 0 then
return true
end
sleep(100)
end
return false
end
Если функция вернула false, значит что-то пошло не так. Таймаут устанавливается пользователем. Я обычно ставлю 15 секунд.
Заявки не были исполнены по непонятной причине, ошибка в работе демо-версии
Пользователь
Сообщений: Регистрация: 31.01.2015
07.02.2018 14:44:38
Форум как-то неинтуитивно реализован, поэтому часто очень забавные скриншоты получаются.
Наверное, в диалоговое окно "Вставить изображение" надо сразу кнопку "Прочитать справку, чтобы не накосячить" добавить.
Ошибка после обновление Windows, Как исправить ошибку , после обновления системы Windows
Пользователь
Сообщений: Регистрация: 31.01.2015
07.02.2018 14:42:04
Если не хватило памяти под объекты, значит надо чаще терминал перезагружать. Не может он справиться с большим объёмом данных и/или внутренние ошибки происходят.
Разработчикам пора в дистрибутив терминала включить вот такой bat-файл, чтобы простыню из нескольких пунктов про то, что нужно удалить, не писать.
Код
del /F /Q acnt.dat
del /F /Q alerts.dat
del /F /Q alltrade.dat
del /F /Q banners.dat
del /F /Q classes.dat
del /F /Q firms.dat
del /F /Q limits.dat
del /F /Q locales.dat
del /F /Q orders.dat
del /F /Q par.dat
del /F /Q portfolio.dat
del /F /Q scripts.dat
del /F /Q search.dat
del /F /Q sec.dat
del /F /Q tmsg.dat
del /F /Q tradermsg.dat
del /F /Q trades.dat
del /F /Q trans.dat
del /F /Q transresult.dat
del /F /Q info.log
del /F /Q portfolio.log
info.exe -clear
Ошибка при чтении стакана
Пользователь
Сообщений: Регистрация: 31.01.2015
07.02.2018 14:38:00
Ещё (у меня очень редко) бывает, что терминал глючит и тогда корректный lua-код начинает работать некорректно. Ощущение, что при долгой или интенсивной работе терминала изредка происходят какие-то внутренние ошибки, после чего ссылки на некоторые функции и поля таблиц портятся. Чтобы этого избежать, перезапускаю терминал раз в 2-3 дня.
Надеюсь, что в Вашем случае это, всё-таки, ошибка программиста, и можно это исправить. Попробуйте переписать код так, чтобы не было вот таких фрагментов:
Код
value.tbl.bid[indexBid].price
а были примерно такие:
Код
local tbl = value.tbl
local bids = tbl.bid
local price = bids[indexBid].price
Это позволит локализовать ошибку и избавит от многократных обращений к таблицам (см. повторяющиеся фрагменты типа value.tbl.bid, это, к тому же, замедляет код).
Также, если indexBid равен 0 или nil, то стакан частично или полностью пустой.
А зачем Вам "дальний край" стакана value.tbl.bid[indexBid].price ? Обычно value.tbl.bid[1].price более важное значение.
Ошибка при чтении стакана
Пользователь
Сообщений: Регистрация: 31.01.2015
07.02.2018 06:40:37
В lua есть 2 функции, pcall и xpcall, для перехвата ошибок, которые могут возникнуть при исполнении кода. Посмотрите в документации к языку lua. Например, здесь даётся описание обеих этих функций.
Я делаю так: если в результате sendTransaction получается результат "", считаем, что транзакция отправлена, будем ждать для неё OnTransReply и OnOrder, иначе рапортуем об ошибке и думаем, что делать дальше (для лимитной заявки слать/не слать новую, для kill-заявки пытаться/не пытаться ещё раз послать kill-заявку).
Когда приходит OnTransReply() / OnOrder(), то разбираемся, что произошло и модифицируем состояние системы. Там логика сложная и в ссылке как-то описана.
Мне сильно помог такой подход: предполагать, что подавляющее большинство транзакций отправлены и обработаны без проблем, а там, где возникли какие-то ошибки, работают "заплатки", разбирающиеся с частными патологиями. Тут всё (OnOrder(), OnTrade() и OnTransReply()) надо использовать.
Реально в коде используется проверка статусов 3, 4, 5 и 13.
> если sendTransaction() возвратил непустую строку, то ошибка, и вызова OnTransReply() не будет.
Вызова OnTransReply() не будет.
> «0», «1» и «15» являются нетерминальными статусами, то есть после их получения будет еще вызов OnTransReply() с другим статусом - так?
Коллбэк OnTransReply() вызывается только один раз. Очень редко, при ошибках сети/сервера/терминала, OnTransReply() может не придти.
Ошибка в контекстном меню, quik 7.14.1.7
Пользователь
Сообщений: Регистрация: 31.01.2015
28.12.2017 13:08:04
У себя проверил. Действительно, надпись "Alt+F4" вместо стандартного для Windows-программ "Ctrl+F4" для закрытия внутренних окон приложения.
Цитата
Можно скриншот, на котором видна проблема?
Вам же русским понятным языком написали о проблеме, которую элементарно воспроизвести.
Отработка OnOrder после остановки скрипта
Пользователь
Сообщений: Регистрация: 31.01.2015
24.11.2017 06:40:00
Цитата
nero333 написал: , а сможете ли вы запустить скрипт из другого потока и, если да, то каким образом?
Скрипт -- это некий код, часть из которого исполняется в main-потоке, а часть в потоке коллбэков. Запускается скрипт кнопкой "Запустить". После этого начинает выполняться код main() и время от времени будут вызываться коллбэки. Фраза "запустить скрипт из другого потока" кажется некорректной.
Ошибка при переподключении к серверу брокера
Пользователь
Сообщений: Регистрация: 31.01.2015
22.11.2017 07:07:08
финамовец, Вам уже пора в командировку съездить в Новосибирск к разработчикам ARQA вместе со своим компьютером. Как вариант -- дать разработчикам доступ через TeamViewer, чтобы они сами всё видели, что Вы видите своими глазами.
nero333 написал: _sk_, спасибо, это хорошая идея, думаю реализовать что-то подобное. Вопрос был к разработчикам относительно кнопки "Остановить", аварийный выход - это всё-таки когда скрипт падает с выводом ошибки в поле "Ошибки выполнения скрипта".
Кнопка "Остановить" это не аварийный выход, а просто остановка скрипта. Принудительная (в Вашем термине "аварийная") остановка происходит не по нажатию кнопки, а по истечении таймаута 5 сек. И это не зависит от того что в это время делает main, что-бы Вы туда не написали скрипт принудительно завершится. Таймаут можно изменить, это делается в return события OnStop (см документацию QLUA.chm) Если Вам что-то нужно снять заявки перед остановкой скрипта, делайте это в самом OnStop
OnStop -- это последний коллбэк, который будет вызван при остановке скрипта. Однако, чтобы корректно сделать всё, что необходимо для снятия отправленных заявок в общем случае, не получится. Например, если транзакция на постановку заявки отправлена, OnTransReply ещё не пришёл, а пришёл OnStop. Как снять заявку, если мы ещё не знаем и не узнаем её orderNum? Никак.
Кроме того, в OnStop делать завершение неудобно, т.к. логика обработки находится в main-потоке.
Именно поэтому нормальная практика прерывания потока в многопоточном программировании состоит в уведомлении другого потока о том, что надо завершить работу. Эта практика и была предложена.
Отработка OnOrder после остановки скрипта
Пользователь
Сообщений: Регистрация: 31.01.2015
17.11.2017 06:28:22
Цитата
nero333 написал: Он не остановит работу, ведь main продолжает работать. Что вы посоветуете сделать, как выйти из main-a только удостоверившись, что все заявки сняты (а это можно сделать только по результатам колбека OnOrder)?
У меня используется следующая схема. Скрипт создаёт окно, где отображается информация о его работе (позиции, прибыли/убытки и др.). Если его закрывают нажатием на крестик в правом верхнем углу окна, то скрипт понимает, что окно закрыто (IsWindowClosed(windowId) == true), поднимает флаг, аналогичный Вашему IS_STOPPING, снимает необходимые заявки, закрывает файлы, в которые шла запись и т.п., после чего завершает исполнение функции main. Получается, что использование крестика в правом верхнем углу окна -- это штатный выход из скрипта, а нажатие кнопки "Остановить" в окне скриптов -- аварийный выход.
Проблема с уровнями Фибоначчи
Пользователь
Сообщений: Регистрация: 31.01.2015
16.11.2017 06:07:56
Не уверен, что после закрытия и открытия терминала проблема с графиками останется. Если останется, то вышлю архив терминала.
Синхронизация между потоком main и потоком, вызывающим OnXxx
Пользователь
Сообщений: Регистрация: 31.01.2015
13.11.2017 11:36:27
Когда ещё был старый форум, там это обсуждалось. Пусть кто-нибудь из представителей ARQA дальше по теме видимости изменения переменных отвечает (даёт ссылку на соответствующее обсуждение или заново тут ответит).
Приведённый мною код работает с конца 2013 года без каких-либо проблем.
Цитата
Моя блокировка отличается от такой блокировке только тем, что разблокировка происходит по уведомлению из другого треда напрямую непосредственно в момент, когда нужно произвести действия.
Конечно, так и надо делать. Только в стандартном Lua для этого нет средств, а в QLua, наверное, через sinsert как-то можно извратиться и реализовать Lock. На практике же повелось так, что в main-потоке большинство пишет цикл, совершающий нужные проверки/действия и засыпающий, если это надо/есть возможность.
Синхронизация между потоком main и потоком, вызывающим OnXxx
Пользователь
Сообщений: Регистрация: 31.01.2015
13.11.2017 10:34:19
Код написан с учетом Ваших опасений
Цитата
В коде выше чтение и запись в submit/get не синхронизированы. Что случится, если вызов будет произведен одновременно на двух родных потоках (мейн и колбек)? Например, колбек вызовет submit, который уже модифицирует очередь при присвеоении, но еще не завершит операцию, а get уже начнет из нее читать?
submit меняет только tail, get меняет только head. И указатели двигаются только в те моменты, когда структура готова. За видимость переменных из разных потоков разработчики QLua уже подумали.
Цитата
Все же, хотелось бы избежать копирования всего и вся из коллбеков в очередь.
Передавайте только те данные, которые нужны. Полагаю, что если использовать что-то блокирующее, у Вас производительность понизится.
Как эвристику можно использовать следующее наблюдение: если при чтении из очереди она оказалась пуста, можно поставить sleep с аргументом побольше, если же непуста, то вообще не вызывать sleep.
Если очередь разгребается быстрее, чем пополняется, то в памяти растёт только массив, на базе которого реализована очередь. Этот массив занимает в памяти относительно небольшой размер, а перезапуск скрипта, который происходит раз в несколько дней, приводит к старту с малого размера массива.
Проблема с уровнями Фибоначчи
Пользователь
Сообщений: Регистрация: 31.01.2015
13.11.2017 10:24:49
Наблюдаю проблему в терминале 7.14.1.7 уже второй раз.
Строим графики цен нескольких инструментов в одном окне на низком таймфрейме (5 мин, например). Накладываем уровни Фибоначчи на график одной из цен. Ждём некоторое время, пока появляются новые свечи и график не сдвинется так, что уже не видно тех точек, по которым уровни Фибоначчи были построен. У меня обычно это наступает на следующий день после построения уровней. Возможно, надо чтобы был рестарт сервера, когда графики исчезают, а потом снова появляются.
В результате видим вот такие два графика. Первый -- это если проскроллировать график цен в прошлое, чтобы были видны точки, по которым строились уровни, а второй -- если проскроллировать график цен обратно. Когда большая свеча уходит из окна, график цен меняет свой масштаб по вертикали и при этом уровни уносит чёрт знает куда.
Первый график:
Второй график: Наверное, надо такое чинить.
Синхронизация между потоком main и потоком, вызывающим OnXxx
Пользователь
Сообщений: Регистрация: 31.01.2015
13.11.2017 07:29:07
Один из вариантов кардинально решить проблему многопоточности при программировании на QLua описан ниже.
В потоке main делаем всю логику торгового робота, а из потока коллбэков только передаём данные в поток main через очередь. Очередь решает задачу синхронизации, коллбэки завершают свою работу максимально быстро, не тормозя UI терминала.
Реализация очереди функций на базе массива позволяет в потоке коллбэков указать, какие данные нужно использовать, и как именно. При получении функции в потоке main остаётся лишь запустить её.
Код
--
-- Реализация очереди из функций и их исполнения.
--
local Executor = {}
--- Конструктор.
-- @param self объект
local function new(self)
local queue = {
head = 1,
tail = 0
}
setmetatable(queue, self)
self.__index = self
return queue
end
Executor.new = new
--- Поместить функцию в очередь на выполнение.
-- @param self объект
-- @param f функция
local function submit(self, f)
if type(f) == "function" then
self[self.tail + 1] = f
self.tail = self.tail + 1
end
end
Executor.submit = submit
--- Получить очередную функцию из очереди.
-- @param self объект
-- @return функция
local function get(self)
if self.head > self.tail then
return nil
else
local f = self[self.head]
self[self.head] = nil
self.head = self.head + 1
return f
end
end
Executor.get = get
--- Выполнять функции из очереди либо пока они там есть, либо пока не будет выполнено указанное количество функций.
-- @param self объект
-- @param max максимальное количество исполняемых за один раз функций
local function execute(self, max)
max = max or 1000000
while max > 0 do
local f = self:get()
if f == nil then
return
else
f()
max = max - 1
end
end
end
Executor.execute = execute
return Executor
Используется это примерно так.
Код
local tradeCounters = {} -- таблица[secCode], содержащая количество обезличенных сделок по каждому инструменту
В потоке коллбэков пишем, например:
Код
function OnAllTrade(t)
executor:submit(function()
tradeCounters[t.sec_code] = (tradeCounters[t.sec_code] or 0) + 1
end)
end
В потоке main пишем цикл, достаточно часто вызывающий функцию execute, т.е. что-то типа:
Код
while not interrupted do
....
executor:execute()
....
end
В результате в потоке main выполнится функция, которую мы задали в потоке коллбэков с данными, которые в тот момент были доступны.
Удачи!
Новый расчет комиссии биржи
Пользователь
Сообщений: Регистрация: 31.01.2015
04.10.2017 09:10:39
Готовы зарегистрировать пожелание по доработке для трансляции точной комиссии, просьба уточнить необходимость данной доработки.
Зарегистрировать нужно обязательно и реализовать как можно быстрее, пожалуйста.
Новый расчет комиссии биржи
Пользователь
Сообщений: Регистрация: 31.01.2015
04.10.2017 07:36:05
Обновление терминала до 7.14.1.7 ничего не изменило. Ждём ответа от разработчиков терминала.
Последняя доступная версия QUIK
Пользователь
Сообщений: Регистрация: 31.01.2015
04.10.2017 07:28:03
Терминал 7.14.1.7:
Новый расчет комиссии биржи
Пользователь
Сообщений: Регистрация: 31.01.2015
04.10.2017 07:23:49
Посмотрел комиссию по SRZ7. Сейчас терминал 7.12.1.10 пишет комиссию 1.22 руб, на сайте 1.18 руб.
Не знаю, у меня в 7.14.1.7 для SRZ7 (сбер) совпадает с рассчитанной и с сайтом = 0.59.
По SRZ7 у меня тоже совпадает. Я писал про SiZ7.
В отчёте от биржи за вчерашний день комиссия за сделку по SiZ7 указана 0.82 руб. В терминале (создать окно -> сделки -> редактировать таблицу + добавить столбцы про комиссию) видим 0.91 руб с утра и 0.92 руб во второй половине дня. В торговых роботах из коллбэков OnTrade приходит комиссия 0.91/0.92 руб.
Настоятельная просьба к разработчикам терминала оперативно пояснить, какая комиссия по SiZ7 правильная? Если проблема в терминале/сервере -- укажите. Если проблема в том, что биржа так транслирует данные -- тоже укажите.
Несоответствие данных -- это критичная ошибка.
Новый расчет комиссии биржи
Пользователь
Сообщений: Регистрация: 31.01.2015
03.10.2017 13:38:43
Сейчас терминал (7.12) транслирует комиссию по SiZ7 равную 0.91 руб/контракт, а на указано, что должна быть 0.82 руб/контракт. Где правда? Это биржа так транслирует данные?
Последняя доступная версия QUIK
Пользователь
Сообщений: Регистрация: 31.01.2015
25.09.2017 14:22:25
Терминал 7.14:
Номера сделок идут не в соответствии со временем сделок
Пользователь
Сообщений: Регистрация: 31.01.2015
12.09.2017 06:12:23
Прикольная ошибка. Время должно быть 195911.999640. Похоже, что из-за округления такое произошло. Кто виноват, биржа или терминал, неясно.
Последняя доступная версия QUIK
Пользователь
Сообщений: Регистрация: 31.01.2015
22.08.2017 14:10:08
Терминал 7.13:
Насколько уникален order_num?
Пользователь
Сообщений: Регистрация: 31.01.2015
22.08.2017 06:21:09
Если торгуете на Московской бирже, то class_code + order_num уникальная комбинация.
Ошибка not enough memory, сегодня скрипт впервые упал с такой ошибкой -- как выявить причину?
Пользователь
Сообщений: Регистрация: 31.01.2015
15.08.2017 05:50:29
Очень хочется, чтобы хоть у кого-то получилось понять, как гарантированно воспроизвести проблемы, подобные описанным выше. У меня не получилось, хотя я даже некий скрипт специально писал и отправлял разработчикам для тестов. Пока не будет чёткого алгоритма воспроизведения проблемы разработчики нам вряд ли помогут, к сожалению.
Ошибка not enough memory, сегодня скрипт впервые упал с такой ошибкой -- как выявить причину?
Пользователь
Сообщений: Регистрация: 31.01.2015
02.08.2017 07:34:57
Цитата
Отключение тиковых графиков проблему не решает, а вот отключение трансляции обезличенных сделок -- по первым ощущения ее устраняет. Мне они категорически нужны, не понимаю что делать.
Похоже, что есть некоторые ошибки в терминале, которые проявляются только под нагрузкой (и, может быть, только в некоторые дни, скажем, связанные с экспирацией или ещё какими-то событиями). Трансляция обезличенных сделок таковой является.
Для минимизации вероятности проблем можно перезапускать терминал каждый день или через день.
Конечно, хотелось бы, чтобы разработчики пофиксили причину, поскольку регулярный перезапуск терминала делать неудобно.
Подсобите с битовыми флагами на примере выяснения позиции из таблицы OnTrade( )?
Пользователь
Сообщений: Регистрация: 31.01.2015
24.07.2017 07:30:51
Если посмотреть внимательно на вопрос, то станет ясно, что он был об обезличенных сделках (OnAllTrade), а не о сделках пользователя терминала (OnTrade).
Не знаю, что надо делать с мордами невнимательных комментаторов.
Отдельные биты, как я понимаю, были сделаны разработчиками терминала из-за того, что в обезличенных сделках, представляющих собой данные по индексам, оба бита нулевые.
Подсобите с битовыми флагами на примере выяснения позиции из таблицы OnTrade( )?
Пользователь
Сообщений: Регистрация: 31.01.2015
24.07.2017 06:57:10
Код
local SELL_FLAG = 1
local BUY_FLAG = 2
function OnAllTrade(allTrade)
...
local buySell = 0
if bit.band(currTrade.flags, BUY_FLAG) == BUY_FLAG then
buySell = 1
elseif bit.band(currTrade.flags, SELL_FLAG) == SELL_FLAG then
buySell = -1
end
...
end
Ошибка not enough memory, сегодня скрипт впервые упал с такой ошибкой -- как выявить причину?
Пользователь
Сообщений: Регистрация: 31.01.2015
24.07.2017 06:53:14
Стандартная схема работы виртуальных машин: 1) выделяем какой-то объём памяти для работы; 2) работаем, периодически вызывая сборщик мусора (мелкая гребёнка); 3) если после сборки мусора осталось мало свободной памяти, выделяем больше памяти (периодическое повышение объёма) и продолжаем работать с пункта 2). Продвинутые виртуальные машины умеют уменьшать объём выделенной памяти, если потребность в ней снизилась. Похоже, что виртуальная машина lua к таким не относится.
Удаление элементов в больших таблицах., Крайне медленная работа table.remove и возможные обходные пути для быстрого удаления большого числа элементов крупных массивов/таблиц.
Пользователь
Сообщений: Регистрация: 31.01.2015
24.07.2017 06:47:31
Судя по написанному, Вам нужно реализовать в своём скрипте циклический буфер (кольцевой буфер) на базе массиве.
В такой структуре данных легко добавлять в конец, удалять из начала и итерировать по элементам. Если в буфере кончилось свободное место, можно увеличить его размер, скажем, вдвое.
Пример реализации на lua (не ручаюсь за качество):