В документации сказано: GetCell Функция возвращает таблицу, содержащую данные из ячейки в строке с ключом «key», кодом колонки «code» в таблице «t_id». Если входные параметры были заданы ошибочно, то возвращается «nil»
В таблице:
image – строковое представление значения в ячейке,
---@param n number
local function money_value(n, sep)
n = tostring(n)
sep = sep or ' '
local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
print(left,num,right)
if not left or not num or not right then return n end
return left..(num:reverse():gsub('(%d%d%d)','%1'..sep):reverse())..right
end
local version = getInfoParam("VERSION")
local bits = version:sub(1, 2) == '7.' and 'x86' or 'x64'
local gSPath = getScriptPath()
local libs_Path = getScriptPath()..'\\clibs_'..bits
package.cpath = libs_Path.."\\?.dll;"..libs_Path.."\\?\\?.dll;"..package.cpath
package.path = gSPath .."\\?.lua;"..gSPath .."\\?\\?.lua;"..gSPath .."\\?\\init.lua;"..package.path
local imap4 = require 'imap4'
local ssl = require("ssl")
local imapServer = 'imap.yandex.com'
local serverPort = 993
local login = 'login'
local password = 'pass'
-- If in doubt, see RFC 3501:
-- https://tools.ietf.org/html/rfc3501#section-6
-- Create new imap4 connection.
-- Port is optional and defaults to 143.
local connection = imap4(imapServer, serverPort, {protocol = 'tlsv1'})
-- If you are connecting to gmail, yahoo or any other server that needs a SSL
-- connection before accepting commands, uncomment this line:
--
-- connection:enabletls{protocol = 'sslv3'}
--
-- You can skip this step by creating the connection using
--
-- local connection = imap4('imap.gmail.com', 993, {protocol = 'sslv3'})
-- Print the servers capabilities.
print(table.concat(connection:capability(), ', '))
-- Make sure we can do what we came for.
assert(connection:isCapable('IMAP4rev1'))
-- Login. Warning: The credentials are sent in plaintext unless you
-- tunnel the connection over ssh, or use SSL (either via the method shown
-- above or calling connection:starttls(params) before logging in).
connection:login(login, password)
-- connection:lsub() lists all subscribed mailboxes.
for mb, info in pairs(connection:lsub()) do
-- connection:status(mailbox, items) queries status of a mailbox.
-- Note: The mailbox name may contain unescaped whitespace. You are
-- responsible to escape it properly - try ("%q"):format(mb).
local stat = connection:status(mb, {'MESSAGES', 'RECENT', 'UNSEEN'})
print(mb, stat.MESSAGES, stat.RECENT, stat.UNSEEN)
end
-- Sel ect INBOX with read only permissions.
local info = connection:examine('INBOX')
print(info.exist, info.recent)
-- List info on the 4 most recent mails.
-- See https://tools.ietf.org/html/rfc3501#section-6.4.5
for _,v in pairs(connection:fetch('(UID BODY.PEEK[HEADER.FIELDS (From Date Subject)])', (info.exist)..':*')) do
-- `v' contains the response as mixed (possibly nested) table.
-- Keys are stored in the list part. In this example:
--
-- v[1] = "UID", v[2] = BODY
--
-- `v[key]' holds the value of that part, e.g.
--
-- v.UID = 10
--
-- `v.BODY' is the only exception and returns a table of the format
--
-- {parts = part-table, value = response}
--
-- For example:
--
-- v.BODY = {
-- parts = {"HEADER.FIELDS", {"From", "Date", "Subject"}},
-- value = "Fr om: Foo <foo@bar.baz>\r\nDate:..."
-- }
print(v.id, v.UID, v.BODY.value)
local txt = connection:fetch('(BODY.PEEK[TEXT])', v.id)
if #txt > 0 then
print(txt[1].BODY.value)
end
end
-- close connection
connection:logout()
Нет, линии не обязательны конечно. Просто старые значения не должны исчезнуть с графика, поэтому вывод линий, пусть даже и одной, должен учитывать это.
RayIntraday написал: Николай, а как можно сделать, что бы ' maxVol ' формировался в процессе, за некий промежуток времени и оставался неизменным, а не расчитывался по уже полученным данным. Я тут пытался поэксперементировать меняя период и отступ, с разными периодами и разными отступами, но результат получился так себе.
График в процессе торгов движется и данные постоянно меняются и пересчитываются, так что такое представление наверное не особо подходит для торговли и анализа. maxVol, это я так понимаю нечто вроде point of control? Было бы здорово, скажем чтобы maxVol, отрисовывался в течении часа, а потом так и оставался на графике. Может вы знаете как это реализовать в коде? Смотрел на гитхабе, у вас там много интересных вещей, но подобного нет.
Сделать можно. Но для этого необходимо сразу инициализировать столько линий, сколько будет отрисовано для всех интервалов.
Для первого часа 100, для второго еще 100 и т.д. Т.е. выделив 1000 линий можно будет отрисовать, скажем, 10 интервалов. Тогда каждый новый интервал инициировать расчет заново и выводить новый пакет линий.
Но даже на 100 линиях индикатор долго применяет настройки.
Другой вариант использовать не линии, а тип вывода бар (TYPET_BAR) или точки. Тогда можно использовать те же линии, т.к. они не будут соединяться между собой. Правда выглядит это уже не очень.
Если речь про замыкание функции, то это делается, чтобы обеспечить сохранность данных между вызовами функции. Также это дает возможность создать несколько экземпляров расчета одного и того-же алгоритма. Допустим, Вам необходимо обеспечить несколько вариантов расчета CCI. Для этого пишется одна такая функция конструктор. Далее ее можно вызвать несколько раз с разными настройками и получить разные функции расчета.
Правда этот пример (и другие из архива) настройки передают при каждом вызове для расчета, хотя конструкция замыкания предполагает, что настройки и ds надо было передать при вызове конструктора CCI, т.к. настройки в процессе работы не меняются. Поэтому их нет необходимости каждый раз передавать как аргумент.
Ну так у стопа две цены - цена активации и цена отправки транзакции в ядро биржи. Стоп ордера живут на сервере брокера, на бирже только лимитки.
Если есть профит, то есть цена активации профита, есть защитный спред (то же проскальзывние) и есть отступ. Вот отступ - это как бы скользящий стоп. Когда профит активировался, то риск модуль брокера начинает следить за ценой, если она опустится на величину отступа, то отправляем на биржу ордер. Если же растет дальше, то ничего не делаем. В теории это дает получить больший профит.
Так это надо тогда сначала разобраться в логике работы стоп ордеров как таковых. Что такое стоп цена, что такое проскальзывание и зачем цена подачи исполняемой заявки должна быть другой и т.д.
Старатель написал: Отдельный поток у вас уже есть - main. Зачем ещё один городить?
Дело в том, что вы так или иначе всё равно лезете в основной поток: GUI, хранилище данных.
Да, но зачем нагружать поток терминала, пусть себе в сторонке что-то делается. Тогда можно было бы и нагруженные модули писать. Сейчас же в основном потоке только данные заполнить в общей области видимости, никаких ожиданий и долгих вычислений.
Ну если уж просить, почему бы не попросить еще один поток для своих колбеков. Т.е. реализовать методы регистрации своих функций обратного вызова и отдельный поток для них, чтобы не лезть в основной поток вовсе.
Если простыми словами - то это функция объект с своей областью видимости. Что дает возможность создавать разные экземпляры функции с своими переменными.
Таймер на любую функцию можно сделать так (пример на чистом lua):
Код
local timer_processor = function(delay)
delay = delay or 0
local last_time = 0
return function(func, ...)
local cur_time = os.time()
if cur_time - last_time >= delay then
last_time = cur_time
return func(...)
end
return ...
end
end
local some_func = function(x)
x = x + 1
print(x)
return x
end
local timer = timer_processor(2)
local a = 1
while a < 5 do
a = timer(some_func, a)
end
Функция some_func вызывается постоянно, но исполняется только каждые 2 секунды - параметр delay. При этом можно создавать несколько таймеров на разные задержки, используя один и тот же конструктор.
Можно также просто сделать некую функцию, в Вашем случае читающую файл, внутри замыкания, а не передавать ее как аргумент.
Колбеки хороши, но их не гарантированность - убивает идею.
У Вас доступны методы прямого перебора таблиц: перед подачей транзакции запоминаете число строк в таблице ордеров, после просто проверяете, что появились новые записи в таблице, проверяя каждую, что это необходимая. Правда если номер транзакции сначала не будет заполнен, то уже возникают сложности. Поэтому можно использовать второй вариант - функция SearchItems. Запоминаете номер транзакции и далее ищете в таблице, когда там появится запись.
Далее, что важно в таком сценарии, вы легко запоминаете индекс в таблице, а значит всегда можете обновить информацию по ордеру, без всякого колбека.
А как сделать обмен в обратном направлении? Из Питона в Квик Квик -> Питон все просто. watсhdog python отслеживает изменение файла. В qlua нет функции отслеживания изменения файла. Спс
Ничего сложного. Открываете файл в режиме чтения и читаете его.
Все зависит от методики обмена, как Вы будете записывать информацию. Одна строка, несколько строк. Возможно надо написать свой итератор перебора строк.
Для примера, можно просто читать последнюю строку файла через:
Код
file:seek("end")
last_line = file:read('*l')
Если появится новая строка, то и при чтении она считается, т.к. директива *l - Reads the line from the current file position, and moves file position to next line.
Скажем |||||||||||||||||||||||||||||||| мелким шрифтом будет выглядеть как линия. Но вот длину придется подбирать опытным путем, т.к. у метки есть только одна координата - начало.
Если число 5 выглядит как целое, но его тип math.type может быть float. Поэтому tostring добавит в представление точку и ноль. Квик такое не принимает в качестве параметра транзакций, где предполагается целое.
Если классическая задача разбиения строки с разделителем на отдельные элементы, то регулярные выражения помогут. В частности итератор string.gmatch или написать свой итератор. Или, если формат постоянный (число параметров постоянно), то string.match.
Для примера string.match для чтения трех числовых параметров, разделенных запятой:
Сделайте замыкание функцию с встроенным таймером, выводящую сообщения. Сможете создавать разные экземпляры на разный интервал. Не будет лишних локальных, а тем более глобальных переменных.
sleep - это заморозить поток, чаще всего это не так и надо выполнять остальные действия.
Время ответа на транзакции - это не детерминированная величина. В ядро биржи уходят лимитные заявки. В ядре биржи всегда будут транзакции атомарны: снять, поставить. При существенной нагрузке на сервера биржи и брокера ответ на команды может приходить совсем не быстро. Мой наблюдаемый рекорд - 12 минут.
Также надо учитывать, что исполнение команд происходит в порядке очереди. Вы не можете гарантировать, что ваша транзакция по установке нового ордера после снятия, будет первой в вашей же очереди команд. Для примера, от Вас идет поток команд, одна из которых сдвинуть ордер. Ядро биржи может обработать команду (и не одну) между снятием-постановкой, если таковые есть. Гарантий достаточности средств, при постановке нового ордера после снятия, нет, т.к. они могли быть заблокированы другими ордерами.
Поэтому контроль перед подачей транзакции будет всегда.
Но для решения данной задачи карман - не самый удобный инструмент. Это надо руками выгружать заявки из таблиц заявок, при этом фильтруя исполненные. А в карман загружать из этого файла. При этом как-то очищая дубли, если заявка уже есть в кармане.
spy написал: Подниму старую тему, т.к. вопрос по ней: при выставлении заявки нужно ли вручную приводить цену к шагу цены? Допустим, шаг цены инструмента 0,01 - выставится ли лимитная заявка с некратной ценой вроде 75,1234? И если да, то в какую сторону будет округлена фактическая цена?
Необходимо привести цену к шагу. Если это не делать при подаче транзакции будет получена ошибка.
Владимир написал: Nikolay, Нафига дамп? Нафига хранить всю информацию в самой таблице? Хранить сколько-нибудь важные данные в таблицах Квика могут разве что камикадзе - нужно хранить в таблицах Lua. А таблицы Квика только для визуализации данных для юзера и обработки событий от него же.
Люди разные. У Вас привычка навязывать мнение, но это не значит, что нельзя делать по-другому. Впрочем, я отметил, что хранить в самой таблице - это не лучший вариант.
Можно ли переформировать без потери данных в таблице? Или нужно перезаполнять и соответствующую таблицу тоже?
Сделайте дамп таблицы в структуру и перезаполните ее. Такой механизм обычно нужен всегда, чтобы реализовать перезапуск скрипта без потери информации. Можете хранить всю информацию в самой таблице и тогда становится важным делать своевременный дамп или можете хранить всё в некой структуре в памяти, позволяющей восстанавливать состояние, что более предпочтительно.
Столбцы добавляются до формирования окна. Это его структура, типы данных, ширина. После формирования окна столбец уже не добавить, необходимо переформировать окно.
Владимир написал: Самый надёжный способ - не запускать ничего автоматом. Более того, когда я перезапускаю Квик (после какой-то страшной ошибки, когда он отвисает), мой скрипт стартует автоматом (поскольку не был остановлен перед выходом), и я его немедленно останавливаю, чтобы ничего не натворил. А потом спокойно запускаю, когда Квик обновит свои таблицы (на мой взгляд, он неприлично долго это делает), и в ТТТ что-то там начнёт мельтешить - торговля пошла.. Я бы вообще запретил автомат. Вы сами ищете приключений на свою задницу, господа. Это У ВАС "ку-ку система получается". Впрочем, деньги ваши - развлекайтесь...
Если у Вас задача быть постоянно "привязанным" к терминалу, то можете действовать и так. Но многие запускают скрипт на VPS и смотрят, что происходит раз в день, а то и реже, когда скрипт пришлет какое-то оповещение. Поэтому скрипт должен успешно стартовать вместе с терминалом, а также корректно работать если терминал не выключается вовсе.
У меня несколько другая ситуация. Есть lua-скрипт, который стартует вместе запуском программы quik и создает окно-таблицу. Если, после авторизации, quik показывает диалог с запросом замены истекающего фьючерса на новый и ответ на него утвердительный, то происходит "как-бы переоткрытие" видимых в этот момент таблиц. Их окна закрываются и тут же открываются вновь. А окно-таблица созданная lua-скриптом тоже закрывается, но вновь уже не отрывается. Из менеджера окон пропадает, хотя сам lua-скрипт работает. Приходится его останавливать и запускать по новой. Ведь так быть не должно?
Вам надо создать метод контролирующий наличие окна. Если его нет, и это не команда пользователя по его закрытию, то переоткрыть и перезаполнить его. Должно ли быть так или нет - сложный вопрос. Окна терминала переоткрываются, т.к. они в его оконной модели и он их контролирует. А окно скрипта нет. Терминал не знает о его составе и наполнении.
Владимир написал: Nikolay, ЧАВО?! Во-первых, В МОИХ базах данных, как правило, ОДНА таблица (неоднородных кортежей). :: Во-вторых, какое отношение имеет открытие таблицы к визуализации? ТТТ - это ХРАНЕНИЕ данных в терминале, а никакая не "визуализация". И доступ к ней как раз "ракообразный", через getParamEx, а не getItem, скажем. Разумного объяснения сему факту лично я найти не могу. Привязка же доступа к графикам - это КРЕТИНИЗМ! АДНАЗНАЧНА!
... ТТТ - это ХРАНЕНИЕ данных в терминале ... оставлю без комментариев
"Во-вторых, какое отношение имеет открытие таблицы к визуализации?" Вы таблицу зачем открываете? Смотреть глазами? Не надо смотреть, то зачем открывать. А если смотреть, то какие претензии к термину "визуализация".
Доступ к данным параметров корректный. Обычный запрос на получение данных key-value по ключу параметра.
Пример: База данных. в ней много таблиц. Пока не откроешь таблицу, т.е. визуализируешь данные, прочитать из таблицы ничего нельзя. Очевидно, что так это не работает.
ТТТ - это визуализация данных в терминале. Но ее можно и не открывать, т.к. key-value, связанный с этой "таблицей", находится в памяти и доступен для чтения через публичные методы. Поэтому есть необходимость реализации методов для всех, так называемых "таблиц" Квика.
Привязка же к графикам - это просто один из методов, считывания информации с этого графика, со всеми вытекающими проблемами. И зачастую, используется не для получения данных баров (свечек).
Необходимо еще учитывать то, что при старте терминала индикаторы не могут инициализироваться одновременно. Текущий запустился первый, а два других, с которых данные считываются - еще нет. Или в другой последовательности.
Я по ошибкам вывожу строку текста через debug.getinfo(2), а в assert есть имя функции, аргумента, чтобы в тексте ошибки было имя. Часто этого достаточно для понимания что и где. Правда если скомпилировать без отладочной информации, что всегда и делается, то информация теряется. Для этого, как раз в assert имя функции и прописывается. Если же это для каких-то логических целей, то лучше не через debug.getinfo решать вопрос, конечно.
Постоянный спор. Вот это "Грубо, узнать когда количество загруженных строк в таблице будет равно количеству на сервере в том состоянии которое есть в данный момент." было бы полезно. Получать событие когда количество строк в таблицах futures_client_limits, money_limits, depo_limits на сервере и клиенте стали разные и обратно одинаковые. Правда само число строк мало о чем говорит, если только это не очистка и заполнение.
Кажется, гораздо проще было бы добавить в руководство описание полей и поддерживать его актуальность. Что вполне естественно. Впрочем, такие пожелания были неоднократно.