Прочитал уведомление "Уведомление в связи с обновлением торговой системы срочного рынка Московской биржи (Spectra 6.3)", где говорится о 19-значных номерах заявок и сделок.
Там было написано так: Внимание! Это крайне важно!
В связи с этим вопросы:
1) Если внутри QLua для номеров заявок и сделок используются переменные числового типа, то появятся ли отрицательные значения в этих переменных?
2) Если появятся, то будет ли корректно работать постановка/снятие заявок через sendTransaction?
Просьба добавить любые другие подробности касательно того, с какими проблемами могут столкнуться роботописатели?
Старатель написал: В какой версии была добавлена ошибка? 7.16 - это последний релиз 7 версии, где нет этой ошибки?
Точно не отслеживал. У меня в какой-то момент при попытке обновиться на более позднюю версию с версии 7.16 вылезла проблема, пришлось откатиться. Так теперь на 7.16 и сижу. В последней версии 7.х терминала ошибка осталась.
У меня была такая проблема. Разработчики больше не поддерживают 7-ю версию терминала. Откатитесь на версию 7.16 (там ещё нет этой ошибки) или перейдите на 8.1 (там уже нет этой ошибки).
А вообще, плохо, конечно, что последний релиз 7-й версии терминала оказался таким вот образом сломан.
Проверил, что будет после обновления до версии 8.0.2.3. Визуально ничего не изменилось, lua-скрипты работают (за исключением тех, что были скомпилированы lua -> luac через Lua For Windows x86; внешние библиотеки я не использую). Заметных ускорений/замедлений или повышенных требований к памяти не вижу. Через некоторое время обновлю боевой торговый компьютер, если на тестовом будет "нормальный полёт" в течение нескольких дней.
Если перезагрузить компьютер и не запускать никаких программ, какая будет загрузка процессора?
У меня был случай, когда из-за какого-то обновления драйвера видеокарты процессор стал грузиться примерно на 20%. При этом было несколько процессов, которые отжирали по 3%-5% CPU и делали какие-то RPC-вызовы. После замены драйвера на старый это ушло, даже после обновления драйвера в Windows Update проблема больше не появлялась. Не исключаю, что возможна аналогичная ситуация, в которой обращение к видеокарте в Windows идёт совсем неоптимально и торговый терминал тормозит. Косвенно об этом может свидетельствовать загрузка GPU в диспетчере задач на Вашем скриншоте.
Исторические данные торгов spbexchange - какого брокера выбрать, Можно ли получить исторические данные торгов Санкт-Петербургской биржи через CreateDataSource
Я через Best Efforts Bank из терминала QUIK получал рыночные данные с Санкт-Петербургской биржи по американским акциям. Время у свечек московское, приходилось к американскому времени специально приводить с учётом переходов на летнее и зимнее время. Не знаю как там сейчас, но раньше не всё гладко было с ценами. Во время американской сессии котировки были адекватные, в остальное время могли быть странные цены.
_sk_ написал: Ходят слухи, что в середине лета появится 64-битная версия терминала QUIK.
Откуда дровишки?
Вот отсюда:
Цитата
Уважаемые коллеги!
В начале июля 2019 года компания ARQA Technologies планирует выпустить Рабочее место QUIK версии 8.0, поддерживающее только 64-разрядные ОС Windows. Уведомляем Вас, в связи с этим, о следующем:
Версии РМ QUIK для 32-разрядных ОС Windows выпускаться более не будут. Текущие версии (x32 6.x, 7.x) будут продолжать работать и смогут подключаться к новым версиям сервера QUIK, но обновлений для этих версий не будет. Прекращается поддержка операционной системы Window XP. Если Ваши сотрудники и/или клиенты используют Window XP или x32-релизы других ОС Windows - рекомендуем донести до них информацию о необходимости обновления в случае, если они заинтересованы получать обновления РМ QUIK.
Имеет смысл завести по одной таблице, индексируемой с 1, для каждого из параметров свечи: open, high, low, close, stdev. Все эти таблицы должны иметь одинаковую длину; забота об этом лежит на программисте. Такой подход приведёт к лучшему использованию памяти по сравнению с одной таблицей candles, в каждой ячейке которой записана таблица с описанием свечи: candles[i] = { open = ..., high = ..., low = ..., close = ..., stdev = ...} В первом случае lua обходится массивами примитивов, а во втором случае в каждой ячейке таблицы candles записывается некий объект, что для большого количества индексов приводит к большим расходам памяти и медленной скорости работы.
Как всегда в программировании: наблюдаем trade-off между удобством и производительностью.
1. "Желаемые позиции" - это чисто алгоритмическая вещь ТС? Например, как вторую ногу поставить при парном трейдинге или арбитраже. 2. Это проверка текущей расчетной позиции в роботе с реальной позицией? Например, в лишний раз куда-то в табличку терминала заглянуть и проверить, правильно ли робот держит позу или он пропустил какие-то сделки, в результате чего его расчетная позиция не совпадает с фактической. Почему тогда много строк кода?
Например, сейчас у робота куплено 200 контрактов (текущая позиция). Закончилась очередная 15-минутная свеча и логика торговой системы говорит, что теперь хочется иметь 300 контрактов (желаемая позиция). В работу вступает модуль исполнения, который, скажем, раз в 5 секунд: - выставляет по цене бид 10 контрактов, - ждёт сделок, если они будут; - снимает заявку, если там что-то осталось; - снова выставляет в бид 10 контрактов (или сколько там осталось, чтобы получилась желаемая позиция). Таким образом, сведение позиций занимает довольно много времени, зато меньше проскальзывание и влияние на рынок. Кроме того, логика расчёта желаемых позиций отделена от логики их достижения.
Цитата
Учитываете ли вы заявки или сделки только на основании OnTransReply() и до срабатывания OnOrder() или OnTrade()?
Информация о заявке берётся из OnTransReply() в обязательном порядке. Список сделок пишется только на основании OnTrade(). Если что-то где-то пропало, выдаются предупреждения. Если у неактивной заявки долго не сходится сумма объёмов по сделкам и разность между объёмом и остатком, выдаётся ошибка.
_sk_ написал: Биржа работает быстро, у нескольких сделок могут микросекунды совпадать.
OnTransReply() лучше использовать. В принципе, можно и без него обойтись, но тогда исполнение заметно замедлится.
Если программируете свой исполнитель заявок, то лучше делайте его корректно работающим, а не компактным.
Вас хотелось бы расспросить больше, чем кого бы то ни было :) 1. что есть такого критичного и необходимого в OnTransReply(), чего нельзя поймать через OnOrder() и OnTrade()?
2. нет ли у вас шаблона робота, который можно просто купить и вставить туда логику? :) Сколько стоит?
1) Детали уже не помню, давно дело было. При программировании мне хотелось: а) использовать как можно больше источников информации, чтобы повысить надёжность системы; б) реализовать быструю систему работы с заявками. В результате получилась хоть и непростая система, зато с коррекцией всякого рода редких ошибок и нетипичных ситуаций, которая работает на полном автомате.
2) Шаблона робота нет. На моей практике кроме менеджера заявок нужен ещё и модуль сведения позиций, который приводит текущие позиции робота к желаемым. Это ещё примерно столько же строк кода. Таких модулей у меня три, каждый со своей спецификой работы с заявками. Продать что-то из кода нет возможности.
Это сколько стоят 2 нефтяных контракта в рублях. Цена нефти при этом указана в долларах. Как эта цифра получается описано в спецификации на сайте МосБиржи.
Вижу сообщения от пользователей, которые утверждают, что используют терминал версии 7.26.0.26. При этом вот тут ftp://ftp.quik.ru/public/updates только версия 7.25 есть. В новостях про 7.26 тоже ничего нет.
Правда ли, что терминал 7.26.0.26 был выпущен "ограниченным тиражом" для отдельных брокеров?
Мне кажется, что проблема производительности решается. Если у вас есть DataSource, и вам надо обратиться к последним 100 свечкам, пишите цикл от ds:Size() - 100 до ds:Size(), чтобы пропустить всё ненужное далёкое прошлое.
Используемый индикатор можно запрограммировать самостоятельно. Это далеко не самое сложное в торговом роботе. Если, к примеру, надо рассчитать какой-нибудь EMA для последних 100 свечей, достаточно начать рассчитывать этот индикатор, скажем, для последних 300 свечей (отступ зависит от периода EMA), т.к. влияние далёкого прошлого мало.
Практика разработки роботов для трейдинга показывает, что расчёты типичных однопроходных индикаторов можно организовать так, чтобы на это тратилось порядка 100-500 мс. Этого вполне достаточно.
Данная проблема вызвана ошибкой в ПО терминала QUIK и будет исправлена в одной из ближайших версий программы. Приносим извинения за причиненные неудобства. В качестве временной меры рекомендуем воспользоваться специальным функционалом экспорта в Excel (Ctrl + L или пункт контекстного меню таблицы "вывод через DDE сервер". Укажите книгу, лист, а так же прочие необходимые параметры вывода и нажмите кнопку "Вывести сейчас".
Я правильно понимаю, что в версии 7.24.1.15 проблема решена, т.е. можно поставить в настройках галочку "Формальное представление данных" и пробелы в числах уйдут?
При этом заголовки столбцов станут английскими. Так и должно быть?
Если есть критичные ошибки либо падения/запуск скриптов за последние 30 секунд, отправляется письмо со списком этих ошибок и смс на телефон, что есть проблемы и надо читать почту. Обычно такие ошибки возникают блоками (несколько писем с интервалами по 30 секунд между ними) по несколько раз в месяц в среднем.
На всякий случай, два раза в день приходят письма со списком работающих скриптов.
Несколько раз в день приходит письмо с оценками P&L портфеля с начала дня для каждого из скриптов.
Письма про проблемы с электропитанием пишет приложение UPS, которое вместе с этим UPS поставляется. Питания хватает на 20-30 минут. Случаев, когда питания не хватало, бывает пару раз в год.
Для отслеживания, что скрипт живой/сдох, можно поступить так: 1) скрипт периодически даёт знать, что он жив; 2) имеется внешний наблюдатель, который просигнализирует о том, что скрипт не дал о себе знать в течение некоторого времени.
Варианты реализации пунктов 1 и 2 могут быть разными. Например, скрипт раз в 5 секунд записывает в некоторый файл текущее время, а наблюдатель раз в 10 секунд читает этот файл и, если записанное в файле время отличается от текущего времени более чем на 60 секунд или не удалось прочитать файл 5 раз подряд, то наблюдатель считает, что скрипт умер и сигнализирует куда-нибудь об этом, например по электронной почте. Вместо файлов и электронной почты можно применять сокеты и смс или ещё что-нибудь.
У нас применяется вариант с файлами и электронной почтой. Наблюдатель реализован в виде консольного java-приложения. Туда же до кучи приделано оповещение об ошибках, возникающих в скрипте: дисконнекты терминала и сервера QUIK, непонятные изменения статусов заявок (например, если заявку выставил робот, а сняли руками), невозможность выставить заявку из-за нехватки средств и др. С какими-то ошибками скрипт справляется сам, но уведомляет об этом, а какие-то ошибки требуют уже ручного вмешательства.
Наблюдателя надо делать как можно более надёжным (внешнее приложение по отношению к терминалу или даже на другом устройстве).
Возможно, что надо ещё наблюдать за наблюдателем, а то ошибки повалятся, а мы не в курсе, поскольку наблюдатель сам сдох.
В дополнение на торгующем компьютере стоит UPS, который шлёт по электронной почте предупреждения об отключении и включении электричества.
В целом, такой самодельный комплекс у нас более-менее работает.
Версия терминала 7.23.2.5 с несколькими запущенными lua-скриптами после нескольких дней непрерывной работы иногда внезапно аварийно закрывается перед началом торговой сессии. Кажется, что это происходит в момент подключения информации по срочному рынку. В папке dmp, куда терминал обычно пишет аварийный дамп, пусто. Вопрос: как, всё-таки, получить дамп? Запускать терминал с каким-то ключом или использовать внешние утилиты от Microsoft? Просьба к разработчикам подсказать решение.
Жаль, что Вы не программист. Если Вы готовы выделять средства сторонним программистам, можете попробовать заказать робота, но я бы посоветовал в любом случае самому изучить QLua, чтобы Вы могли хотя бы разобраться, что понаписали программисты на заказ и как это доделать до нужного Вам состояния.
Примеров роботов, действительно, мало. Такова реальность на настоящий момент.
Нормальная историческая волатильность акций, к примеру, должна находиться в пределах 10-15%. Если же данный параметр превышает 100%, то активы обладают повышенной волатильностью.
Наконец, вот примеры implied-волатильности для опционов на RI и SR с нашего рынка во время девальвации в декабре 2014 года. Данные из терминала на 2014-12-16.
Примеры можно увидеть в "Руководстве пользователя QLua". Там в приложении 3 приводятся примеры обработки событий для таблиц. Дальше всё зависит только от вашей фантазии.
Конкретно мы у себя сделали интерактивное изменение размера капитала, выделяемого торговой системе. Двойной щелчок левой кнопкой мыши на ячейке таблицы уменьшает капитал на 10%, а то же самое правой кнопкой мыши -- увеличивает на 10%.
Код
--
-- Таблица для управления долей капитала, которую разрешается использовать торговой системе.
--
local AmountPercentTable = {}
--- Конструктор.
-- @param self объект
-- @param accountSecurityPositions объект, хранящий данные о позициях
-- @param step шаг изменения величины, задающей процент использования капитала
local function new(self, accountSecurityPositions, step)
local tableId = AllocTable()
local table = {
tableId = tableId,
accountSecurityPositions = accountSecurityPositions,
step = step,
}
setmetatable(table, self)
self.__index = self
AddColumn(tableId, 1, "Счёт", true, QTABLE_CACHED_STRING_TYPE, 15)
AddColumn(tableId, 2, "Объём", true, QTABLE_DOUBLE_TYPE, 15)
AddColumn(tableId, 3, "Процент", true, QTABLE_DOUBLE_TYPE, 10)
SetTableNotificationCallback(tableId, function(tId, msg, rowId, colId)
if tableId ~= tId then
return
end
if msg == QTABLE_LBUTTONDBLCLK and colId == 3 then
local account = GetCell(tableId, rowId, 1).image
local percent = table.accountSecurityPositions[account].percent
percent = percent - step
if percent < 0 then
percent = 0
end
table.accountSecurityPositions[account].percent = percent
SetCell(tableId, rowId, colId, tostring(percent), percent)
end
if msg == QTABLE_RBUTTONDBLCLK and colId == 3 then
local account = GetCell(tableId, rowId, 1).image
local percent = table.accountSecurityPositions[account].percent
percent = percent + step
if percent > 100 then
percent = 100
end
table.accountSecurityPositions[account].percent = percent
SetCell(tableId, rowId, colId, tostring(percent), percent)
end
end)
return table
end
AmountPercentTable.new = new
--- Закрыть окно монитора позиций и удалить все его данные.
-- @param self объект
local function delete(self)
DestroyTable(self.tableId)
self.tableId = nil
self.accountSecurityPositions = nil
self.step = nil
end
AmountPercentTable.delete = delete
local function show(self, caption, windowPosition)
local tId = self.tableId
if IsWindowClosed(tId) then
CreateWindow(tId)
if type(windowPosition) == "table" then
local x, y, dx, dy = windowPosition.x, windowPosition.y, windowPosition.dx, windowPosition.dy
if x and y and dx and dy then
SetWindowPos(tId, x, y, dx, dy)
end
end
end
SetWindowCaption(tId, caption)
local rows = {}
local rowCount = 0
for account, securityPositions in pairs(self.accountSecurityPositions) do
rowCount = rowCount + 1
rows[rowCount] = {
account = account,
amount = securityPositions.amount,
percent = securityPositions.percent,
}
end
table.sort(rows, function(row1, row2) return row1.account < row2.account end)
local tableRows = GetTableSize(tId) or 0
local shouldAddRows = false
if tableRows ~= rowCount then
for i = tableRows, 1, -1 do
DeleteRow(tId, i)
end
shouldAddRows = true
end
for i = 1, rowCount do
if shouldAddRows then
InsertRow(tId, -1)
end
local row = rows[i]
SetCell(tId, i, 1, row.account)
SetCell(tId, i, 2, tostring(row.amount), row.amount)
SetCell(tId, i, 3, tostring(row.percent), row.percent)
end
end
AmountPercentTable.show = show
return AmountPercentTable
В модели Блэка-Шоулса есть время до экспирации, обозначаемое буквой T. Так уж повелось, что T = 1 означает экспирацию через год, т.е. единица шкалы T -- год.
Кроме того, есть волатильность доходности базисного актива sigma, являющаяся безразмерной величиной. Так уж повелось, что опционщики привыкли оперировать с величиной sigma * 100%. С этой точки зрения волатильность, вроде бы, указана в процентах, но при этом вполне может быть больше 100%, если исходное значение sigma > 1.
Не надо переживать, что если волатильность больше 100%, то цена через год станет отрицательной. Этого не допустит модель геометрического случайного блуждания.
Для реализации диалогов и окон мы пробовали использовать библиотеку iplua. Только интерфейс при этом тормозит из-за особенностей многопоточности в QLua в нашей конкретной реализации.
Ещё можно использовать обычные таблицы терминала совместно с событиями нажатия на кнопки мыши. Костыльный вариант, но иногда подходит.
Волатильность измеряется в процентах, приведённых к промежутку в один год. То, что встречаются значения более 100, не приводят к противоречию, т.к. в основе модели Блэка-Шоулса лежит не обычное случайное блуждание, а геометрическое (логарифм цены считается случайным блужданием). Более детально разобраться с нюансами, на мой взгляд, можно только непосредственно изучая модель Блэка-Шоулса. Можно, например, вот это пособие почитать: А. Н. Балабушкин «Опционы и фьючерсы» http://studentam.net/download/opciony_i_fyuchersy_balabushkin.zip
Это и для общего понимания сути дела хорошо подойдёт.
Если в таблице относительно немного колонок, но много строк, то есть способ сильно сэкономить, если хранить таблицу в виде набора колонок. В Вашем примере будет 6 колонок, которые можно реализовать через массив чисел с индексацией с 1. Конечно, надо беспокоиться о том, чтобы в колонках было одинаковое количество элементов. В результате экономия будет существенной, т.к. не будет создаваться хэш-таблица на каждую строку.
Чтобы при рестарте терминала счётчик не сбрасывался, я у себя реализовал такую схему: 1) для значений счётчика выделяется достаточно широкий диапазон чисел от a до b: [a, b); 2) периодически, скажем, раз в минуту, значение счётчика сохраняется на диск в файл; 3) при запросе номера транзакции в скрипте текущее значение счётчика увеличивается на 1 и, если оно становится равно b, то оно приравнивается a; 4) при старте скрипта значение счётчика считывается из файла и увеличивается достаточно большую на величину c и аналогичным образом приводится в диапазон [a, b), чтобы не было пересечений номеров транзакций, которые были посланы после того, как значение счётчика сохранялось в файл.
При такой схеме каждому скрипту выделяется свой диапазон номеров и исключаются повторения из-за сбоев и падений терминала.
Типичные значения в моих скриптах: a = 123 000 000, b = 124 000 000, c = 1000.
Поскольку сейчас планируется сделать номера глобальными для копии терминала, то описанная выше схема потребует выделения всего одного диапазона. Значение c и периодичность записи на диск имеет смысл вынести в конфигурационный файл.