51

Re: Обмен данными между Lua-скриптами в QUIK

Апну старую тему. В сообщении https://quik2dde.ru/viewtopic.php?pid=476#p476 уважаемый swerg писал:

"Ограничения:
передача данных между разными скриптами только в пределах одного процесса, т.е. одного QUIK;"

Это чье ограничение и можно ли его как-нибудь обойти? А если 2 квика? А если квик и внешний скрипт, например, (не к ночи будь помянут) на python?

52

Re: Обмен данными между Lua-скриптами в QUIK

michael.s пишет:

"Ограничения:
передача данных между разными скриптами только в пределах одного процесса, т.е. одного QUIK;"
Это чье ограничение и можно ли его как-нибудь обойти? А если 2 квика? А если квик и внешний скрипт, например, (не к ночи будь помянут) на python?

Это ограничение реализации. Всё хранится только в рамках одного процесса.
Обмен между несколькими квиками сделать так и не собрался.

Что касается питона - то вот только что были про него сообщения.

53

Re: Обмен данными между Lua-скриптами в QUIK

Уважаемый swerg, ждем-с StaticVar под х64.
Если можно, то сразу поправьте SetVarList и GetVarList:
t={1,2,3,4}
stv.UseNameSpace("")
stv.SetVarList(t) ==> invalid key to 'next'
------
stv.SetVar(1, 1)
stv.SetVar(2, 2)
stv.SetVar(3, 3)
stv.SetVar(4, 4)

local t=stv.GetVarList() -- преобразует числовые ключи в строчные
message(tostring(t[1])) ==> nil
message(tostring(t["1"]))==> 1

54

Re: Обмен данными между Lua-скриптами в QUIK

kalikazandr пишет:

ждем-с StaticVar под х64.

Сделано, архивы обновил, ссылки во втором посте темы.

