Andrei2016 (Все сообщения пользователя)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 След.
разработчикам: отладчик, монитор ресурсов
 
Imersio Arrigo,

нужно уточнить, что не просто для торговли, а для сильно дискретной торговли, но в первую очередь QUIK - это терминал для операций брокера по слежению за клиентскими позициями. Для современных методов динамической торговли его нельзя применять, если, конечно, вас интересует результат вашей деятельности.
OnQuote вешает квик
 
Let_it_go,

вы не сможете решить вашу проблему теми способами, которые пытаетесь использовать. К сожалению, терминал QUIK - это терминал по большей части для нужд брокера, а не физических лиц, торгующих те или иные инструменты. Если вы хотите 100%-й адекватной вашим требованиям работы при нормальной частоте рыночных операций, вам нужно ограничиться только ОДНИМ скриптом и только по ОДНОМУ инструменту. Присоединение хотя бы еще одного скрипта или еще одного-двух тикеров моментально уменьшит вашу производительность процентов на 40.
Сам основной поток терминала в режиме "ТОЛЬКО отражение данных" - т.е. без скриптов, но, возможно, с некоторыми алгоритмами брокера выдерживает одномоментно изменения не более чем по 50 инстурментам. Именно поэтому у брокеров стоит хотя бы 2-3 терминала для отслеживания изменений по разным тикерам. Понятно, что вы не сможете решить ту задачу, которую ставите, никакими ухищрениями. Единственный способ следующий.

1. Пишете не скрипт, а DLL на С++ (можете взять за основу исходники с пакетов на GitHub), которые реализуют в Lua работу с портами  (Sockets). Ваша DLL должна делать всего одну вещь: обрабатывать вызовы OnQuote, OnParam и другие по вашему выбору и передавать содержимое их параметров через внутренний для вашего ПК порт.
2. Пишете полновесное многопоточное приложение на C++, в котором один поток принимает информацию поступившую через порт от вашей  DLL, а другие заняты распределенной обработкой данных.
3. Еще один порт задействуете для отправки терминалу QUIK вызовов sendTransaction().
4. В этом случае вы будете использовать терминал не как рабочую машину, а просто как транзитный передатчик данных. Основной поток терминала в этом случае не будет перегружаться, но я рекомендую вам уменьшить суммарное число отслеживаемых тикеров до хотя бы 48-49.
5. Альтернатива также известна. Как я уже написал выше: "один терминал - один скрипт - один рассчитываемый тикер".
Ошибка при освобождении памяти строк(LUA C API), Unknown error. Possible unhandled exception.
 
Скорее всего, ошибка идет из-за const auto firmid. Попробуйте поставить const char *firmid. Либо прямо указать  delete (char*)firmid.
Не совсем понял, зачем вам удалять по delete объект, который вы по new не создавали. Фактически, вы хотите удалить объект, созданный  через Lua C API? Там же могут быть какие-то еще перекрестные связи, которые вы не отслеживаете.
Кстати, зачем вам вообще удалять firmid? Вы поставили спецификацию const, она в любом случае для этой переменной, не создаваемой по new разместит при работе компилятора firmid либо в стеке, либо в статическом локальном секторе кода программы. Уберите delete[] firmid вообще.
Можно ли одним скриптом луа запустить другой.?
 
Зачем вообще заморачиваться с автозапуском второго скрипта, если можно его запустить вручную? Я могу понять интерес, если бы это реализовывалось парой вызовов стандартными Lua-функциями, но нагромождать кучу сторонних библиотек ради, по сути, одной строки кода - это, на мой взгляд, чересчур.
Если уж очень нужно, чтобы второй скрипт работал в отдельном потоке со своей ВМ, модифицируйте его под ручной запуск стандартной процедурой в терминале и все.
Обновление пользовательской таблицы/окна
 
Sergey Gorokhov,

еще один вопрос.
Вы пишете, что если изменений нет, то OnParam() не сработает. Однако, в документации по терминалу указывается, что обновление таблицы текущих торгов производится с периодичностью, заданной пользователем в конфигурации терминала. У меня задано обновление раз в 5 секунд. Я понимаю это так: каждые 5 секунд QUIK делает запрос на сервер и запрашивает данные отображаемых в ТТТ полей. Да, данные могут прийти и раньше, если обновление информации производится с большей скоростью. Но, в частности, на вечерней сессии эта скорость как-раз сильно падает. И, тем  не менее, OnParam() у меня отрабатывает даже в то время, пока котировки не меняются. Определяю я это как раз по тем самым вызовам message() и записям в таблице сообщений.
Прошу прокомментировать с уточнением порядка функционирования OnParam().
Обновление пользовательской таблицы/окна
 
Sergey Gorokhov,

по поводу типа значений QTABLE_STRING_TYPE - да, действительно оказалась опечатка в одной букве, исправил - заработало.
В этой связи еще один вопрос: чем различаются типы QTABLE_CACHED_STRING_TYPE и QTABLE_STRING_TYPE? В документации о различиях - ни слова. На что влияет замена одного типа другим, в каких случаях?

Относительно срабатывания на OnParam() до вызова цикла в main():
нет, речь идет о том времени, когда таблица уже создана,цикл запущен, скрипт полностью работает и сама OnParam() вызывалась уже не раз. Сегодня на вечерней сессии еще раз проведу тесты.
Обновление пользовательской таблицы/окна
 
PS.
При вызове AddColumn вторым параметром указывается i - номер столбца, пропало ввиду опечатки. То есть верная запись:
       AddColumn(t_id,  i, ("N "..i), true, QTABLE_CACHED_STRING_TYPE, 10)

Также была обнаружена еще одна деталь:
если я при добавлении столбца указываю тип QTABLE_STRING_TYPE - столбец не добавляется, как ни крути. Возвращаюсь обратно к QTABLE_CACHED_STRING_TYPE - столбец появляется.
Обновление пользовательской таблицы/окна
 
Sergey Gorokhov,

мой скрипт вам совершенно не нужен для того, чтобы отследить описанную проблему. Возьмите хотя бы следующий - самый минимальный по размеру скрипт и убедитесь сами.

Код
local t_id, isStopped

local function UserFunc(m)
    for i = 2, 6 do
         for j = 1, 4 do
              m = m + 1
              SetCell(t_id, i, j, tostring(m))
         end
    end
