Колбек вызывается по событию и это не значит, что уже загружены все бары. Как минимум мы не знаем как организован вызов колбека в терминале. Может при получении очередного пакета данных, он разбирается и вызывается колбек на данные в нем. Т.е. вызвали для первого пакета, а когда придет условно последний - неизвестно. Понятие "последние данные" очень условно в ситуации непрерывного потока информации. На этом форуме уже много раз спорили, обсуждали эту тему. С тем же успехом можете просто смотреть на n = Size(), и если он отличен от 0, то проверит время бара с этим n. Если время "устраивает" - данные есть.
Владимир написал: Колбек МНОГОКРАТНО вызывается когда наступило событие связанное с данным колбеком
Это не так. Если бы это был колбек по получению нового бара, то да. Но этот колбек по событию: изменение текущего бара. А изменится он может при изменении любого из значений, в том числе и закрытия бара, что происходит при новой сделке. Также и время, что происходит при приходе нового бара. Можно сказать, что нехватает колбека именно на новый бар, да. Но текущий колбек о другом. И по хорошему, я лучше сам проверю Size() чем буду доверять колбеку.
Чтобы получить исторические данные, да и текущие, не обязательно подписываться на колбек. Просто заказали данные, установив пустой колбек через SetEmptyCallback, дождались получения баров с сервера и можете делать с ними все что хотите. Пройтись итератором по ним, совершив действия хоть на каждом баре. А новый бар можно получить просто проверив, что размер Size() стал больше.
Колбек же нужен если надо обрабатывать каждую сделку (точнее каждый вызов, сделок больше может быть) и попутно еще получать данные бара. Но в большинстве случаев это не надо. Да и сделки лучше отслеживать по обезличенным сделкам, а не по колбеку источника баров.
Вы привели пример лямбда функции. SetUpdateCallback в качестве первого аргумента просит ссылку на функцию. Функцию можно объявить в переменную, можно без объявления как лямбду. Кажется в С++ 14 появилось и лямбы и замыкания.
Но Вам необходимо "захватить" переменные, чтобы они были видимы в итоговой исполняемой функции. Делать это можно и так как написали, но лучше использовать более явный подход. Вот на чистом lua:
Код
local function call_back_processor(var1, var2)
return function(index)
print(index, var1, var2)
end
end
local my_call_back = call_back_processor('a', 'b')
my_call_back(1)
my_call_back(2)
my_call_back(3)
my_call_back(4)
Мы создаем замыкание с явной передаче переменных, требующих запоминания меду вызовами.
Для вашего случая можно сделать и через неявную функцию (лямбду):
Если настроено получение потока данных для необходимых инструментов и заданы получаемые параметры, то да. Такая настройка будет не умной, как ее называют в интерфейсе. Тогда можно не открывать ни одной таблица, ни один график. Если параметры не заданы, то можно заказать его через ParamRequest https://luaq.ru/ParamRequest.html
Арифметика арифметика чисел с плавающей запятой работает с некоторой точностью. Поэтому при сложении выходит, например не 2, а 2.0000000001. Необходимо, либо делать свой итератор, либо добавляйте дельту погрешности меньше шага для гарантированного включения числа в перебор.
Задержки. Пока сигнал дойдет до терминала, то уже может быть точка входа неактуальной. Вот если время доставки сократить до 1-5 сек., то возможно, наверно. Но это надо свой web-server и обработку webhook с передачей в терминал.
Читаем: инициализировать переменную Size числом. Функция Size тем самым становится недоступной, точнее переопределенной на число. При повторном выполнении кода, при попытке вызова функции Size(), получите ошибку.
Язык Lua динамической типизации. Поэтому надо быть очень аккуратным с желаниями.
Брокер Сбербанк вчера перестал выдавать информацию при подаче запроса через метод CalcBuySell. Уже было. Приходится временно отключать контроль и переходить на самостоятельный расчет объема сделки или ГО и проверку достаточности средств.
Айдар написал: номер транзакции я сравнивал с пользовательским номером стоп заявки, значит это неправильно?
Нет. Номер стоп-ордера - это его номер. После его активации устанавливается лимитный ордер, номер которого будет записан в таблице стоп-ордеров, в поле linkedorder. Соответственно сделки будут приходить по ордеру с этим номером.
В идеальном мире: При активации стоп-ордера придет колбек OnStopOrder. Для своего стоп-ордера увидите заполненное поле linkedorder. При совершении сделок по этому ордеру придут колбеки OnTrade, где в поле order_num будет тот же номер, что и в linkedorder.
В реальном мире, в теории, колбек OnStopOrder с заполненным linkedorder может прийти после колбека OnTrade. Правда, с учетом того что OnTrade приходит не один раз, то синхронизация возможна.
В любом случае схема такая стоп ордер - linkedorder - ордер с этим номером - сделки по этому ордеру.
Правда при работе с стоп ордерами всегда важно помнить, что стоп ордера - это просто триггер. Он всего лишь отправляет транзакцию при активации. А исполнится ли лимитный ордер или останется висеть неисполненным, или он будет отвергнут ядром биржи - это уже "проблема индейцев". Т.е. это Вы должны контролировать что случилось после активации стоп-ордера. Иначе позиция может так и остаться не закрытой.
Любое клиент-серверное взаимодействие в той или иной мере будет транзакционным. Условно: отправили запрос - ждете ответ - проверка. Только потом следующее действие. При этом таких "транзакций" может быть много параллельно. Например, отправили 100 транзакций, далее ждете по ним ответы. Кто-то ответит первым, кто-то последним.
Поэтому и алгоритм должен быть построен так, чтобы поддерживать такой механизм. Например, создаете сущность "Задача". В вашем случае она будет состоять из двух этапов: снять ордер, поставить ордер. Далее просто выполняете задачу, поэтапно. Если на каком-то этапе ошибка - кидаете исключение и алгоритм принимает решение о том, что делать в этом случае.
Это спорно. Если закрыть глаза на запаздывание графической составляющей, то да. Иногда бары отриосовываются с значительной задержкой. Но если индикатор написан, скажем "криво", то уже вряд ли. Недавно пришлось реализовывать алгоритм по индикатору. Автор решил, что для надежности надо на каждой сделке, т.е. вызове OnCalculate, пройтись по всем барам и поставить значение. Или размер массивов данных - алгоритм требует, например, только значения прошлого бара, но мы зачем-то храним данных для всех баров. Для склейки фьючерсов такой индикатор уже не мало будет потреблять памяти.
Поэтому от ситуации. Впрочем, мое мнение - не стоит. Т.к. надо держать открытыми графики с индикаторами. Нельзя, даже случайно, изменить ТФ, инструмент, параметры при работающем скрипте. Один вариант - есть индикатор с неизвестным алгоритмом. Тогда да, выхода нет.
Про это уже говорилось разработчикам неоднократно, уже много лет назад. Даже не помню когда первый раз. Зачем - так и нет ответа. Видимо, особенность, которая мало волнует большинство пользователей. А это брюзжание скрипто-писателей мало значимо.
EVGEN799 написал: Вы сможете это сделать? Сколько будет стоить и что для этого нужно? Проще на Whatsapp 89163874567
Сделать не проблема, тем более что это уже давно сделано. Но клиент отказался от всей этой затеи, т.к. пытался торговать минутки. Даже небольшая задержка полностью убивает идею. Могу отдать как есть, без поддержки. Ну и как выше написали - зачем TW, если все проще сделать внутри скрипта. И, представляете, есть люди которые не используют Whatsapp, Telegram и другие поделки для сбора информации.
Если не будете использовать TSL (SSL), то можно прямо из скрипта, используя socket библиотеку. Примеров достаточно как это сделать. Либо, если есть собранная библиотека luasec под версию lua и разрядность, то можно тоже прямо из скрипта по защищенным каналам. А если нет, то написать внешнюю программу чтения почты, сохранения содержимого в файлы. В скрипте их читать и разбирать. Вариантов достаточно. А раз уж поднят веб сервер, то можно и web аппликацию написать и развернуть для webhook.
Для этого Вам необходимо поднять Web server, который будет слушать и принимать POST запрос от TW. После этого этот ваш сервер должен оповестить тем или иным способом скрипт. По мне, почта в данном случае - самый надежный и простой способ. Побочный положительный эффект - можете сами отправлять письма на ящик, а скрипт будет их обрабатывать. Такая удаленная ручка для терминала.
Брать данные с графика - это крайний вариант, когда неизвестен алгоритм построения. А когда известно, то зачем. Тем более, что приведенный пример - очень неаккуратный. При этом очень неэффективен по памяти.
А Вы используете этот код как индикатор или как скрипт?
Если как скрипт, то не забывайте передавать поток данных, для которого даже есть переменная ds. Или, возможно, Вы просто переопределили глобальную переменную C, например С = 5. Что делать в индикаторе нельзя. Да и в скрипте тоже, если используете этот код, т.к. (C and C(I))просто проверяет на nil, а уж число там или нет уже не проверяет.
Да делайте как Вам угодно. Я не наблюдаю проблем сортировки для числовых колонок таблиц. Если хотите сортировать как строки, то да, тип строка, как число - число. И проблем с добавлением и тем более удалением строк не наблюдается.
Boris написал: отсортируте массив массивов со СТРОКОВЫМИ ключами в lua - по значению одному из столбцов вложенных массивов.вот может тогда поймёте в чём вывих мозга lua
В чем проблема - пишите свою анонимную функцию и сортируете.
Цитата
Boris написал: У меня есть большой массив данных, который выводится в ВИЗУАЛЬНУЮ таблицу и мог бы быть интерактивно и удобно для пользователя отсортирован в этой таблице - вообще без обращения к функциям lua - чисто уже имеющимся функционалом quik
И это сортируется. Но, как я понимаю, Вас не устраивает как сортируется строковое представление чисел. Так делайте тип колонок числовой (QTABLE_DOUBLE_TYPE или QTABLE_INT_TYPE) и выводите числа, а не строки.
Что-то я не понял про "привыкшего к стройному Си-синтаксису". Lua для сравнения строк использует С функцию strcoll. Ничего не выдумывая http://www.lua.org/source/5.3/lvm.c.html#l_strcmp. Сравнение строк - это всегда, не то чтобы проблема, но, как минимум, повод подумать. Кроме Вас никто не знает что и как Вы хотите от символов 1, 10, 11, 2.
Здесь возникает вопрос о целесообразности хранения чисел как строк. Или необходимости визуализации постоянно сортируемых данных. Впрочем, периодическая сортировка таблицы на 10 тыс. строк. не вызывала какого-то существенного замедления работы.
А если это будет таблица как внутренний объект lua типа 'table', то просто реализовать один из алгоритмов сортировки, удовлетворяющий задаче. Благо сейчас их много есть.
Я понимаю, что штатно терминал эти данные уже потерял, но хотелось бы услышать, что за все эти годы была написана некая утилита, осуществляющая это. HEX редактор как-то неохота привлекать.
Подниму тему. Есть папка archive, в ней есть данные минутного ТФ по контракту RIZ1, т.е. 2021 год. На графике этих данных нет. Как склеить данные и вывести их на график?
Администрация, а это нормально когда движок форума дает авторизироваться по тому же логину, что уже есть (даже если использовали символы другой раскладки)?
Автору: дело в том, что bid_count - это строка. И поэтому ее необходимо привести к числу.
Зачем так усердно бороться с колбеками, когда проще и, главное, надежней самому обрабатывать записи в таблице trades. Хотя, возможно, каждый должен пройти этот путь сам. Мне хватило одного раза, в самом начале, получив все колбеки за день, после восстановления соединения с брокером.
Технология Event-Driven, Asynchronous Callbacks хороша, когда поведение предсказуемо. А когда нет, то я уже как-нибудь сам, по старинке, найду новую запись в таблице.
Плохая затея. Вызов методов только в момент получения данных. Нет вызова - ничего сделать не можем. А как проверить, что все корректно после отправки транзакции вообще загадка, т.к. будет вызов OnCalculate или нет - неизвестно. Т.е. мы закладываем что все всегда хорошо, быстро и исполняется. Но это, как показывает практика, почти всегда не так.
Чем не устраивает файл с списком кодов инструментов и списком параметров для считывания. Читаете файл при старте, а дальше читаете данные по ним. И не надо заполнять ненужные мелькающие таблицы в терминале.
OnQuote - это и есть доступный колбек. Объявленная глобально такая функция будет вызываться на каждый чих в стакане. Т.к. таких изменение очень, очень много, и на каждое изменение вызывается getQuoteLevel2, то память и забивается, т.к. getQuoteLevel2 возвращает две таблицы, две строки. А это не так и мало. И делается это так часто, что сборщик мусора просто не успевает.
Если Вам не нужны данные стакана в каждом срезе без пропусков, то в колбеке надо просто установить флаг, что есть новый стакан по инструменту, а в потоке main его прочитать.
Чистый Lua синхронный, максимум что есть - это корутины. Можно попробовать использовать внешние библиотеки, обеспечивающие асинхронность.
Можете попробовать корутины, вот классчический пример для HTTP, который сразу находится по запросу "Lua socket asynchronous calls": Хотя, наверно, уже пробовали.
Код
function download (host, file, port)
port = port or 80
print (host, file, port)
local connectStatus, myConnection = pcall (socket.connect,host,port)
if (connectStatus) then
myConnection:settimeout(0.01) -- do not block you can play with this value
local count = 0 -- counts number of bytes read
-- May be easier to do this LuaSocket's HTTP functions
myConnection:send("GET " .. file .. " HTTP/1.0\r\n\r\n")
local lastStatus = nil
while true do
local buffer, status, overflow = receive(myConnection, lastStatus)
-- If buffer is not null the call was a success (changed in LuaSocket 2.0)
if (buffer ~= nil) then
io.write("+")
io.flush()
count = count + string.len(buffer)
else
print ("\n\"" .. status .. "\" with " .. string.len(overflow) .. " bytes of " .. file)
io.flush()
count = count + string.len(overflow)
end
if status == "closed" then break end
lastStatus=status
end
myConnection:close()
print(file, count)
else
print("Connection failed with error : " .. myConnection)
io.flush()
end
end
threads = {} -- list of all live threads
function get (host, file, port)
-- create coroutine
local co = coroutine.create(
function ()
download(host, file, port)
end)
-- insert it in the
table.insert(threads, co)
end
function receive (myConnection, status)
if status == "timeout" then
print (myConnection, "Yielding to dispatcher")
io.flush()
coroutine.yield(myConnection)
end
return myConnection:receive(1024)
end
function dispatcher ()
while true do
local n = table.getn(threads)
if n == 0 then break end -- no more threads to run
local connections = {}
for i=1,n do
print (threads[i], "Resuming")
io.flush()
local status, res = coroutine.resume(threads[i])
if not res then -- thread finished its task?
table.remove(threads, i)
break
else -- timeout
table.insert(connections, res)
end
end
if table.getn(connections) == n then
socket.select(connections)
end
end
end
host = "www.w3.org"
get(host, "/TR/html401/html40.txt")
get(host,"/TR/2002/REC-xhtml1-20020801/xhtml1.pdf")
get(host,"/TR/REC-html32.html")
get(host,"/TR/2000/REC-DOM-Level-2-Core-20001113/DOM2-Core.txt")
dispatcher()
Подниму. Сам часто забываю зажимать Ctrl. Кажется, что лучше добавить тип установки цены исполнения: абсолютный и относительный. При выборе относительного задается отступ в указанной величине (шаги, пункты, проценты). Тогда при сдвиге отступ будет рассчитываться при активации.
Сейчас же, забудешь зажать и цена легко уйдет за границы допустимого ценового коридора или выйдет за проскальзывание и стоп ордер становится, по сути, бессмысленным. А пользователь, если не обратит внимание, узнает об этом когда увидит странное - он исполнен, а лимитный ордер висит или отвергнут.