55 (2019-07-18 21:21:41 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

kalikazandr пишет:

Если можно, то сразу поправьте SetVarList и GetVarList:
t={1,2,3,4}
stv.UseNameSpace("")
stv.SetVarList(t) ==> invalid key to 'next'

В таком формате и не обещалась работа.
Если требуется именно таблицу сохранить и восстановить в целостности - то

t={1,2,3,4}
stv.SetVarList("somename", t)
....
stv.GetVarList("somename", t)

Так в справке и написано же:
SetVarList(table)  -- из переданной в качестве аргумента таблицы формата ["var_name"]=var_data заполняет данные с указанными именами


kalikazandr пишет:

stv.SetVar(1, 1)
stv.SetVar(2, 2)
stv.SetVar(3, 3)
stv.SetVar(4, 4)

local t=stv.GetVarList() -- преобразует числовые ключи в строчные
message(tostring(t[1])) ==> nil
message(tostring(t["1"]))==> 1

Ну так-то тоже всё по справке:
GetVarList()  -- возвращает таблицу формата ["имя_переменной"]=значение

Ну т.е. Set / Get (в том числе SetList / GetList функции) подразумевались именно как сохранение неких именованных (текстом) переменных (первый параметр), а не сохранение честных таблиц Lua. Таблицы корректно сохраняются из второго параметра,  с учётом всех типов.

Так что тут вопрос всё же идеологии.

Другое дело, что, быть может, имеется смысл поменять формат обращения так, чтобы это выглядело как обращение к некой "глобальной таблице", видимой отовсюду. Про это да, есть идеи, но надо продумать как это должно выглядеть.

56

Re: Обмен данными между Lua-скриптами в QUIK

Может придет какая идея у вас.
Делаю так (и это не очень удобно и затратно по времени).
Бот формирует заявку(и) с уникальным id(string), и своим торговым алгоритмом и событиями (у каждой заявки может быть свой алгоритм в рамках одного бота).
Заявка(smartorder) после своего формирования переключает пространство имен:
stv.UseNameSpace(id)
и накатывает свои параметры:
stv.SetVarList(smartorder)

После чего, бот регистрируется в пустом пространстве имен: ["bot_name"] = {id_list}.
Таким образом любой бот получает доступ не только к любому боту, но и к конкретной заявке и может отправить, заявку с нужным id минуя ее торговый алгоритм или отдать приказ этой заявке, скорректировать позицию, например.

Изменения значений в заявке отслеживаются и обновляются
stv.UseNameSpace(id)
stv.SetVar("price",64.3)

Гуи считывает пустое пространство имен, получает список ботов, список заявок и в таймерах опрашивает заявки, на предмет изменений.

Иногда возникает ситуация, когда умная заявка генерирует еще несколько дочерних заявок, пирамида, сетка и т.д.
И вот такие заявки удобно хранить внутри самой заявки в списке:
smart.posa = 1
smart.plan = 1
smart.price = 64.5
smart[1] = {balance=5, plan=5, price=64}
smart[2] = {balance=10, plan=10, price=63.5}

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

Было бы удобно иметь возможность прописать не ссылки на поля заявки в пространстве имен, а сразу наследовать туда от класса заявку с методами.
Тогда я бы сделал 1-го бота, который подписался бы на все события и сразу дергал метод нужной заявки напрямую. Сейчас в каждом боте дублируются OnOrder и прочее, что не есть гуд при большом кол-ве ботов.

57 (2019-07-19 10:19:28 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

Возможно я не все понял, но я бы предложил не маяться с пространствами имён, а пойти таким путём.

smart.botname = "bot_name"  -- если имя бота вообще требуется - сохранить его как один из параметров
smart.posa = 1
smart.plan = 1
smart.price = 64.5
smart[1] = {balance=5, plan=5, price=64}
smart[2] = {balance=10, plan=10, price=63.5}

Далее
Бот формирует заявку(и) с уникальным id(string)

stv.SetVar(id_заявки, smart)   -- id_заявки - уже строковое!

Где-то надо получить параметры бота (и возможно поправить), зная id заявки - не проблема:

smart = stv.GetVar(id_заявки)
smart.price = 65.5  -- новое значение
stv.SetVar(id_заявки, smart)

Где-то надо просто перебрать все имеющиеся заявки:

allOrders = stv.GetVarList()

получили таблицу allOrders в формате:
["id_заявки1"] = {таблица с параметрами заявки, включая "bot_name"}
["id_заявки2"] = {таблица с параметрами заявки, включая "bot_name"}
и т.д.

Таблицу allOrders можно проитерировать, посмотреть/отобразить параметры всех заявок.
Можно даже поменять параметры каких-то заявок и все скопом потом записать назад как

stv.SetVarList(allOrders)

58 (2019-07-19 12:30:43 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

Кстати, при изготовлении скрипта для тестирования библиотеки наткнулся на подвох с пространствами имён, про который я как-то не думал.
Схема примерно такая проблемы:

-- main() --                 |
                             |
stv.UseNameSpace("AA")       |
stv.SetVar(...)              |
stv.SetVar(...)              |
....                         |
.... тут  ...                |
.... что-то ...              |   -- параллельно сработал callback (OnOrder, например) в основном потоке --
.... делаем ...              |   ....
.... нужное ...              |   stv.UseNameSpace("BB")
....                         |   stv.SetVar(...)
....                         |   stv.GetVar(...)
....                         |   ....
....                         |
....                         |
a = stv.GetVar(...)  <-- на этот момент у нас уже переключено пространство имён на "BB"
                     <-- (переключено оно было в коде callback'а),
                     <-- а не "AA", как мы его устанавливали в main(),
                     <-- но мы  про это не знаем и узнать не можем!!

Понятно, что в переменной a из main()  после этого  будет ерунда, данные не из того пространства имён, какое ожидалось  в коде функции  main().

Наверное надо будет доработать логику: выбор пространства имён сохранять и использовать в контексте номера потока, из которого вызваны GetVar / SetVar.

Имеет место быть такая проблема, как думаете?

59

Re: Обмен данными между Lua-скриптами в QUIK

swerg пишет:

Имеет место быть такая проблема, как думаете?

Приветствую, я чуть ранее об этом писал, что StaticVar не потокобезопасен и такая проблема есть.
Вообще, в рамках квик, плохая практика работать в разных потоках, т.к. в main простой опрос таблиц видит событие раньше, чем будет вызван соответствующий calback в 90% случаев.
По этому событие из calback-ов обрабатываю в main.

Ваше предложение по архитектуре nsp я пользовал раньше, в итоге, более удобно не загружать весь смарт в nsp, а переключаться на nsp заявки и менять 1 значение, либо накатывать сразу несколько значений:
stv.UseNameSpace("AA")
stv.SetVarList({price=64.3,plan=10,BS=true})
Это удобно, так же и для gui, где 1-н tabsheet в таймере опрашивает конкретную стратегию, а не все стратегии сразу.

60

Re: Обмен данными между Lua-скриптами в QUIK

kalikazandr пишет:

Приветствую, я чуть ранее об этом писал, что StaticVar не потокобезопасен и такая проблема есть.

Я помню что вы в самом деле писали про "потоконебезопасность", но сценария приведено не было (или я не смог осознать), и понять тогда в чем "небезопасность" я лично не сумел.
Теперь сценарий понятен, исправлю; фактически установка NameSpace должна работать в рамках каждого потока своя и всё будет отлично.
Занятно, что для разных скриптов NameSpace'ы как раз хорошо изолированы уже сейчас, выбор NameSpace работает раздельно в рамках каждого скрипта.

61

Re: Обмен данными между Lua-скриптами в QUIK

Давайте придумаем что бы нам хотелось и как это хотение должно работать.

kalikazandr пишет:

Если можно, то сразу поправьте SetVarList и GetVarList:
t={1,2,3,4}
stv.UseNameSpace("")
stv.SetVarList(t) ==> invalid key to 'next'

Я в таком сценарии не понимаю вот что: а как после этого (предположим, что данный код сработал) должны работать SetVar / SetVar? что им надо будет указать в качестве "имени переменной"?

62 (2019-07-26 00:31:15 отредактировано kalikazandr)

Re: Обмен данными между Lua-скриптами в QUIK

swerg пишет:

Я в таком сценарии не понимаю вот что: а как после этого (предположим, что данный код сработал) должны работать SetVar / SetVar? что им надо будет указать в качестве "имени переменной"?

Странный вопрос. Это обычный массив и получить i-й элемент массива из (в контексте) пустого nsp по его индексу и точно так же туда по индексу что-то записать.В идеале insert/remove, а текущие функции оставить как есть.

А SetVar/GetVar отлично сохраняют/считывают по индексу.

63 (2019-07-26 10:13:49 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

kalikazandr пишет:
swerg пишет:

Я в таком сценарии не понимаю вот что: а как после этого (предположим, что данный код сработал) должны работать SetVar / SetVar? что им надо будет указать в качестве "имени переменной"?

Странный вопрос. Это обычный массив и получить

Нет, это никак не массив.
Это именно отдельная функция "дай значение параметра по ранее сохранённому имени".

Я понимаю вас в том смысле, что программирование на Lua приводит к определённому взгляду на объекты в программе, и этот взгляд переносится на все аспекты применения/использования в данном языке любых сущностей. Как и программирование на других языках тоже привносит определённую проф. деформацию мозга в каждую свою сторону для каждого языка :)

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

kalikazandr пишет:

insert/remove, а текущие функции оставить как есть.
А SetVar/GetVar отлично сохраняют/считывают по индексу.

Ну не таблица это ну никак! Чисто даже синтаксически.
Т.е. я понимаю ваши чаяния и хотелки, но не поднимается у меня рука в таком виде их реализовывать / развивать.

64 (2019-07-26 10:18:46 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

Однако чтобы разговор этот был плодотворным, давайте помечтаем и о том, какие фичи нам хочется видеть в библиотеке и как красиво и логично они должны выглядеть.

Я предполагаю развить интерфейс библиотеки примерно в таком направлении:

require("StaticVar")
......
stv.любое_имя_A = a   -- сохранили значение переменной a в хранилище
......
z = stv.любое_имя_A   -- прочитали ранее сохранённое значение в переменную z
......
t = {}
t.aa = 1
t.bb = 2
t[8] = 88
stv.любое_имя_T = t   -- сохранили значение из таблицы t
......
z = stv.любое_имя_T   -- прочитали ранее сохранённое значение таблицы в переменную z (целиком таблицу)
z_aa = stv.любое_имя_T.aa  -- т.к. в ".любое_имя_T" сохранена таблица, можно обращаться к её элементам стандартным синтаксисом так
z_88 = stv.любое_имя_T[88]  -- или так

Возможно, буквально в таком синтаксисе не получится - тогда с небольшой модификацией:

stv.DataStorage.любое_имя_A = a   -- сохранили значение переменной a в хранилище
......
z = stv.DataStorage.любое_имя_A   -- прочитали ранее сохранённое значение в переменную z

и т.п.

Как вам такая идея? какие будут предложения в развитие этой идеи или других? Не стесняйтесь! Давайте мечтать и делать мир лучше!

PS
Одного опасаюсь: при таком синтаксисе (прям как таблицы) пользователи решат, что это прям натурально Lua-таблицы и начнут использовать/требовать общение и синтаксис обращения к ним как полностью аутентичным Lua-таблицам (применяя всякие table.sort(), table.insert, итерирование в for и т.п.). А т.к. пока (для скорости обмена между скриптами скриптами) предполагается это реализовывать вручную, не копируя в реальные промежуточные Lua-таблицы (при обращении по индексам), то как бы не замаяться всё это поддерживать smile Плюс разные аутентичные нюансы повылазят (типа того, как индексы разных типов (заданные числами и строками из цифр) в Lua считаются различающимися индексами; это спасибо вы подсказали, а сколько там еще таких нюансов может всплыть...).

65

Re: Обмен данными между Lua-скриптами в QUIK

swerg пишет:

Однако чтобы разговор этот был плодотворным, давайте помечтаем и о том, какие фичи нам хочется видеть в библиотеке и как красиво и логично они должны выглядеть.

Чем больше фич, тем труднее будет отловить ошибку. Нужно оставить как есть, оно вполне себе годный вариант, только индексы поправить и сделать Set/Get-функции пот типу qpile с явным указанием на nsp (в qpile явно указывается имя таблицы).

Тем не менее, давайте помечтаем ("кто о чем, а вшивый о бане").
Итак, есть пространство имен "nsp1", конкретной заявки, которое будет хранится в поле комментария brokerref и доступно в транзакционных таблицах и событиях:

stv.SetVarList("nsp1", {-- сразу! используем нужное пространство имен
  plan = 1,
  posa = 1,
  price = 64.3,
  status = "F",
  event_msg = {}, -- для событий извне
})

В event_msg нужно "накатить" события, будь то события с кнопки или с калбэка:

  stv.SetMsg("nsp1", "event_msg", {OnTrade = true})
  stv.SetMsg("nsp1", "event_msg", {OnOrder = true})
  stv.SetMsg("nsp1", "event_msg", {gui = {plan = -4, price = 64.9})

в итоге имеем поле event_msg в nsp1:

  event_msg = {
    [1] = {OnOrder = true},
    [2] = {OnOrder = true},
    [3] = {gui = {plan = -4, price = 64.9}},
  }

Бот опрашивает event_msg:

  emsg = stv.GetMsg("nsp1", "event_msg") -- при вызове GetMsg поле event_msg = {} - автоматически, если не пустое
  if #emsg > 0 then
    -- обработка событий
  end
  -- пошелестел торговый алгоритм
  trade()

По сути, поле event_msg должно выглядеть отдельным объектом в пространстве имен.

И функции SetVar/GetVar нужны с явным указателем на пространство имен:

  plan = stv.GetVar("nsp1", "plan")
  stvSetVar("nsp1", "price", 64.5)

Пустое пространство имен или именованное (например, nsp_list или "TQBR_SBER") можно использовать для хранения общей информации по инструменту, например.

А stv.UseNameSpace убрать совсем, за ненадобностью + нет гарантии, что сразу после вызова UseNameSpace одним ботом, второй бот тоже ее вызывает и первый бот запишет не в свое пространство имен, что собственно и бывает на практике. И функция о текущем пространстве имен, тоже не нужна, т.к. Set/Get будут явно указывать на nsp.

И будет счастье:)

66

Re: Обмен данными между Lua-скриптами в QUIK

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

67 (2019-08-01 13:48:05 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

kalikazandr пишет:

Чем больше фич, тем труднее будет отловить ошибку.

Хорошо, тот вариант синтаксиса, который я предлагаю выше - он ведь покроет полностью ваши потребности, верно ведь я понимаю?

68

Re: Обмен данными между Lua-скриптами в QUIK

swerg пишет:

Хорошо, тот вариант синтаксиса, который я предлагаю выше - он ведь покроет полностью ваши потребности, верно ведь я понимаю?

Вполне

69

Re: Обмен данными между Lua-скриптами в QUIK

Заметил странную особенность в терминале от финам.
Отключение ботов, использующих StaticVar, не очищает пространство имен и при повторном включении боты видят то, что там записано. Помогает перезапуск терминала.
А в терминалах втб и открытие все норм.

70

Re: Обмен данными между Lua-скриптами в QUIK

А что есть "отключение ботов"? Остановка всех скриптов, использующих StaticVar?
Вообще говоря по задумке ничего и никогда пропадать не должно до самого перезапуска терминала. В этом суть в том числе данной библиотеки: предоставлять не только обмен данными между скриптами, но и обеспечивать сохранность данных между перезапуском скриптов.
Надо будет проверить это момент.
Что касается разного поведения на терминалах разных брокеров - то это и вовсе очень странно. Терминалы указанных брокеров бинарно идентичны.

71

Re: Обмен данными между Lua-скриптами в QUIK

swerg пишет:

Что касается разного поведения на терминалах разных брокеров - то это и вовсе очень странно. Терминалы указанных брокеров бинарно идентичны.

Все, не ищите. Все ровно, старая версия бота обнуляла пространство имен после перезапуска бота.

72

Re: Обмен данными между Lua-скриптами в QUIK

Получается?

73 (2019-08-20 22:53:15 отредактировано swerg)

Re: Обмен данными между Lua-скриптами в QUIK

(версия 1.3.1)
Добавлено корректное потоконезависимое переключение NameSpace'ов
Теперь если в main() задать NameSpace - то он активен только для потока main() этого скрипта и не влияет на код, выполняемый в основном потоке (или в потоке main() других скриптов).

74

Re: Обмен данными между Lua-скриптами в QUIK

s_mike пишет:

swerg,

luaopen_staticvar возвращает boolean

Как-то это некомфортно - по сложившейся традиции внешние lua библиотеки возвращают сам объект...

Поправлено в версии 1.3.1

75

Re: Обмен данными между Lua-скриптами в QUIK

Отлично! Спасибо!