end

local function cb_func(...)
end

function OnParam()
    local y = os.time() % 1000
    SetCell(t_id, 1, 1, tostring(y))
    message("  system table:  y1 = "..y)
    y = y + 20000
    SetCell(t_id, 9, 1, tostring(y))
    message("  system table:  y9 = "..y)
end

function OnInit(...)
    isStopped = false
end

function OnStop(...)
    isStopped = true
end

function main()
    t_id = AllocTable()
    for i = 1, 6 do
        AddColumn(t_id,  ("N "..i), true, QTABLE_CACHED_STRING_TYPE, 10)
    end
    CreateWindow(t_id)
    for i = 1, 10 do
         InsertRow(t_id, i)
    end
    local nx = 0
    for i = 1, 10 do
         for j = 1, 6 do
              nx = nx + 1
              SetCell(t_id, i, j, tostring(nx))
         end
    end
    SetTableNotificationCallback(t_id, cb_func)
    nx = 0
    while (not isStopped) do
         nx = nx + 1
         UserFunc(nx * 100)
         sleep(100)
    end
    DestroyTable(t_id)
end


Существенные особенности:
1) отображение измененной в OnParam() ячейки (1, 1) может произойти почти сразу, но отображение изменения ячейки (9, 1) только после изменения котировки инструмента;
2) лучше всего это видно на вечерней сессии после 19-00, даже после 19-30, когда скорость изменения котировок падает очень сильно, и паузы превышают установленные для OnParam() 5 секунд - они могут быть и 20 - 40 секунд;
3) запись в таблицу сообщений по message() отображается моментально: это говорит о том, что все системные таблицы обновляются сразу же после изменения содержимого хотя бы одной ячейки.

В таблице текущих торгов - только один инструмент (сейчас - BRQ8),  окно котировок также открыто только по этому инструменту, график - тоже единственный. То есть, все ресурсы, которые могут занимать время и увеличивать паузу, - минимальные.
Жду вашего ответа.
Обновление пользовательской таблицы/окна
 
Sergey Gorokhov,

Версия терминала 7.18.1.20.
Насчет кода. Мой скрипт приводить здесь не имеет смысла, он очень большой.
Приведу лишь базовые установки.

1) в функции OnInit() задается таблица, состоящая из 6 столбцов, каждый столбец по значению имеет тип QTABLE_CACHED_STRING_TYPE.
2) после отработки OnInit() управление передается в поток main(), где вызывается функция - назовем ее так - UserFunc(). Вызов функции UserFunc() происходит в обычном цикле while. Кроме нее никаких других вызовов в main() - нет.
3) В функции UserFunc(), вызываемой в цикле с периодичностью 200 миллисекунд, происходит занесение строковых выражений в среднем в ячейки от 5 до 10 строк по - также в среднем - от 2 до 6 столбцов. Занесение значений производится функцией SetCell().
4) При этом присутствует функция OnParam(), которая получает данные при обновлении таблицы текущих торгов через каждые 5 секунд (периодичность установлена мною отдельно в самом терминале).
5) в функции OnParam() также есть установка значений всего в двух ячейках таблицы (пусть, для примера, их координаты (1, 1) и (1,9)).
Обновление пользовательской таблицы/окна
 
Вопрос к разработчикам.

Заметил такую особенность: далеко не всегда обновление пользовательской таблицы/окна происходит сразу же после изменения содержимого одной или нескольких ячеек. Причиной может быть:
1) установленная периодичность обновления пользовательских таблиц - как внутренний параметр терминала QUIK. В этом случае вопрос: какое значение имеет этот параметр (в миллисекундах, секундах или еще каким-то образом измеримый);
2) захват на определенное время контроля за таблицей/окном со стороны основного либо клиентского потока (при вызовах SetCell в разных потоках) с блокированием доступа (и соответственно процедуры обновления) из другого потока. Если да, то вопрос: как можно снять такую блокировку?
3) блокировка обновления самим механизмом функционирования пользовательских таблиц/окон.

Неясно также и то, что именно блокируется: инвалидация области окна или же процесс отображения таблицы в окне.
Прошу дать пояснения.

Еще один вопрос: периодически (особенно в период медленного обновления таблицы текущих торгов после 19-00) происходит отбраковка функции SetCell: функция вовзращает false при стандартном занесении строки в столбец с типом STRING.
Прошу дать ответ на вопрос: в каких ситуациях функция SetCell возвращает значение false и не производит изменение содержимого ячейки. Ситуация с несоответствием передаваемого значения типу столбца рассматривать не нужно: все столбцы имеют тип STRING, при этом передаваемое по SetCell значение - также строковое.
Окно графика со своим таймфреймом
 
Андрей Пахомов,

Из QLua-скрипта вы в терминале QUIK ничего нарисовать не сможете, если не считать неким рисунком наложение заранее заготовленных меток в виде графических рисунков. Если очень нужно иметь возможность рисования через скрипт, то только один вариант: пишете внешнюю DLL, рисующую в отдельном - вне терминала QUIK - окне, и вызываете ее функции. Громоздко и затратно получится, но получится. Правда, имеет смысл только в том случае, если у вас большой объем графического отображения. Иначе только головную боль приобретете и время потеряете.
Использование данных по фьючерсам, вышедшим из обращения
 
Zoya Skvorcova,

огромное спасибо! Как только у брокера появится новая версия, сразу же воспользуюсь.
Использование данных по фьючерсам, вышедшим из обращения
 
Станислав, зарегистрируйте.

Если я правильно понимаю, как работает терминал, то главная проблема именно в исключении необращающихся фьючерсов из списка доступных инструментов. Технически данные графика содержатся в папке архива. Но даже при их нахождении там, в файле, содержащем перечень доступных инструментов после подключении к актуальной сессии идентификаторы и внутренние ссылки исчезают.
Было бы очень хорошо, если бы появился такой функционал:
в панель выбора инструмента добавить еще один раздел "Архив", в котором и появлялись бы те инструменты, срок обращения которых истек, но данные по которым для терминала доступны.
Использование данных по фьючерсам, вышедшим из обращения
 
Прошу прощения, если данный вопрос уже обсуждался ранее.
Вопрос к разработчикам.

Допустим, у меня есть данные по апрельскому фьючерсу, срок которого истек 1 мая. Начиная с 1 мая, подключения терминала к действующим торгам не было, анализ производился на открытом графике и данных апрельского фьючерса в архивных данных терминала. Если я сейчас подключусь к торгам, то QUIK предложит мне заменить апрельский фьючерс майским, при этом из списка доступных для открытия графика инструментов апрельский фьючерс исчезнет, даже если в архивной папке будут находиться его сохраненные данные. Если я откажусь заменить инструмент и решу сделать это вручную, то список доступных инструментов все равно обновится и апрельский фьючерс из него также исчезнет.
Вопрос в том, могу ли я сделать так, чтобы при сохранении архивных данных, подключении к серверу и получении данных по майскому фьючерсу, апрельский фьючерс:
а) не исчезал из списка доступных инструментов;
б) мог быть открыт на графике, на основании архивных данных, даже в условиях открытия в соседнем графике майского фьючерса.

Если ответ "да", то прошу указать, как это сделать. Поиск разъяснений в документации результатов не принес.
Странная типизация результата
 
Suntor, и вы туда же.
Мне что: больше делать нечего, кроме как моделировать странный эффект?
Я вам привел функцию, можете оставить в ней вообще 5 строк и воспроизводить хоть миллион раз. Только, прежде чем соберетесь увидеть этот эффект, увеличьте объем своего программного кода до 200К (без учета объема комментариев) - неважно чем. Вот, тогда и увидите. Это отдельно стоящий, ни с чем несвязанный (ни с какими-либо другими функциями, данными) участок кода. Можете считать его полностью локализованным.
Действие "подпорки" в виде "x=10" однозначно говорит о наличии погрешности при заполнении структуры, отвечающей за идентификацию переменной в Lua. Вопрос в том, из-за чего происходит эта погрешность. Один из возможных вариантов: фоновый вызов сборщика мусора с недостаточной для имеющихся условий частотой. Почему, собственно я и просил разработчиков указать заложенную в текущей реализации терминала частоту вызова сборщика мусора при работающем пользовательском скрипте.
Странная типизация результата
 
Цитата
Suntor написал:
Цитата
Andrei2016   написал:
kroki,
проблема в том, что эффект проявился на 11-м знаке, а не на 17-м:
вместо 2 message выдал 1.999999999991. Это первое.
Второе. Я же четко написал: присваивается операнду ЦЕЛОЧИСЛЕННОЕ значение, т.е. условно "x=10".
Выложите сюда фрагмент кода с ошибкой, чтобы мы смогли его запустить у себя на Quik и воссоздать ситуацию. Тогда быстрее поможем найти ошибку...

Suntor, так я привел его в своем первом сообщении. В том-то и дело, что ничего подобного такому эффекту быть не должно. Поэтомуречь и идет не об ошибке, а об эффекте. Меня же интересовал вопрос, из-за чего может проявиться такой эффект: дважды после присаивания значения integer все происходит идеально, на третий раз - результат не целочисленный, а с плавающей точкой.
Как я понял, ни у кого подобный эффект не проявлялся. Ну. на нет - и суда нет.
Кстати, "подпорку" для решения вопроса я уже соорудил. Вы будете долго смеяться, когда узнаете как. :)
Решение оказалось не менее странным, чем сам эффект:
Перед третьим присваиванием "x = (y-z)*param" нужно добавить еще одно присваивание, скажем так:
"x=10". Все - на этом эффект числа с плавающей точкой в x исчезает, и message выводит нормальное 2.
А теперь, если вы уберете "подпорку", эффект double возвращается на место.
Странная типизация результата
 
kroki,
почитайте на досуге товарища Р.Иерусалимски - создателя Lua - относительно типизации значений и переменных в Lua. И тогда все ваши рассуждения по поводу 14, 17 и 19-го знаков пойдут лесом.
Вам русским языком говорят: ПРИСВАИВАЕТСЯ ЦЕЛОЧИСЛЕННОЕ значение. Понимаете: ПРИСВАИВАЕТСЯ, а не предполагается. Если вам это непонятно, то говорить не о чем.
По поводу очевидных доказательств. Вы предлагаете мне запостить на форуме порядка 200К программного кода? Можете заняться этим сами, если ARQA позволит. Кусок кода, где проявился эффект я привел. Можете искать очевидное или невероятное сколько влезет. Меня же интересовало мнение других, сталкивался кто-либо с таким эффектом или нет. Кто смог сказать что-то по делу, сказал.
Странная типизация результата
 
kroki,
проблема в том, что эффект проявился на 11-м знаке, а не на 17-м:
вместо 2 message выдал 1.999999999991. Это первое.
Второе. Я же четко написал: присваивается операнду ЦЕЛОЧИСЛЕННОЕ значение, т.е. условно "x=10".
Вариант, который вы приводите в качестве аргумента - "local x = 1.000000000000007", изначально содержит число с плавающей точкой, а не целочисленное. Посему к моему случаю ваш пример отношения не имеет.
Относительно остального: речь в принципе идет не о логике вычислений и не об ошибках алгоритма, а о результатах одной и той же простейшей операции с технической точки зрения. Мои опыты показали, при падении объема скрипта до уровня примерно 50К-60К (просто за счет физического убирания нескольких процедур, при оставлении неизменным содержимого сбойной операции), все становится идеально.
То, что QLua в плане своей "аппаратной" (назовем так) реализации существенно отличается от того же Lua for Windows, - это уже и проверенный, и доказанный не только мною факт. Зачем опровергать очеивдное?
Странная типизация результата
 
kroki,
проверяется элементарно через message("x= "..x.."  y= "..y.."  z= "..z.."  param= "..param). Можете убедиться сами.
Речь идет не о сложном или простом коде. Речь идет о том, что происходит одно и то же присваивание результата от оперирования целочисленными значениями три раза: дважды результат - целочисленный, а на третий раз - с плавающей точкой. Вопрос: каким образом это происходит? Повторюсь: нет никаких сторонних операндов или странных преобразований.

Относительно повышения ошибочности скрипта при превышении определенного объема.
К сожалению, не правы вы. Самая простая вещь: присвоение значения элементу таблицы и затем адресация при скрипте , скажем в 30К работает как и должно. При скрипте объемом 300К вы начинаете получать ошибку ровно в том же самом месте. Я это уже проходил, и даже писал об этом на форуме.
При этом заметьте: я веду речь не просто о stand-alone Lua, а именно о трансляции скрипта под управлением QUIK.
Странная типизация результата
 
Михаил, это понятно. Относительно операций, где присутствует, хотя бы теоретическая возможность генерации результата типа double, у меня нет никаких вопросов. Но в описании Lua, в частности, самого Р.Иерусалимски, указано, что условно для пользователя тип конкретной переменной определяется значением, присваиваемым "на лету".
Т.е., пишу я, скажем, x = 3. Да, по факту оно хранится как double (допустим, как 3,000000000001). Но для пользователя это трактуется как 3. И если я проведу сравнение (x == 3), то получу значение true, а не false, как было бы в случае с чистым double/
Если исходить из того, что "условно целочисленное представление" не работает в большинстве случаев с присваиванием чистых значений integer, то тогда вся арифметика, мобильность и логические отношения в Lua летят вверх тормашками.

У меня есть очень сильное подозрение, по аналогии с целым рядом других ситуаций, что эффект, подобный описанному мною, получается из-за ориентированности терминала QUIK на нормальную работу скриптов небольшого размера. Возможно, проблема в накоплении каких-то погрешностей, где-то, может быть, запоздал вызов сборшика мусора. Вобщем, что-то тут есть.
По моим исследованиям, как только скрипт (основной плюс подключаемые через dofile), превышает суммарно некоторый объем, при выполнении скрипта начинаются какие-то совершенно несуразные ошибки.

В этой связи, хочу еще спросить у разработчиков: какой суммарный объем скрипта в килобайтах обеспечивает безошибочную работу в рамках терминала QUIK? То, что есть предел определенный - несомненно. Хотелось бы его узнать поточнее.
А также еще вопрос: с какой периодичностью при выполнении скрипта QUIKв фоновом режиме запускает сборщик мусора?
Странная типизация результата
 
Возник очень любопытный и очень неприятный эффект. Суть в следующем.
Запускаю один единственный скрипт, открыт один график, открыт один источник данных. Сессия закрыта, помех связи нет. Дальше самое интересное.
Есть функция, назовем ее func() такого вида:

local function func()
local x, y, z, param
-- Присваиваются значения переменным y, z, param. Все значения - целочисленные (integer).
x = (y-z)*param  -- результат в x тоже целочисленный
-- некоторые действия, которые не изменяют значений всех четырех переменных
-- Вторично присваиваются значения переменным y, z, param. Все значения - целочисленные (integer).
x = (y-z)*param  -- снова результат в x тоже целочисленный
-- некоторые действия, которые не изменяют значений всех четырех переменных
-- Снова (уже в третий раз) присваиваются значения переменным y, z, param. Все значения - целочисленные (integer).
x = (y-z)*param  
-- результат в x оказывается числом с плавающей точкой (double). Ошибка в расчетах!
end

Эффект проявился впервые. В документации по Lua сказано, что интерпретатор знает, какой должен быть тип у результата арифметической операции, в зависимости от операнда. Здесь же получается, что все операнды - целочисленные, но результат или получается или остается типа double.
Сооружать костыли в виде постоянного использования math.floor как-то не хочется.
Есть ли у кого помимо разработчиков какие-то соображения, почему такое могло случиться? Были ли у кого подобные "фокусы".

PS.
Была бы в Lua четкая типизация данных, такого эффекта не могло бы быть в принципе.
Жаль, что все идет в виде union.
CreateDataSource возвращает пустую таблицу, если использовать параметр param
 
Дмитрий Минеев,

Не совсем понятно, на что указывает ваша стрелка, так как изображение сокращено.
Поясните, что вы хотите сказать.
CreateDataSource возвращает пустую таблицу, если использовать параметр param
 
Дмитрий Минеев,

Указанная вами callback-функция myFunc() и не должна была сработать ни разу.
На момент компиляции строки ds:SetUpdateCallback(myFunc) у вас myFunc содержит значение nil. Поэтому дальше все действия определяются именно этим.
Вам необходимо переместить тело callback-функции, так, чтобы она располагалась в коде скрипта до ее фактического упоминания или вызова.
SearchItems: утечки памяти
 
Сергей,

одна из возможных причин - в создании функции-реферрала внутри другой функции. Не исключено, что в той реализации, которую вы указали, особенности Lua в механизме создания функций и их вызовов приводят к удержанию в памяти огромного количества экземпляров тела функции. Попробуйте вынести функцию-реферрал, которую вы указываете в качестве параметра для SearchItems(), за пределы какой-либо текущей функции или метода (:). Попробуйте оперировать ссылкой на отдельно  стоящую функцию.
Открытие по рынку
 
Lena Po,

1) На срочной секции Мосбиржи - FORTS -НЕТ рыночных заявок, т.е. открывающих позицию по рынку, в принципе. Поэтому для работы на срочном рынке Мосбиржи не пользуйтесь этим типом заявки вообще.

2) Если вы все же выставляете тип заявки как рыночной при работе на FORTS, то в соответствии с руководством  по терминалу QUIK цена должна быть отличной от нуля, выставленной как наихудшая из допустимых. Это связано с тем, что сервер QUIK, который стоит у брокера эмулирует "рыночный" тип заявки посредством выставления серии лимитных ордеров.

3) Еще раз: не пользуйтесь псевдорыночными автоматическими режимами сервера QUIK вообще. Результат - непредсказуем.
Вопрос -пожелание по улучшению сервиса пользовательских таблиц
 
Вопрос-пожелание.

Ранее я уже поднимал эту тему - изначального присутствия столбца с номерами строк в любой таблице, созданной посредством функции AllocTable(). Очень усложняет работу необходимость постоянного уменьшения ширины этого служебного столбца до нуля при каждом запуске скрипта, в том числе, и в процессе его отладке.

Проанализировав таблицы терминала, я пришел к выводу, что во всех случаях используется один и тот же класс, задающий рабочую таблицу. Отличие же пользовательских таблиц, созданных через QLUA, от таблиц собственно терминала только в наличии ряда ограничений по функциональности (de facto, в отсутствии наследования ряда методов класса при создании пользовательской таблицы). Тем не менее, наличие столбца с номерами строк и автоматическая их нумерация - свойство абсолютно всех таблиц терминала, как пользовательских, так и всех остальных. Возможность вручную уменьшить ширину этого столбца до нуля говорит о том, что в конструкторе класса, описывающего таблицу, имеется опция по установке изначальной ширины этого столбца - отличной от нуля, а при дальнейшей работе обрабатывается событие изменения ширины этого столбца с сохранением новой величины в отдельной переменной класса.

В связи с этим повторный вопрос-пожелание.
Прошу добавить в формат вызова функции AllocTable() дополнительный параметр - скажем, ZeroColumnSize, - который может принимать значения 0 и больше нуля. По умолчанию, т.е. при отсутствии указания этого параметра в вызове функции, сохраняется нынешняя последовательность действий в плане создания таблицы - т.е. с некой изначально ненулевой шириной столбца номеров строк. Если же параметр указан, то задается именно та ширина столбца номеров строк, которая указана. Режим формата функции "по умолчанию" обеспечит совместимость созданных к настоящему моменту пользовательских скриптов без необходимости их доработки в части вызовов AllocTable().
Если нет возможности добавить целочисленный параметр функции, то можно сделать вариант, скажем, NoZeroColumn со значениями "true / false", где значение false берется по умолчанию и означает стандартную схему создания столбца с номерами строк. Значение же true будет означать задание нулевой ширины этого столбца.

Если трогать формат вызова функции AllocTable() нежелательно, то прошу добавить в QLUA отдельную функцию, скажем, SetZeroColumnSize(number) или ShowZeroColumn(boolean), которую можно вызвать в любой момент, и которая как раз и будет переустанавливать ширину столбца с номерами строк.
Распределенность обработки вызовов OnOrder
 
Sergey Gorokhov,

Такой вариант я анализировал.
Даже если брать в расчет ситуацию прихода двух вызовов: первый - "сырой" (с отсутствующими uid и trans_id), второй - нормальный (с проставленными uid и trans_id), то в моем скрипте на обработку в теле OnOrder() будет допущен лишь второй вызов, так как первый, ввиду отсутствия uid и trans_id, будет отбракован. То есть, обработка в любом случае будет происходить один раз. До сегодняшнего дня все было нормально: трассировка показывала однократное исполнение OnOrder() в случае, когда flags в пришедшей записи указывает, что заявка снята. Это логично: если заявка снята, то биржа с ней ничего уже делать не будет, так как сама заявка уже отправлена в архив. Что может сделать сервер QUIK, стоящий у брокера, после получения от биржи записи о том, что заявка снята? Если я правильно понимаю, то только одну вещь: поместить заявку в архив как снятую и неактивную и выслать соответствующее уведомление на рабочее место QUIK. Пусть даже это уведомление и будет в виде двух вышеуказанных вызовов - "сырого" и нормального.
Но казус проявился в двукратном срабатывании кода OnOrder(), как если бы ее вызвали одновременно из двух разных потоков..
Распределенность обработки вызовов OnOrder
 
Николай Камынин,

казус произошел именно при выполнении OnOrder(). Массив, в который вносятся и из которого исключаются заявки по order_num, объявлен локальным для всего скрипта, но затрагивается только в OnOrder(). Поток функции main() с этим массивом не работает.
Попробую тестировать еще, так как ранее подобных случаев не наблюдал.
Распределенность обработки вызовов OnOrder
 
Вопрос к разработчикам.

Столкнулся с очень странным эффектом при работе callback-функции OnOrder().
Картина следующая. Работает скрипт, выставляется заявка, отрабатывает. Далее следуют два вызова OnOrder() в ситуации, когда оба раза флаги показывают, что заявка снята. Но двойной вызов OnOrder() на СНЯТОЙ заявке - это еще ладно, проблема в другом.

Суть проблемы.
В скрипте создан массив, куда заносятся номера выставленных заявок. После того, как заявка снята, соответствующий элемент с order_num снятой заявки из массива исключается. СУЩЕСТВЕННО: обе операции - и включение в массив заявки , и исключение ее из этого массива происходят именно в OnOrder(), а не где-либо еще в скрипте.
Трассируя функцию OnOrder(), обнаружил, что почти мгновенно происходят ДВА ее вызова при снятии заявки ( lags показывает, что заявка снята), но при этом оба вызова, проходя через тело OnOrder(), отрабатывают, как если бы в первом вызове не было указано, что заявка на биржевом сервере уже снята, и она с ее order_num не была бы исключена из массива.

Я могу понять такую ситуацию, если допустить что два эти вызова OnOrder() происходят из РАЗНЫХ потоков. Тогда - да, возможна ситуация, что VM LUA еще не успела полностью отработать код OnOrder(), вызванный первым потоком, тогда как сразу же запустилось исполнение экземпляра OnOrder(), созданного для второго потока.
Но разработчики QUIK все время говорят, что ВСЕ вызовы callback-функций со стороны терминала происходят исключительно в главном (т.е. одном и том же) потоке терминала. В этом случае описанного мною эффекта достичь не получится, так как обработка второго вызова OnOrder() для уже снятой заявки произойдет только после полного завершения отработки первого вызова OnOrder(), который априори исключит  данную заявку по ее order_num из массива.

На мой взгляд возможны два варианта:
а) вызовы callback-функций, в том числе и OnOrder(), ДЕЙСТВИТЕЛЬНО происходят из разных потоков терминала, а не только из одного единственного  - главного; при этом очередность вызовов не предустановлена, и тогда руководство по QLUA и комментарии на форуме от разработчиков вводят нас в явное заблуждение.
б) разработчики не знают, какой конкретно поток внутри терминала может в конкретный момент времени - помимо ОСНОВНОГО потока рабочего места QUIK - вклиниться в цепочку вызовов callback-функций. И имеют в виду, что?, к примеру, вызов OnOrder() происходит не строго, а ПРЕИМУЩЕСТВЕННО в главном потоке терминала, что допускает такие вызовы и другими потоками терминала, в том числе и с неуловимой для VM QLUA задержкой по времени вызова.

Прошу разработчиков прокомментировать изложенное, и - либо подтвердить один из вариантов, либо опровергнуть.
Вопрос очень существенный.
OnTransReply(). Вопросы по полям таблицы, передаваемой callback
 
Алексей,

Видимо, разработчики в названии колонки "Код биржи" имеют в виду то, что слово "Код" касается заявки, а слово "биржи" является характеристикой происхождения этого кода. Правильное название должно быть "Биржевой код" или "Биржевой №" в данном случае.
Задержка при обновлении полей в таблице
 
Egor Zaytsev,

переформулирую заданный вопрос:

1. С какой периодичностью и в каком порядке происходит инвалидация области пользовательской таблицы и вызов обновления отрисовки области экрана, занимаемой таблицей пользователя?
2. Каким образом можно принудительно вызвать визуальное обновление пользовательской таблицы при отражении в терминале?

Очевидно, что функция SetCell() не генерирует внутренне сообщение терминала о необходимости перерисовки тела таблицы. В этом случае, видимо, используется механизм автоматического обновления таблиц, допустим, 1 раз в секунду, вне зависимости от того, изменялось ли ее содержимое посредством SetCell() или нет. Поэтому прошу дать ответы на два вышеуказанных вопроса.
Исполнение рыночной заявки
 
Алексей,

Мой вам совет: не пользуйтесь "псевдорыночными" заявками на FORTS, так как результат не предсказуем.
Если вам нужно что-то взять по рынку, воспользуйтесь обычной лимитированной заявкой и все.
OnStop
 
s_mike@rambler.ru,

относительно первой части - т.е. завершения работы при ручном закрытии главного окна скрипта - эти процедуры можно произвести в качестве ответа скрипта при отслеживании сообщения QTABLE_CLOSE, информируя поток с main() об окончании работы.
В случае с завершением по OnStop() - через диалоговое окно - в принципе, вызов тех же самых процедур.

Но, вот, чтобы при закрытии терминала ничего не делать, по идее, необходимо иметь какое-то уведомление о статусе текущего рабочего сеанса терминала. Тогда формально вы могли бы добавить соответствующий фильтр в обработку QTABLE_CLOSE. Однако, в текущей версии рабочего места QUIK, по-моему, нет таких уведомлений. Либо разработчики о них не сообщают.
OnStop
 
s_mike@rambler.ru,

мой личный опыт показывает, что сообщение QTABLE_CLOSE генерируется, если пользователь сам закрывает окно таблицы, созданное скриптом, либо если это делает терминал автоматически при простом закрытии. Но, если вы останавливаете скрипт через сервис терминала (диалоговое окно), то данное событие не генерируется.
Удаление элементов в больших таблицах., Крайне медленная работа table.remove и возможные обходные пути для быстрого удаления большого числа элементов крупных массивов/таблиц.
 
Иван Ру,

вам действительно нужно хранить в памяти все эти десятки тысяч записей?
Я понимаю, когда речь идет о текущей итерации скрипта, но ведь вы храните даже не агрегированные данные, а непосредственно данные по сделкам. Какой в этом смысл, если сделка прошла, условно говоря, 15 минут назад, а за это время вы получили еще 5000 сделок? Если вам необходимо сохранять эти сделки для последующей обработки сторонним приложением, так пишите их сразу в файл, но не сохраняйте в памяти.
Все же мое мнение со стороны (оно может быть ошибочным): необходимо оптимизировать логику скрипта как такового, "облегчая" его.
Ошибка not enough memory, сегодня скрипт впервые упал с такой ошибкой -- как выявить причину?
 
Иван Ру,

1) Попробуйте перед началом работы терминала удалить все файлы из папки терминала с расширением .log.
2) Не оставляйте терминал открытым, если закончили работу. Закрывайте терминал.
3) В скриптах не используйте механизм постоянного и бесконтрольного воспроизводства таблиц ( {} ).
4) Помните, что в первую очередь терминал выполняет свои основные задачи и лишь потом - ваши. Чем "тяжелее" скрипт, тем больше времени он требует, тем медленнее работает терминал и все остальные вызовы.
5) Если у вас действительно ресурсоемкий - с точки зрения объемов обрабатываемых данных - скрипт, то имеет смысл выносить его вовне. Иначе вы в конце концов придете к неконтролируемому торможению собственно работы терминала.

Еще один возможный выход: договоритесь с брокером, чтобы он выделил вам еще одно рабочее место с другим uid, и запускайте его либо на отдельной машине, либо в отдельном процессе.
Проблема с WinRos
 
Присоединяюсь к пожеланию ликвидировать winros.exe и его загрузчик iwr. Пользы - никакой, а помех при работе и задержек  в функционировании терминала создает много. Если уж кому-то так нужен этот модуль, пусть подключают его факультативно.
Частота срабатывания callback-функции для источника данных (CreateDataSource)
 
Sergey Gorokhov,

благодарю за ответ.
Если я правильно понимаю, то по умолчанию из таблицы обезличенных сделок берутся три параметра:
price, qty и datetime, где datetime и price являются основными, связанными с осями абсцисс и ординат графика, а параметр qty предоставляет дополнительную информацию об объеме.

Но вы сказали, что param берется из таблицы текущих торгов.
Правильно ли я понимаю, что из всего перечня параметров таблицы текущих торгов можно использовать для формирования источника данных через CreateDataSource() только те, которые имеют динамический характер на протяжении какого-либо интервала?
Если мы берем интервалы, меньшие чем 1 день, то, скорее всего, можно использовать следующие параметры:
numbids, numoffers, last, qty, value, yield, currentvalue, numcontracts, chngopen, chngclose, sellprofit, buyprofit, tradechange, strike, realvmprice, ichange, pchange. Так или нет?
Частота срабатывания callback-функции для источника данных (CreateDataSource)
 
Sergey Gorokhov,

благодарю за ответы.
Еще один вопрос, касающийся функции CreateDataSource() и создания источника данных.

3. В руководстве пользователя QLUA указано:
"param – необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок, если задан – данные по этому параметру."

В ситуации с таблицей обезличенных сделок механизм обновления состояния бара ясен - при поступлении очередной сделки по инструменту, т.е. при обновлении самой таблицы обезличенных сделок. Описание параметров таблицы обезличенных сделок в Руководстве также приводится. В таком случае возникают вопросы:
3.1. Необязательный параметр param - это один из параметров таблицы обезличенных сделок или же из какой-то другой таблицы?
3.2. В каких случаях имеет смысл пользоваться этим необязательным параметром?
Частота срабатывания callback-функции для источника данных (CreateDataSource)
 
Sergey Gorokhov,

По поводу таблицы обезличенных сделок - ясно.
Переформулирую свой вопрос:
1. С какой частотой происходит вызов callback-функции для источника данных, открытого посредством CreateDataSource()?

а) Каждая новая запись с биржи о совершенной сделке приводит к изменению состояния текущего бара и вызову callback-функции; соответственно, частота вызова совпадает с частотой поступления сделок по выбранному инструменту.
б) Вызов происходит с некой фиксированной частотой, которая не зависит от частоты поступления сделок по инструменту: очередное изменение состояния бара может отражать суммирование данных за 2 сделки, а может агрегировать и 50 сделок, но доступными эти сведения становятся 1 раз в период N секунд,
в) Вызов происходит с переменной частотой, которая зависит от момента накопления очередной порции из N сделок, после чего происходит изменение состояния бара и вызов callback-функции: соответственно, вызов может произойти и уже через 3 секунды, а может лишь по прошествии 30 секунд.

Какой вариант ответа является верным? Если есть дополнения или уточнения, прошу изложить.

Дополнительный вопрос:
2. Возможно ли пользователю терминала регулировать частоту вызова callback-функции для источника данных, открытого посредством CreateDataSource()?
Частота срабатывания callback-функции для источника данных (CreateDataSource)
 
Вопрос в первую очередь к разработчикам.

На данный момент у меня в терминале QUIK стоит настройка "Запрашивать данные каждые 10 секунд". Это означает, что частота обновления данных в терминале составляет не менее, чем 1 пакет/ 10 сек.

Допустим, я создал источник данных при помощи функции CreateDataSource(class, sec, interval). Значение param у меня не задано - соответственно, формирование массива баров происходит на основании таблицы обезличенных сделок.
Вопрос: если сделки по выбранному инструменту происходят с частотой выше, чем 1 сделка / 10 сек. - допустим, по сделке раз в 3 секунды, как поведет себя терминал в плане вызова установленной callback-функции?
а) терминал будет получать данные от сервера QUIK с установленной частотой - т.е. 1 пакет / 10 секунд, - что означает приход за период 10 секунд одного пакета с суммированной информацией по 3 сделкам. И, соответственно, callback будет вызван тоже только 1 раз за 10 секунд;
б) терминал будет получать данные от сервера QUIK с той частотой, с которой на сервер с биржи приходят очередные записи о сделках по инструменту - т.е. в рассматриваемом примере терминал получит 3 пакета за период в 10 секунд и так же 3 раза произведет вызов callback-функции источника данных в моем скрипте.

Какой из указанных вариантов действий является верным? Если есть какие-то особенности или дополнения, прошу изложить.
CreateDataSource возвращает пустой набор данных, Функция CreateDataSource возвращает пустой набор данных, сообщений об ошибках нет
 
Alexegin,

попробуйте после вызова функции CreateDataSource() добавить следующую строку:
if  (not dsData:SetEmptyCallback())  then  message("Server returns no data")  end
Если сообщение у вас появится, вероятнее всего, что проблема на стороне брокера (возможно, "слетели" какие-то настройки либо появились новые ограничения частного характера).
Исполнение рыночной заявки
 
Результат совершенно непредсказуем.

Если на FORTS выставить заявку с типом "M" - т.е. рыночную, то никакого стандартного нормального ордера выставлено не будет. Это уже "изюминка" Мосбиржи, у которой по некоторым причинам  - в отличие от тех же бирж Европы и США - почему-то никак не получается сделать сервис рыночных ордеров. На фондовой секции рыночные ордера есть, а на срочной - никак-с.

По своему личному опыту скажу. Если нужно получить закрытие объема "по рынку", вам придется самому программировать на QLua этои  механизм. Я не рекомендую пользоваться для таких целей эмулятором рыночных заявок с сервера QUIK именно из-за того, что никаких гарантий результата в этом случае Мосбиржа не дает.
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Michael Bulychev,

Возник еще один технический вопрос.
Допустим, с биржи пришла некоторая последовательность записей о состоянии заявок клиентов. Может ли в штатном режиме работы сервера QUIK (обрывов связи либо падения сервера нет) возникнуть ситуация, при которой клиент брокера на своем рабочем месте QUIK получит вызовы OnOrder() не в той последовательности, в которой они получены с биржи, а в иной - в результате каких-либо действий/преобразований на самом сервере QUIK у брокера. Если такая ситуация возможна, то прошу прокомментировать в каких случаях.
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Цитата
Nikolay Pavlov написал:
Добрый день.
По вопросу из #11 поста. Если на у пользователя с uid=102 и у пользователя с uid=107, допустим по классу TQBR, брокер настроил в правах одинаковую Фирму и Код клиента, то независимо от того пользователь с uid=102 или с uid=107 будет подавать заявку, они оба получат ее в "чистом виде", т.е. сначала с полем UID на заявке равным 0, а после с UID пользователя, которым была выставлена заявка. Сервер Quik при рассылке заявок/сделок смотрит не на UID пользователя, а на фирму и код клиента, которые прислал шлюз на заявке/сделке и рассылает ее всем у кого есть права на данную фирму и код клиента.
Nikolay, вы не совсем правильно поняли мой вопрос к разработчикам в сообщении # 11.
Я вначале рассуждал именно так, как вы и описали, однако, затем Егор Зайцев из группы поддержки ARQA в своем ответе на мои вопросы указывает:
Цитата
По второму есть уточнения. Если у пользователя два разных UID, то он получит ответ только на одном UID.
Потому я и спрашивал разработчиков, какой смысл в рассылке "безадресной" (с точки зрения, наличия uid и trans_id) самой первой записи - "фотоснимка" биржевой записи, где есть лишь код клиента для идентификации владельца заявки, - если при наличии у пользователя двух uid эта первая - "сырая" - запись, когда еще сервер QUIK не определил uid и trans_id, попадает только на один из двух терминалов. При этом нет никакой гарантии, что именно на тот терминал, который и отправли заявку изначально.
Случай с теми или иными брокерскими настройками - это частный случай работы конкретного брокера. Поэтому такие случаи я не рассматриваю, поскольку механизм обработки и рассылки пользователям биржевых записей, заложенный разработчиками  QUIK в серверное ПО, - универсальный для всех брокеров и для любых брокерских настроек.

На данный момент у меня уже есть ответ на вопрос 8 из сообщения # 11.  Поэтому на повестке остается лишь вопрос 9 в сообщении # 13.  
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Nikolay Pavlov,

спасибо за комментарий.
Можете ли вы высказать свое мнение по моему вопросу 9 в сообщении #13?
Поясню: речь у меня сейчас идет только о цепочке вызовов OnOrder(), не касаясь вызовов OnTransReply и OnTrade совсем.

---

Уважаемые разработчики QUIK!

Прошу дать ответы на мои вопросы 8 и 9 в сообщениях 11 и 13 данной темы.
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
s_mike@rambler.ru,

во-первых, не совсем понятно о каком сервере вы говорите: о транзакционном сервере Мосбиржи, о распределенных серверах МБ, о сервере QUIK у брокера или еще о каком-то?
А во-вторых, нет никакой Камчатки или Химок в цепочке у моего брокера. Это не вариант общественного WiFi или частной сети. У моего брокера стоит выделенный канал подключения напрямую к Мосбирже. Информация с МБ приходит большими пакетами, или "срезами". И никакой путаницы в стиле "хз куда что пошло" там нет. Речь не идет о сравнительном порядке прихода вызовов разного типа: я не сравниваю пакет об изменении состояния заявки с пакетом о совершении/изменении сделки. Меня интересует один и тот же тип биржевой записи, который приводит к генерации последовательности действий сервера QUIK, отправляющей на мое рабочее место вызов OnOrder().
Вы можете мне детально сказать, как фактически реагирует сервер QUIK в том или ином случае, и что он отправит мне на конечный пользовательский терминал? Думаю, что не можете, поскольку вы не являетесь разработчиком QUIK.
Повторюсь, вопрос конкретный и весьма существенный именно для меня. Я не говорю о ваших нуждах или об общих принципах организации торговли через QUIK. Возможно, вам в ваших алгоритмах вообще без разницы, что, куда и в какой момент приходит, но такая ситуация - ваша, связанная с вашими задачами, а не с моими.  
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Николай Камынин,

я не пытаюсь получить синхронизированную последовательность в вызовах разных функций. Но я хочу получить ответ от тех, кто непосредственно программировал взаимодействие сервера QUIK с биржевым шлюзом и собственно с биржевым сервером, а также взаимодействие рабочего места QUIK и сервера QUIK.
Я бы не задавал вопросов, если бы у меня было прямое подключение к бирже и я получал биржевые данные "as is". Однако, я имею дело даже не с интерфейсом сервера QUIK у брокера, а с удаленным рабочим местом QUIK. Биржа не присылает вызовов OnOrder() и других функций, а сервер QUIK присылает, хотя транслируются они терминалом не так, как поступают, а после некоторых преобразований. Вы можете в этом убедиться очень просто.
Группа поддержки говорит о том, что вначале вызов OnOrder() при любом изменении состояния заявки будет с "сырой" биржевой записью, а потом уже приходит та, в которой проставлены uid и trans_id. Это не так. Самая первая запись, касающаяся только что зарегистрированной заявки, действительно приходит без uid и trans_id. Но во всех последующих вызовах OnOrder() - неважно, сколько их будет суммарно, - ВО ВСЕХ проставлен и uid, и trans_id. Вы можете мне точно сказать, КТО проставляет эти значения, отсутствующие в биржевой записи: сервер QUIK или же уже сам терминал? Думаю, вы не сможете мне дать точный ответ. Мне же до ответа разработчиков ясно одно: то, что приходит к брокеру с биржи и то, что де-факто приводит к вызову на моем рабочем месте функции OnOrder(), - это, как говорят в Одессе, две большие разницы.
Поэтому я и задаю свои вопросы. Возможно, в вашем рабочем алгоритме подобные нюансы не играют роли. Но это зависит исключительно от тех задач, которые вы решаете.
А вариант ответа "Никто ничего не может гарантировать" - это не ответ. Хотя бы потому, что с биржи данные приходят срезами. И если исходить из предположения, что там может быть все  что угодно в каком угодно порядке, то, пардон, это не биржевые данные, а какой-то трэш из соцсетей. Если же мы говорим о биржевых данных, то они структурированы даже на уровне внутренней передачи между главным сервером биржевых транзакций и пулом распределенных серверов, выполняющих разные задачи. Заявка, попадая на биржевой конвейер, проходит предтранзакционный контроль и, если все в порядке, идет на регистрацию. И если я вначале отправляю приказ "снять № 102", то обрабатываться будет вначале снятие именно номера 102, а не 107, если, конечно, по sendTransaction() запрос на биржу о снятии уйдет именно в том порядке, как я и вызываю эти функции.
И когда мне говорится, что возможно и так, и эдак, я понимаю, что речь идет не о биржевой последовательности, а о том, как мне биржевая последовательность будет преподнесена рабочим местом QUIK - третьей, вообще говоря, "ступенью" во всем этом обмене, а отнюдь не первой и даже не второй.  
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Николай Камынин,

поскольку сей анекдот явно недетерминированный, я хочу послушать еще раз.
Интересуют некоторые подробности.
Очередность срабатывания OnTransReply, OnOrder, OnTrade
 
Michael Bulychev,

спасибо за ответы. Но возник еще вопрос:

9) Допустим, программно выставлены 2 заявки: одна с trans_id = 102 в 14-15мск, другая с trans_id = 107 в 14-25мск. Обе заявки зарегистрированы биржей, обе активны. Далее происходит отправка двух транзакций вида "KILL_ORDER": сначала отправлена заявка на снятие активного ордера с trans_id = 102 и сразу же - следующей командой sendTransaction() - на снятие ордера с trans_id = 107.
Вопрос: возможна ли ситуация, что вначале будет снят ордер с trans_id = 107 и лишь затем снимется ордер с trans_id = 102? Или же порядок вызова OnOrder() будет жестко совпадать с порядком транзакций на снятие ордеров: т.е. сначала в любом случае придет вызов OnOrder() с trans_id = 102 и лишь после него OnOrder() с trans_id = 107?
Вопрос весьма существенный, поэтому прошу прокомментировать максимально точно.

И еще: хотелось бы услышать ответ также и по моему вопросу 8, изложенному в сообщении # 11.
Страницы: 1 2 След.
Наверх