Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 17:18:08
С этим разобрались, идея классная и правильная! Но мой эксперимент сводился к получению данных с использованием 4 необязательного параметра, задача получить ("LAST", "NUMCONTRACTS", "NUMBIDS", "NUMOFFERS", "BIDDEPTHT", "OFFERDEPTHT") в виде свечей и применить к ним технический анализ?
Ни ужели не кто ни использует?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 17:03:21
Не, не Вы правы это я невнимателен, не сразу рассмотрел идею. "Доходит до утки, на третьи сутки" из этой области.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 16:56:14
Кажется я уловил идею, цикл до основного потока это отдельная не блокирующая основной цикл задача! Супер.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 16:41:43
Так и в нашем упрощённом варианте предусмотрен выход из цикла подписки. Либо передача управления в основной цикл (поток луа), либо вообще остановка скрипта, так как данных нет, обрабатывать дальше не чего. Но это уже на усмотрение архитектуры решаемых задач.
Переписал с помощью корутин, здесь их применение наиболее показательно.
Код
local is_run = true
if _G.message then
print = function(...) _G.message(table.concat({...}, ", ")) end
end
-- Таблица для управления корутинами
local coroutines = {}
local coroutine_queue = {}
-- Функция для добавления корутины в очередь
local function create_task(process_func, description, done_callback, err_callback, ctx)
local task = {
coroutine = coroutine.create(process_func),
description = description,
done_callback = done_callback,
err_callback = err_callback,
ctx = ctx,
done = false,
error = false
}
table.insert(coroutine_queue, task)
return task
end
-- Функция для выполнения корутин (аналог Dispatch)
local function ProcessCoroutines()
if #coroutine_queue == 0 then
return
end
local i = 1
while i <= #coroutine_queue do
local task = coroutine_queue[i]
if task.done or task.error then
-- Задача завершена, удаляем из очереди
if not task.silent then
if task.done then
print('Задача выполнена успешно: '..tostring(task.description))
elseif task.error then
print('Задача не выполнена: '..tostring(task.description))
end
if task.response_mes and task.response_mes ~= '' then
print('\t'..task.response_mes)
end
end
if task.done and task.done_callback then
task.done_callback(task.ctx, task.response_mes)
elseif task.error and task.err_callback then
task.err_callback(task.ctx, task.response_mes)
end
table.remove(coroutine_queue, i)
else
-- Выполняем корутину
local status = coroutine.status(task.coroutine)
if status == 'dead' then
task.done = true
elseif status == 'suspended' then
local success, result = coroutine.resume(task.coroutine)
if not success then
task.error = true
task.response_mes = tostring(result)
elseif coroutine.status(task.coroutine) == 'dead' then
task.done = true
task.response_mes = tostring(result)
end
end
i = i + 1
end
end
if #coroutine_queue == 0 then
print('Очередь корутин пуста')
end
end
-- Асинхронная версия создания источника данных
local function create_ds(ctx, done_callback, err_callback, wait_time)
if not ctx then return end
wait_time = wait_time or 60
local start_time = os.time()
local process = function()
local ds, err = _G.CreateDataSource(ctx.class_code, ctx.sec_code, ctx.interval)
if not ds then
error(err)
end
ds.interval = ctx.interval
ds.class_code = ctx.class_code
ds.sec_code = ctx.sec_code
ds.description = ctx.class_code..'|'..ctx.sec_code..', интервал '..tostring(ds.interval)
ds.done_request = false
ctx.ds = ds
print('Заказ данных '..ds.description)
while os.time() - start_time < wait_time do
local size = ds:Size()
if size > 0 then
ds.done_request = true
coroutine.yield(true, false, 'Получены бары '..ds.description..', размер: '..tostring(size))
return
end
coroutine.yield(false, false, 'Ожидание данных...')
end
error('Не удалось инициализировать инструменты за время '..tostring(wait_time)..' сек.')
end
create_task(
process,
'Заказ данных '..ctx.class_code..'|'..ctx.sec_code,
done_callback,
err_callback,
ctx
)
end
-- Асинхронная версия счетчика
local function counter(i, limit)
local x = 0
local process = function()
while x < limit do
x = x + 1
if x >= limit then
coroutine.yield(true, false, string.format('%i: Счетчик до %i завершен', i, limit))
return
else
coroutine.yield(false, false, string.format('%i: Счетчик на %i из %i', i, x, limit))
end
end
end
create_task(process, 'Счетчик до '..tostring(limit))
end
local sec_list = {
{class_code = 'TQBR', sec_code = 'SBER', interval = 1},
{class_code = 'TQBR', sec_code = 'SBER', interval = 2},
{class_code = 'TQBR', sec_code = 'SBER', interval = 5},
{class_code = 'TQBR', sec_code = 'SBER', interval = 10},
{class_code = 'TQBR', sec_code = 'SBER', interval = 20},
{class_code = 'TQBR', sec_code = 'GAZP', interval = 10},
{class_code = 'TQBR', sec_code = 'GAZP', interval = 2},
{class_code = 'TQBR', sec_code = 'GAZP', interval = 5},
{class_code = 'TQBR', sec_code = 'LKOH', interval = 5},
{class_code = 'TQBR', sec_code = 'FEES', interval = 5},
{class_code = 'SPBFUT', sec_code = 'SiZ5', interval = 5},
{class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 5},
{class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 15},
{class_code = 'SPBFUT', sec_code = 'SRZ5', interval = 30},
}
function main()
for i = 1, #sec_list do
counter(i, i*2)
create_ds(sec_list[i])
end
-- Основной цикл выполнения
while is_run do
ProcessCoroutines() -- Обрабатываем корутины вместо задач
sleep(100)
end
end
function OnStop()
is_run = false
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 16:20:09
Теперь я ничего не понял? Вот это место:
Код
for i = 1, #sec_list do
counter(i, i*2)
create_ds(sec_list[i])
end
Пока цикл for i = 1, #sec_list do не завершен, подвешен не исполняется основной цикл while is_run do Так?
while is_run do
Dispatch()
sleep(100)
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
18.11.2025 15:40:43
Запустил у себя, лог:
Код
Тип Дата Время Сообщение
1 18.11.2025 15:26:30 Заказ данных TQBR|SBER, интервал 1
2 18.11.2025 15:26:30 Заказ данных TQBR|SBER, интервал 2
3 18.11.2025 15:26:30 Заказ данных TQBR|SBER, интервал 5
4 18.11.2025 15:26:30 Заказ данных TQBR|SBER, интервал 10
5 18.11.2025 15:26:30 Заказ данных TQBR|SBER, интервал 20
6 18.11.2025 15:26:30 Заказ данных TQBR|GAZP, интервал 10
7 18.11.2025 15:26:30 Заказ данных TQBR|GAZP, интервал 2
8 18.11.2025 15:26:30 Заказ данных TQBR|GAZP, интервал 5
9 18.11.2025 15:26:30 Заказ данных TQBR|LKOH, интервал 5
10 18.11.2025 15:26:30 Заказ данных TQBR|FEES, интервал 5
11 18.11.2025 15:26:30 Заказ данных SPBFUT|SiZ5, интервал 5
12 18.11.2025 15:26:30 Заказ данных SPBFUT|RIZ5, интервал 5
13 18.11.2025 15:26:30 Заказ данных SPBFUT|RIZ5, интервал 15
14 18.11.2025 15:26:30 Заказ данных SPBFUT|SRZ5, интервал 30
15 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных SPBFUT|SiZ5, интервал 5
16 18.11.2025 15:26:30 Получены бары SPBFUT|SiZ5, интервал 5, размер: 23300
17 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных SPBFUT|RIZ5, интервал 5
18 18.11.2025 15:26:30 Получены бары SPBFUT|RIZ5, интервал 5, размер: 33461
19 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных SPBFUT|RIZ5, интервал 15
20 18.11.2025 15:26:30 Получены бары SPBFUT|RIZ5, интервал 15, размер: 12794
21 18.11.2025 15:26:30 Задача выполнена успешно: Счетчик до 2
22 18.11.2025 15:26:30 1: Счетчик до 2 завершен
23 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|SBER, интервал 1
24 18.11.2025 15:26:30 Получены бары TQBR|SBER, интервал 1, размер: 10499
25 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|SBER, интервал 2
26 18.11.2025 15:26:30 Получены бары TQBR|SBER, интервал 2, размер: 3255
27 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|SBER, интервал 5
28 18.11.2025 15:26:30 Получены бары TQBR|SBER, интервал 5, размер: 6302
29 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|SBER, интервал 10
30 18.11.2025 15:26:30 Получены бары TQBR|SBER, интервал 10, размер: 3052
31 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|SBER, интервал 20
32 18.11.2025 15:26:30 Получены бары TQBR|SBER, интервал 20, размер: 3027
33 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|GAZP, интервал 10
34 18.11.2025 15:26:30 Получены бары TQBR|GAZP, интервал 10, размер: 3052
35 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|GAZP, интервал 2
36 18.11.2025 15:26:30 Получены бары TQBR|GAZP, интервал 2, размер: 3255
37 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|GAZP, интервал 5
38 18.11.2025 15:26:30 Получены бары TQBR|GAZP, интервал 5, размер: 6302
39 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|LKOH, интервал 5
40 18.11.2025 15:26:30 Получены бары TQBR|LKOH, интервал 5, размер: 3103
41 18.11.2025 15:26:30 Задача выполнена успешно: Заказ данных TQBR|FEES, интервал 5
42 18.11.2025 15:26:30 Получены бары TQBR|FEES, интервал 5, размер: 3101
43 18.11.2025 15:26:30 Задача выполнена успешно: Счетчик до 4
44 18.11.2025 15:26:30 2: Счетчик до 4 завершен
45 18.11.2025 15:26:30 Задача выполнена успешно: Счетчик до 6
46 18.11.2025 15:26:30 3: Счетчик до 6 завершен
47 18.11.2025 15:26:30 Задача выполнена успешно: Счетчик до 8
48 18.11.2025 15:26:30 4: Счетчик до 8 завершен
49 18.11.2025 15:26:31 Задача выполнена успешно: Счетчик до 10
50 18.11.2025 15:26:31 5: Счетчик до 10 завершен
51 18.11.2025 15:26:31 Задача выполнена успешно: Счетчик до 12
52 18.11.2025 15:26:31 6: Счетчик до 12 завершен
53 18.11.2025 15:26:31 Задача выполнена успешно: Счетчик до 14
54 18.11.2025 15:26:31 7: Счетчик до 14 завершен
55 18.11.2025 15:26:31 Задача выполнена успешно: Счетчик до 16
56 18.11.2025 15:26:31 8: Счетчик до 16 завершен
57 18.11.2025 15:26:31 Задача выполнена успешно: Счетчик до 18
58 18.11.2025 15:26:31 9: Счетчик до 18 завершен
59 18.11.2025 15:26:32 Задача выполнена успешно: Счетчик до 20
60 18.11.2025 15:26:32 10: Счетчик до 20 завершен
61 18.11.2025 15:26:32 Задача выполнена успешно: Счетчик до 22
62 18.11.2025 15:26:32 11: Счетчик до 22 завершен
63 18.11.2025 15:26:32 Задача выполнена успешно: Счетчик до 24
64 18.11.2025 15:26:32 12: Счетчик до 24 завершен
65 18.11.2025 15:26:32 Задача выполнена успешно: Счетчик до 26
66 18.11.2025 15:26:32 13: Счетчик до 26 завершен
67 18.11.2025 15:26:32 Задача выполнена успешно: Счетчик до 28
68 18.11.2025 15:26:32 14: Счетчик до 28 завершен
69 18.11.2025 15:26:33 Задача выполнена успешно: Заказ данных SPBFUT|SRZ5, интервал 30
70 18.11.2025 15:26:33 Получены бары SPBFUT|SRZ5, интервал 30, размер: 3013
71 18.11.2025 15:26:33 Очередь задач пуста
Все задачи Выполнены. Но ведь это тот же самый вариант? Отличие Ваш скрипт ждет подписки (скорее подписка чем получение), а наш блокирует исполнение, привлекая внимание пользователя, передавая ему управление. (Смысл - Допустим, заблокируй не рабочий тикер, и запусти по новой). В Вашем подходе будет все висеть пока все тикеры не подпишутся. Допустим сменился тикер у фьючерса, пользователь в надежде что все работает в автомате? (Это просто частный случай, Вы сами утверждаете, что ситуация мало прогнозируема). А основной поток луа (цикл) остается не рабочем? Тогда уж, все исполнять нужно в основном цикле, с фиксацией состояния подписки, чтоб не повторять запросы?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 17:31:32
Цитата
Nikolay написал: Т.е. кидаем запросы атомарно, создаем задачу для проверки ответа
Поясните?
Подпиской создали таблицу интерфейса для получения данных, а дальше в потоке луа получаем ds:O(I).
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 17:24:18
VPM, А чему Вы удивляетесь? Это не я придумал? Таланты в стране, ни чего не поделаешь.
Цитата
nikolz написал: "А, ты за большевиков, али за коммунистов?"
Я за индивидуальных ТРЕЙДЕРОВ, которым нужны простые рабочие варианты. По сути если обобщить получение данных из квик, есть 2 основных варианта: 1. с помощью параметров (class_code, sec_code) 2. firmid, client_code.
А есть особые случаи!!!
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
VPM написал: "param – необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок, если задан – данные по этому параметру.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 16:57:39
nikolz, И в примере выше подписка сделана один раз, перед созданием потока луа, более того подписка то прошла, ответ true? А индекс = 0? Речь идет о тиковых данных. А количество инструментов тут не причем, разве только все усугубить нужно, но проблематика прекрасна видна на одном инструменте. Я ведь ни чего не придумал, нет тут от "себятины":
"param – необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок, если задан – данные по этому параметру.
Функция возвращает таблицу data_source в случае успешного завершения. Если указан неверный код класса, код инструмента, интервал или параметр, то возвращается «nil». При этом error_desc содержит описание ошибки.
Функцию CreateDataSource можно использовать только внутри функций main() и callback."
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 15:59:14
Минимально безопасный вариант;
Код
function createDS(class, symbol, interval)
for i = 1, 20 do
local ds, err = CreateDataSource(class, symbol, interval)
if ds then return ds end
sleep(100)
end
return nil
end
Почему это безопасно?
Повтор не бесконечный;
Максимальная задержка – ~2 секунды, QUIK не убьёт скрипт;
Если DS не создалась — ошибка обработана, без падений;
Лаконично и безопасно.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 15:32:41
TGB, Спасибо, да но этот случай для получения данных из таблицы обезличенных сделок, я использую так, если не получены то и делать дальше нечего (нечего обрабатывать):
Код
local ds, Error = nil, ''
local count = 0
repeat
ds, Error = CreateDataSource(class, symbol, interval)
if ds == nil then
count = count + 1
sleep(100)
end
until (ds or count == 1000)
А что делать когда получаем из таблицы TTT как в примере выше? И задача стоит получить "LAST", "NUMCONTRACTS", "NUMBIDS", "NUMOFFERS", "BIDDEPTHT", "OFFERDEPTHT"? Один не пришел заблокировал все?
Цитата
VPM написал: Моя идея была получать разные параметры единообразным способом, в формате свечей, что в свою очередь позволило обрабатывать их едиными способами. Использовать единые фильтры, индикаторы, паттерны. Следовательно формировать единую логику, не только для цены, но и для OI, количества на покупку / продажу и так далее.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 12:56:51
Следовательно ds:Size() = 0, есть показатель того что брокер не отдает данные?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 12:49:23
Но все же осталось не понимание:
Код
-- Создаем источник данных свечей
local error_desc = ''
ds, error_desc = CreateDataSource(class_code, sec_code, 60 ) -- ,"last"
message( tostring(error_desc) ..' '.. type(ds))
if ds then
--sleep(1000)
local result = ds:SetEmptyCallback() -- SetUpdateCallback(onCandleUpdate) --
message("Источник свечей создан, размер: " .. ds:Size() ..' '..tostring(result) )
else
message("ОШИБКА: Не удалось создать источник свечей " .. tostring(error_desc))
return
end
Цитата
VPM написал: То подписка на свечи не работает, от слова совсем (17.11.2025 7:51:28 Источник свечей создан, размер: true 0). Не падёт, ошибок не выводит, И НИ ЧЕГО не отдает ds:Size() =0? Настройки: Умный заказ, терминал 12+ проверил на разных.
А как же проверить? Убедиться что все работает?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 12:22:26
Цитата
Nikolay написал: И стоит ли это вообще делать, т.к. обычно такие скорости нужны для HFT где нужны объемы, которые очень редко доступны для физ. лиц.
Моя идея была получать разные параметры единообразным способом, в формате свечей, что в свою очередь позволило обрабатывать их едиными способами. Использовать единые фильтры, индикаторы, паттерны. Следовательно формировать единую логику, не только для цены, но и для OI, количества на покупку / продажу и так далее.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 12:16:18
Проверил. Без доп. параметра работает. Даже задержка уменьшилась на получение из ТТТ.
Код
TYPE DATE TIME MESSAGE
1 1 17.11.2025 12:05:06 Скрипт инициализирован
2 1 17.11.2025 12:05:06 === ПРОСТОЙ РОБОТ ЗАПУЩЕН ===
3 1 17.11.2025 12:05:06 1. bid true boolean
4 1 17.11.2025 12:05:06 2. offer true boolean
5 1 17.11.2025 12:05:06 3. last true boolean
6 1 17.11.2025 12:05:06 1. Level_II true boolean
7 1 17.11.2025 12:05:06 nil table
8 1 17.11.2025 12:05:06 Источник свечей создан, размер: 6950 true
9 1 17.11.2025 12:05:36 Статус: 31 итераций, Bid=97970.000000, Offer=97980.000000
10 1 17.11.2025 12:05:36 получать данные с сервера, размер: 6950 true
11 1 17.11.2025 12:05:36 Свеча: O=295.1 H=296.0 L=295.1 C=295.6
12 1 17.11.2025 12:06:06 Статус: 61 итераций, Bid=97960.000000, Offer=97980.000000
13 1 17.11.2025 12:06:06 получать данные с сервера, размер: 6950 true
14 1 17.11.2025 12:06:06 Свеча: O=295.1 H=296.0 L=295.1 C=295.6
15 1 17.11.2025 12:06:34 Робот остановлен по команде
16 1 17.11.2025 12:06:35 Робот остановлен
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 11:53:34
Nikolay, А подскажите такая практика: ds1, error_desc = CreateDataSource(class_code, sec_code, 60 ,"last") ds2, error_desc = CreateDataSource(class_code, sec_code, 60 ,"bid") ds3, error_desc = CreateDataSource(class_code, sec_code, 60 ,"offer") dsn, error_desc = CreateDataSource(class_code, sec_code, 60 ,"...") Она "никудышняя"? Если допустим со стаканом сравнить, или опять же просто напрямую получить из ТТТ?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 11:42:58
Nikolay, Спасибо Уразумел! Задумался на д тем что получая данные о свечах из таблицы обезличенных сделок, не понятно как обрабатывать свечи на низко ликвидных инструментах?
А что брокер под каждого клиента подстраивает сервер? Или как?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 11:06:57
nikolz, Весь скрип перед Вами, ниже лог его исполнения. На одном инструменте, подписывается на получение данных с сервера, ну а как выводит видно из лога. Если из ТТТ начинает получать (17.11.2025 7:42:28 Статус: 331 итераций, Bid=98610.000000, Offer=98650.000000) хотя и пол века прошло? То подписка на свечи не работает, от слова совсем (17.11.2025 7:51:28 Источник свечей создан, размер: true 0). Не падёт, ошибок не выводит, И НИ ЧЕГО не отдает ds:Size() =0? Настройки: Умный заказ, терминал 12+ проверил на разных.
Вопрос что делаю не так?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 07:55:53
Один простой ВОПРОС "Для кого все это???" . Ни покладая рук разработчики трудятся, а для кого все это? Или я что то делаю ни так?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
17.11.2025 07:53:27
Код
Минимальный рабочий Скрипт для QUIK
local WORKING_FLAG = true
local class_code, sec_code = "TQBR", "SBER"--"SPBFUT", "RIZ5"
-- Простые переменные для данных
local last_bid = "N/A"
local last_offer = "N/A"
local last_candle = nil
local ds = nil
-- Прямые callback функции без сложных систем
function OnParam(class_code, sec_code)
if class_code == "SPBFUT" and sec_code == "RIZ5" then
last_bid = getParamEx(class_code, sec_code, "bid").param_value or "N/A"
last_offer = getParamEx(class_code, sec_code, "offer").param_value or "N/A"
end
end
function OnQuote(class_code, sec_code)
-- Просто получаем стакан, но не обрабатываем чтобы не нагружать
end
-- Callback для свечей
local function onCandleUpdate(index)
if ds and index <= ds:Size() then
last_candle = {
open = ds:O(index),
high = ds:H(index),
low = ds:L(index),
close = ds:C(index),
volume = ds:V(index)
}
if index == 1 then -- Новая свеча
message(string.format("НОВАЯ СВЕЧА %s O=%.1f C=%.1f",
sec_code, last_candle.open, last_candle.close))
end
end
end
function main()
message("=== ПРОСТОЙ РОБОТ ЗАПУЩЕН ===")
-- Простые подписки
local result = ParamRequest(class_code, sec_code, "bid")
message( '1. bid '.. tostring(result) ..' '.. type(result))
local result = ParamRequest(class_code, sec_code, "offer")
message( '2. offer '.. tostring(result) ..' '.. type(result))
local result = ParamRequest(class_code, sec_code, "last")
message( '3. last '.. tostring(result) ..' '.. type(result))
local result = Subscribe_Level_II_Quotes(class_code, sec_code)
message( '1. Level_II '.. tostring(result) ..' '.. type(result))
-- Создаем источник данных свечей
local error_desc = ''
ds, error_desc = CreateDataSource(class_code, sec_code, 60, "last")
message( tostring(error_desc) ..' '.. type(ds))
if ds then
--sleep(1000)
local result = ds:SetEmptyCallback() -- SetUpdateCallback(onCandleUpdate) --
message("Источник свечей создан, размер: " .. ds:Size() ..' '..tostring(result) )
else
message("ОШИБКА: Не удалось создать источник свечей " .. tostring(error_desc))
return
end
-- ОСНОВНОЙ ЦИКЛ - ПРОСТОЙ И ЧИСТЫЙ
local iteration = 0
local last_print_time = os.time()
while WORKING_FLAG do
iteration = iteration + 1
-- Печатаем статус раз в 30 секунд
local current_time = os.time()
if current_time - last_print_time >= 30 then
message(string.format("Статус: %d итераций, Bid=%s, Offer=%s",
iteration, last_bid, last_offer))
local result = ds:SetEmptyCallback() -- SetUpdateCallback(onCandleUpdate) --
message("получать данные с сервера, размер: " .. ds:Size() ..' '..tostring(result) )
if ds:Size() and ds:Size()>0 then
message(string.format("Свеча: O=%.1f H=%.1f L=%.1f C=%.1f",
ds:O(ds:Size()), ds:H(ds:Size()),
ds:L(ds:Size()), ds:C(ds:Size())
))
end
last_print_time = current_time
end
-- ВАЖНО: Даем время QUIK обработать события
sleep(1000) -- 1 СЕКУНДА - достаточно для избежания "Превышения времени"
end
message("Робот остановлен")
end
-- Простые обработчики остановки
function OnStop()
WORKING_FLAG = false
if ds then ds:Close() end
message("Робот остановлен по команде")
end
function OnClose()
WORKING_FLAG = false
if ds then ds:Close() end
end
function OnInit()
message("Скрипт инициализирован")
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
09.11.2025 11:15:09
2. Создание объектов в Lua (OOП-подход). Lua не имеет полноценного OOP, но таблицы + метатаблицы позволяют достаточно просто строить объекты.
Когда удобно использовать объект? * Когда объект “знает о себе всё”, например, инструмент/портфель содержит всю информацию о классе, счёте, лоте, цене, позиции, статусе торгов. * Когда нужно хранить состояние и методы, которые его изменяют. * Когда удобно группировать методы вокруг данных, чтобы не передавать их постоянно в функции.
Когда объект может быть лишним? * Если скрипт простой и все данные можно хранить в таблицах без методов. * Если входные параметры минимальны, и основной сценарий — «инициализировал и забыл».
Итог. * ООП полезно для сложных инструментов, портфелей и роботов. * Но для конечного пользователя упрощённый интерфейс (модуль + таблицы данных) удобнее, просто и наглядно.
3. Удобство конечного пользователя. Ну здесь собственно и комментарии излишни, просто зафиксируем.
* Минимум входных параметров, тикер + счёт + субсчёт. Всё остальное берётся автоматически из QUIK. * Автоопределение параметров, класс инструмента, шаг цены, масштаб, доступные позиции, счета. * Модули как библиотека, пользователь не меняет код робота, а лишь занимается его конфигурацией. * Принцип “Написал и Забыл”, всё сложное внутри библиотеки, робот только управляет потоком и вызывает нужные функции.
Ну как то так. Хорошего кода.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
09.11.2025 11:00:01
Сформулирую подход — Разделение кода на модули. Критерии разделения кода в Lua для QUIK:
а) Функциональная логика – каждый модуль отвечает за конкретную задачу:
* qlib_core.lua — системные и сервисные функции (isConnected, sleep, getTradeDate, логирование). * qlib_data.lua — получение рыночной информации (getQuotes, getParamEx, getSecurityInfo). * qlib_portfolio.lua — управление портфелем (initPortfolio, autoRebalancePortfolio, позиции). * qlib_utils.lua — общие утилиты (tableKeys, форматирование, вспомогательные функции).
б) Повторное использование — если какая-то функция используется в разных местах, выносим её в отдельный модуль. с) Лёгкость замены/обновления — чтобы исправления коснулись только конкретного функционала, без изменения всего робота. д) Простота конечного пользователя — модули скрывают все сложности и предоставляют простой интерфейс: входные параметры минимальны (например, только тикер, счёт, субсчёт).
Итог. Модули разделяем * по смыслу * и повторяемости функций. Цель - пользователь получает простую точку входа — скрипт робота.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
09.11.2025 10:17:13
Прислушаюсь к советам и замечания профи:
Цитата
Nikolay написал: И да, делать для этого объекты - так себе затея. Входящие параметры для скрипта - это код инструмента, торговый счет, субсчет (код клиента) если их несколько. Все. Остальное получается из терминала. Впрочем даже счет и субсчет можно подставить из данных для класса инструмента. Зачастую они и нужны. Если Вы пишите скрипты для себя, то, конечно, делайте как хотите. Но если уже для других, то всегда отталкивайтесь, что максимум что может сделать пользователь - это изменить файл настроек, где все максимально просто и понятно. Не надо искать информацию в служебных окнах терминала. Либо делать интерфейс, через который тоже просто задаются параметры.
Разберусь с чем имеем дело.
1. Сила и мощь при использовании луа - это его основная структура данных - таблица. Именно они позволяют нам структурировать код, так как нам нужно, создавать модули. Что в свою очередь приводит к многоразовому использованию этих модулей (принцип "Написал и Забыл") . Согласитесь - это просто удобно, если возникает необходимость что то исправить, мы просто работаем с этим модулем. И здесь возникает основной вопрос по каким критериям, необходимо делить код на модули?
2. Луа позволяет легко создавать так называемый "Объект", создавая его необходимо понимать, а для чего и когда это удобно? Я не очень разобрался со всеми возможностями ООП, для меня важную роль играет фактор "таблица знает о себе все", то есть удобство управления, хранения и получения данных. Именно здесь возникают профессиональные сложности.
3. Удобство конечного пользователя, просто необходимая. Автоматизация получения данных, утилиты, сервисные вещи и все прочее в библиотеку. Много разовое модульное использования превращает нас из конструктора деталей и узлов в Главного конструктора нашего проекта "Робот". Один раз отладили, и используем в проверке наших торговых идей. Так что взялись за библиотеку, а идей еще очень много и не терпится их проверить!
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
07.11.2025 10:04:51
Если добавить к этим модулям вспомогательную оболочку типа DataHub, которая объединит QuickDataManager и мой MarketData в одну унифицированную архитектуру (единый интерфейс “данные QUIK” и “данные с рынка”), то получим идеальную базу для торгового ядра? Но в этом варианте в разы уваливается сложность, и требуется более профессиональный подход, в распределении ресурсов и нагрузок CPU, то о чем нас постоянно предупреждают опытные разработчики.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
07.11.2025 09:51:52
Разбор полета.
Грамотная архитектура, для идеи "ленивого дата-менеджера" и улучшения её в духе реального продакшн-решения. Разберу вариант подробней, чтобы подтвердить, где попал в точку и что нужно отполировать.
1. Нормализация ключа кэша. Сортировка ключей — идея для стабильности (иначе "a,b" и "b,a" могли бы быть разными), нужно ещё добавить firmid и client_code в начало ключа: local key_parts = {self.firmid, self.client_code, param} Так один менеджер может обслуживать несколько клиентов без пересечений в кэше, теперь комбинация sec_code=SBER и sec_code=GAZP не будет путаться.
2. Кэш с TTL и проверкой актуальности. self.cache_ttl = 5 self.cache_timestamps[cache_key] = os.time()
Это минимальный, но практичный шаг, QUIK не всегда требует мгновенной актуализации, но важно не держать stale-данные применим подход "time-based invalidation". Также можно улучшить, если добавить опциональный параметр TTL при вызове? function QuickDataManager:new(firmid, client_code, cache_ttl) obj.cache_ttl = cache_ttl or 5 end
3. Безопасная загрузка через pcall: local success, err = pcall(function() QUIK-функции часто возвращают nil или бросают ошибки при нестабильных данных. Это гарантия, что менеджер не уронит основной поток.
4. Методы вместо __index. Переход от хардкода (manager.depo) к явным методам (manager:get_depo()) — это повышает читаемость и контроль над параметрами.
5. Управление кэшем. QuickDataManager:clear_cache() QuickDataManager:refresh() QuickDataManager:get_cache_stats()
Просто и функционально — всё, что нужно для отладки и тонкой настройки. get_cache_stats() — инструмент для мониторинга эффективности.
Что можно слегка отшлифовать.
1. Унификация вызова QUIK-функций. сделано логично: if param == "money" then data = getMoneyEx(...)
Но чтобы не плодить if-ветки, можно вынести маппинг функций в таблицу: QuickDataManager.functions = { money = getMoneyEx, depo = getDepoEx, portfolio = getPortfolioInfoEx, buy_sell = getBuySellInfoEx, futures_limit = getFuturesLimit, futures_holding = getFuturesHolding }
А потом универсально: local func = self.functions[param] if not func then error("Unknown data type: " .. param) end data = func(table.unpack(args))
Чтобы args формировать автоматически — хранить шаблоны параметров?
2. Параметры по умолчанию. Сейчас много or "", можно централизовать дефолты: QuickDataManager.defaults = { money = { tag="", currcode="SUR", limit_kind=0 }, depo = { sec_code="", trdaccid="", limit_kind=0 }, portfolio = { limit_kind=0 }, buy_sell = { class_code="", sec_code="", price=0 }, futures_limit = { trdaccid="", limit_type=0, currcode="SUR" }, futures_holding = { trdaccid="", sec_code="", type=0 } } Тогда метод _loadData может начинаться с: optional_params = table.merge(self.defaults[param] or {}, optional_params or {})
3. Асинхронность или очередь обновлений. Если добавить корутину-обновление (например, периодическое refresh), то эта структура идеально готова — просто запускаешь фоновые обновления без блокировки QUIK.
4. Универсальный интерфейс доступа. Чтобы сохранить удобство "ленивого доступа", можно вернуть синтаксическую обёртку:
setmetatable(QuickDataManager, { __index = function(self, key) if self["get_" .. key] then return self["get_" .. key](self) end end }) Тогда снова можно писать: local depo = manager.depo -- ленивый вызов get_depo() но при этом параметры будут управляться методами?
Финальный вариант (сбалансированный).
function QuickDataManager:new(firmid, client_code, cache_ttl) local obj = setmetatable({}, self) obj.firmid = firmid obj.client_code = client_code obj.cache = {} obj.cache_timestamps = {} obj.cache_ttl = cache_ttl or 5 return obj end
function QuickDataManager:_build_cache_key(param, optional_params) local key_parts = {self.firmid, self.client_code, param} if optional_params then local sorted = {} for k in pairs(optional_params) do table.insert(sorted, k) end table.sort(sorted) for _, k in ipairs(sorted) do table.insert(key_parts, k .. "=" .. tostring(optional_params[k])) end end return table.concat(key_parts, "|") end Просто добавить централизованные defaults и маппинг функций.
ИТОГ. Такая версия — уже достаточно зрелая. Она: * Решает проблему дублирования и нагрева QUIK-API; * Гибко масштабируется под любые источники данных; * Предусматривает отказоустойчивость; * Простая для использования в сценариях (ленивая инициализация).
К этому обновленному, менеджеру если добавить, автоматическое обновление данных через coroutine с учётом TTL и нагрузки (чтобы QUIK не тормозил). Это позволит, например, держать кэш свежим без прямых вызовов refresh().
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
07.11.2025 09:44:16
В концептуальном примере выше, используется ленивый подход (lazy loading) для получения данных, когда они действительно необходимы, а не заранее.
В частности, для каждого параметра вызывается функция только при попытке обращения к этому параметру, что снижает избыточную загрузку данных. В примере уже используется ленивое получение данных для параметров через функцию __index. Это значит, что данные не загружаются, пока они явно не понадобятся (например, при обращении к ним в коде).
Производительность, хотя ленивый подход помогает избежать лишних запросов, важно следить за тем, чтобы не было слишком частых запросов к серверу, если объем данных большой. Оптимизация, кэширование данных, чтобы не запрашивать данные каждый раз при обращении к параметрам, добавить кэширование результатов запросов через self.cache для параметров, чтобы избежать лишних вызовов.
Некоторые моменты, которые нужно улучшить для большей гибкости и упрощения, и настройки стабильной работы.
1. Обработчик ленивой загрузки для разных параметров. Вместо жесткого кода для каждого параметра, можно обрабатывать ленивую загрузку более универсально, используя механизм, который будет определять, какой тип данных нужно загружать, в зависимости от имени параметра.
2. Модификация функции __index. Нужно немного улучшить проверку, чтобы все параметры, можно было бы загружать лениво, а не только жестко прописанные. Например, можно динамически извлекать значения для всех типов данных через getParamEx.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 15:31:19
Цитата
nikolz написал: В своем скрипте все параметры типа firmid, client получаю из QUIK. Т е их не надо вводить пользователю.
Не очень понимаю этот подход, ну если с firmid все еще понятно, зависит в чей терминал скипт загружен. То с client не все очевидно, все равно приходится в водить,
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 15:27:47
nikolz, Это не инструкция, это описные одного из вариантов подхода, если хотите мое виденье, выложено на обсуждение сообществу.
"ленивая" загрузка - описание есть выше, такую возможность предоставляет ООП, если не очень понятно можно посмотреть фреймворк на который я ссылаюсь.
Подход уже тоже устарел так как нашлись более удобные решения, например кэширует результаты и имеет авто обновление через корутину (с ограничением нагрузки),
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 14:26:30
Что делает:
QuickDataManager:new(firmid, client_code). Конструктор создаёт экземпляр менеджера с обязательными параметрами firmid и client_code. Это основные параметры для работы с системой QUIK. Все остальные параметры передаются как опциональные в виде таблицы в функции.
QuickDataManager:_loadData(param, optional_params). Это основная функция для ленивой загрузки данных. В зависимости от параметра (например, "money", "depo", "portfolio", и т.д.), она делает запросы к соответствующим функциям QUIK. Функция также проверяет, есть ли уже кэшированные данные для этого параметра, и если они есть — возвращает их. Если данных нет, выполняется запрос и кэшируются результаты? Здесь основной вопрос как правильно организовать работу?
QuickDataManager:__index(key). Метатаблица __index отвечает за доступ к данным через ключи, такие как money, depo, portfolio и другие. Для каждого ключа вызывается соответствующая функция ленивой загрузки, которая получает необходимые данные и кэширует их.
Параметры (например, tag, currcode, limit_kind, sec_code и другие) передаются через опциональные параметры, что позволяет адаптировать запросы под различные нужды и сохранить гибкость подхода.
Пример использования. При первом обращении к данным (manager.money, manager.depo, manager.portfolio, и т.д.) данные будут загружены, затем они будут кэшироваться для последующего использования без лишних запросов к системе. Что позволяет уменьшить нагрузку на систему и ускорить последующие операции. Как альтернатива. Если нужно избежать повторного получения одинаковых данных, можно добавить механизм для "очистки" кэша по истечении времени или по запросу.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 14:16:24
Вариант реализации подхода, что скажите?
Код
QuickDataManager = {}
QuickDataManager.__index = QuickDataManager
-- Конструктор класса
function QuickDataManager:new(firmid, client_code)
local obj = setmetatable({}, self)
obj.firmid = firmid
obj.client_code = client_code
obj.data = {} -- Для хранения кэшированных данных
obj.loaded = {} -- Для отслеживания загруженных параметров
return obj
end
-- Функция для ленивой загрузки данных с учетом firmid и client_code
function QuickDataManager:_loadData(param, optional_params)
-- Формируем уникальный ключ для кэширования (с учетом параметров)
local cache_key = param .. "_" .. (optional_params or "")
if self.loaded[cache_key] then
return self.data[cache_key] -- Возвращаем из кэша
end
-- Если данных нет в кэше, загружаем их
local data
if param == "money" then
-- Вызов getMoneyEx для получения информации по деньгам
data = getMoneyEx(self.firmid, self.client_code, optional_params.tag or "", optional_params.currcode or "", optional_params.limit_kind or 0)
elseif param == "depo" then
-- Вызов getDepoEx для получения позиций по инструментам
data = getDepoEx(self.firmid, self.client_code, optional_params.sec_code or "", optional_params.trdaccid or "", optional_params.limit_kind or 0)
elseif param == "portfolio" then
-- Вызов getPortfolioInfoEx для получения информации по клиентскому портфелю
data = getPortfolioInfoEx(self.firmid, self.client_code, optional_params.limit_kind or 0, optional_params.board_tag or "", optional_params.currency or "")
elseif param == "buy_sell" then
-- Вызов getBuySellInfoEx для получения параметров по заявкам
data = getBuySellInfoEx(self.firmid, self.client_code, optional_params.class_code or "", optional_params.sec_code or "", optional_params.price or 0)
elseif param == "futures_limit" then
-- Вызов getFuturesLimit для получения фьючерсных лимитов
data = getFuturesLimit(self.firmid, optional_params.trdaccid or "", optional_params.limit_type or 0, optional_params.currcode or "")
elseif param == "futures_holding" then
-- Вызов getFuturesHolding для получения позиций по фьючерсным счетам
data = getFuturesHolding(self.firmid, optional_params.trdaccid or "", optional_params.sec_code or "", optional_params.type or 0)
end
-- Кэшируем загруженные данные
self.data[cache_key] = data
self.loaded[cache_key] = true
return data or {}
end
-- Доступ к данным с ленивой загрузкой
function QuickDataManager:__index(key)
if key == "money" then
return self:_loadData("money", {tag = "default", currcode = "USD", limit_kind = 0})
elseif key == "depo" then
return self:_loadData("depo", {sec_code = "SBER", trdaccid = "1234", limit_kind = 0})
elseif key == "portfolio" then
return self:_loadData("portfolio", {limit_kind = 0, board_tag = "TQBR", currency = "RUB"})
elseif key == "buy_sell" then
return self:_loadData("buy_sell", {class_code = "TQBR", sec_code = "SBER", price = 1000})
elseif key == "futures_limit" then
return self:_loadData("futures_limit", {trdaccid = "TQBR", limit_type = 0, currcode = "USD"})
elseif key == "futures_holding" then
return self:_loadData("futures_holding", {trdaccid = "1234", sec_code = "SBER", type = 0})
else
-- Загружать другие параметры по необходимости
return self:_loadData(key)
end
end
-- Пример использования
local manager = QuickDataManager:new("Firm1", "Client1")
-- Ленивое обращение к данным
local money = manager.money -- Получение информации по деньгам
local depo = manager.depo -- Получение позиций по инструментам
local portfolio = manager.portfolio -- Получение информации по портфелю
local buy_sell = manager.buy_sell -- Получение информации по заявкам на покупку/продажу
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 11:09:36
"Едем дальше, видим больше"! На мой взгляд данный подход, нужно распространить на получение "Серверных данных". Для понимания проблематики, архитектуру предлагается использовать общею для фондового и сросного рынков? Задача все та же.
Задача - возможность торговать и управлять 1 инструментом так и портфелем (универсальность), с учетом рисков (как квиковских, так и собственно ручных), ну и конечно одной из основных задач управление позицией. Структура - модульная, много разового использования. Интерфейс - наипростейший, понятный бабушке!
Обобщенно свести квиковские в функции в удобную оболочку:
Функции взаимодействия скрипта Lua и Рабочего места QUIK
getDepoEx - функция для получения позиций по инструментам указанного типа
getMoneyEx - функция для получения информации по денежным позициям указанного типа
getFuturesLimit - функция для получения информации по фьючерсным лимитам
getFuturesHolding - функция для получения информации по фьючерсным позициям
getSecurityInfo - функция для получения информации по инструменту?
getTradeDate - функция для получения даты торговой сессии
CalcBuySell - функция для расчета максимально возможного количества лотов в заявке? (скорее для контроля, уж больно тяжелая?)
getPortfolioInfoEx - функция для получения значений параметров таблицы «Клиентский портфель» с учетом срока расчётов
getBuySellInfoEx - функция для получения параметров (включая срок расчётов) таблицы «Купить/Продать» (Важная для маржинальной торговли!)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 10:45:08
nikolz, На счет сложности, для меня очень сложно, здесь с Вами не поспоришь. Отсюда бывает и путаница.
Не могу согласиться: "Универсальная система - это такая система, разработчик которой не имеет представления где и как ее будут применять.". На все известно и источники и методы, а использование их на прямую зависит от сложности самой торговой системы. Изначально думал для удобства сделать единый интерфейс рыночных данных, как то само собой добавились индикаторы и вся остальная инфраструктура и все вылилось в целый фреймворк. Конечно нужно тестирование и оптимизация.
"Пользователь такой системы не в состоянии понять все, что включил в нее разработчик." Так ведь и задача стоит, не нужно пользователю начинка, подключил блок и пользуйся понятным простым интерфейсом. Меня "ушатала" постоянная переделка. Задача все таки, удобство получать в торговых подходах, а не упражнения в программировании. Удобно и то что есть алгоритмы которые использует большинство, ATR, StDev, средниеи.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
1000 раз уже на форуме говорил "Не программист, и знания мои так себе". Это раз! Форум - это площадка для обсуждений, а не выставления амбиций. Это два!
Теперь что касается последней темы:
1. Не надо "Кусочничить". Я тему веду последовательно, и рассуждения читать нужно также. 2. А Вы то понимаете сами? Пока не создан подход, то и оптимизировать НЕ ЧЕГО, от слова совсем? 3. Ответ на Ваш вопрос. Оптимизация - это КОМПРОМИС. Поменяйте понимание и все встанет по местам. 4. Повторюсь мне не сложно: Подход - Инвестиционный (означает тф. месячный и больше, в квик их нет). Задача - возможность торговать и управлять 1 инструментом так и портфелем (универсальность). Структура - модульная, много разового использования. Интерфейс - наипростейший, понятный бабушке!
Про КПД, чего Вы рассуждаете? Все КПД моего старенького направленно на эффективность торговли = увеличению баланса счета. Тем более что подход описан, и можно воспользоваться функциями без корутин.
И последнее, Вы не сомневайтесь, сомнения нужны на стадии анализа, а когда решение принято, нужно действовать. Попробуйте. Ну или обосновано возражайте.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 09:14:50
TGB, Ну вот, Можете же, нормально изъясняться в пределах общения, без излишней надменности.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 09:07:11
Что вышло. Это — мощный объектно-ориентированный фреймворк для рыночных данных на Lua, для QUIK. Реализует целую универсальную систему источников рыночных данных. Она объединяет котировки, свечи и индикаторы в едином интерфейсе. Система построена на метатаблицах (классическом OOP для Lua), в основу положен подход представленный в фреймворке HH.
Какие задачи решает. Код реализует полный универсальный слой доступа к рыночным данным: ------------------------------ * единый API для котировок, свечей и индикаторов; * кэширование, буферизация и автообновление; * поддержка любых индикаторов; возможность расширять систему.
Чуть подробней. ----------------------- MarketData. Работает с текущими рыночными данными (котировки Level 2, параметры инструмента). Поддерживает: * bids / offers (через getQuoteLevel2()) * другие параметры через getParamEx() Умеет “подгонять” цену под шаг (fit() / move()).
Основной класс — MarketData_Pro. Это универсальный интерфейс ко всем типам данных. Автоматически определяет источник: * есть tag > индикатор с графика + свечи; * есть interval > свечи или любой другой параметр таблицы текущих торгов; * иначе > поток котировок таблица Текущих торгов или таблица Левел2. Автоматически создаёт соответствующий объект-источник.
Методы доступа: ----------------------- UniversalIndicatorSystem - Это глобальный реестр индикаторов. Поддерживает регистрацию, кеширование и вычисление индикаторов.
Есть встроенные индикаторы: Название Назначение Тип SMA Простое скользящее среднее numeric/price EMA Экспоненциальное скользящее среднее numeric/price RSI Индекс относительной силы price ATR Средний истинный диапазон price STDDEV Стандартное отклонение numeric BOLLINGER Полосы Боллинджера price
Можно добавлять свои: GlobalIndicatorSystem:registerIndicator("MY_IND", function(buffer) -- код вычисления end, "My Indicator", {"numeric"})
UniversalDataSource. Базовый класс для любых источников данных. Позволяет: * Получать буфер по типу (getBuffer("close")) * Обновлять данные (updateBuffer) * Вызывать индикаторы (getIndicator("SMA", 14)) Именно от него наследуются конкретные реализации ниже!!!
Реализации источников. ------------------------ 1) CandleDataSource. Создаётся через CreateDataSource(). Загружает OHLCVТ-данные. Обновляет буферы (close, high, low, open, volume). Позволяет вызывать индикаторы на свечных данных.
2) QuoteDataSource. Источник потоковых котировок (через getParamEx, getQuoteLevel2). Буферы (last, bid, offer, volume). Поддерживает вычисление индикаторов по последним значениям
3) getCandlesByIndex()? Удобен для визуализации, но не очень при обработке множества тикеров и таймфреймов, особенно когда есть небходимость их постоянно изменять, в под?
Менеджер источников - MarketData_Pro.Manager. ----------------------------- Создаёт и кеширует все экземпляры MarketData_Pro. а) Глобальный объект: MDP; б) Методы: * getOrCreate(params) — получить источник, если уже есть, иначе создать; * registerIndicator(name, func, desc, types) — глобальная регистрация индикатора.
Ну как то так! Основная цель универсальность - возможность много кратного использования блока модулей, и удобство и простота интерфейса пользователя.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
06.11.2025 08:02:58
Попурри на тему "Три тополя на Плющихи" в исполнении ... .
Зацените на сколько удобен интерфейс конечного пользователя в этом подходе.
Код
-- Примеры использования универсальной системы:
-- Глобальный экземпляр
MDP = MarketData_Pro.Manager:new()
-- 1. УНИВЕРСАЛЬНЫЙ ТЕХНИЧЕСКИЙ АНАЛИЗ ДЛЯ ЛЮБЫХ ДАННЫХ
-- Анализ цены последней сделки
local price_analysis = MDP:getOrCreate{
market = "TQBR",
ticker = "SBER",
interval = INTERVAL_H1,
param = "last"
}
print("Цена SMA20:", price_analysis:sma(20))
print("Цена RSI14:", price_analysis:rsi(14))
-- Анализ стакана (биды)
local bid_analysis = MDP:getOrCreate{
market = "TQBR",
ticker = "SBER",
interval = INTERVAL_M5,
param = "bid"
}
print("Биды EMA10:", bid_analysis:ema(10))
print("Биды STDDEV20:", bid_analysis:getIndicator("STDDEV", 20))
-- Анализ объема
local volume_analysis = MDP:getOrCreate{
market = "TQBR",
ticker = "SBER",
interval = INTERVAL_M15,
param = "volume"
}
print("Объем SMA30:", volume_analysis:sma(30))
-- 2. КАСТОМНЫЕ ИНДИКАТОРЫ ДЛЯ ЛЮБЫХ ПАРАМЕТРОВ
-- Регистрация индикатора для спреда
MDP:registerIndicator("SPREAD_EMA", function(buffer, period)
if buffer.size < period then return nil end
local sum = 0
for i = 1, period do
sum = sum + buffer:last(i).value
end
return round(sum / period, 4)
end, "EMA for Spread", {"numeric"})
-- Анализ спреда bid/offer
local spread_data = MDP:getOrCreate{
market = "TQBR",
ticker = "SBER",
description = "Bid-Offer Spread"
}
-- Здесь можно обновлять буфер вручную с вычисленным спредом
spread_data:updateBuffer("value", 0.15) -- пример спреда
print("Спред EMA10:", spread_data:getIndicator("SPREAD_EMA", 10))
-- 3. УНИВЕРСАЛЬНЫЙ АНАЛИЗ РАЗНЫХ ТИПОВ ДАННЫХ
local analyses = {
{param = "last", desc = "Price Analysis"},
{param = "bid", desc = "Bid Analysis"},
{param = "volume", desc = "Volume Analysis"},
{param = "value", desc = "Value Analysis"}
}
for _, analysis in ipairs(analyses) do
local data = MDP:getOrCreate{
market = "TQBR",
ticker = "GAZP",
interval = INTERVAL_D1,
param = analysis.param
}
local sma = dat a:sma(20)
local rsi = dat a:rsi(14)
print(string.format("%s - SMA20: %.2f, RSI14: %.1f",
analysis.desc, sma or 0, rsi or 0))
end
-- 4. COMPLEX MULTI-PARAMETER ANALYSIS
-- Анализ нескольких параметров одновременно
local multi_analysis = function()
local price = MDP:getOrCreate{
market = "TQBR", ticker = "SBER", interval = INTERVAL_H1, param = "last"
}
local volume = MDP:getOrCreate{
market = "TQBR", ticker = "SBER", interval = INTERVAL_H1, param = "volume"
}
local bids = MDP:getOrCreate{
market = "TQBR", ticker = "SBER", interval = INTERVAL_M5, param = "bid"
}
local price_trend = price:ema(10) > price:ema(20)
local volume_spike = volume:sma(5) > volume:sma(20) * 1.5
local bid_strength = bids:ema(5) > bids:ema(10)
return price_trend and volume_spike and bid_strength
end
-- 5. DYNAMIC INDICATOR CREATION
-- Создание индикатора на лету
local dynamic_indicator = function()
MDP:registerIndicator("VOLUME_PRICE_RATIO", function(buffer, priceBuffer, period)
if not priceBuffer or buffer.size < period then return nil end
local volume_avg = 0
local price_avg = 0
for i = 1, period do
local vol_item = buffer:last(i)
local price_item = priceBuffer:last(i)
if vol_item and price_item then
volume_avg = volume_avg + vol_item.value
price_avg = price_avg + price_item.value
end
end
volume_avg = volume_avg / period
price_avg = price_avg / period
return volume_avg / math.max(price_avg, 0.001)
end, "Volume-Price Ratio", {"volume"})
end
Преимущества MARKETDATA_PRO v1.0:
1. Единый технический анализ - одни и те же индикаторы для любых параметров; 2. Поддержка 4-го параметра - анализ bid, offer, volume, value и любых других данных; 3. Универсальные буферы - хранение истории для любых типов данных; 4. Расширяемая система индикаторов - глобальный реестр с поддержкой кастомных индикаторов; 5. Автоматические алиасы - удобные короткие методы (sma, ema, rsi и т.д.); 6. Типизированные данные - разделение на price, volume, numeric и другие типы; 7. Производительность - интеллектуальное кэширование и управление памятью.
Теперь можем применять единые методы технического анализа к любым данным QUIK!
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 19:41:56
nikolz, 1. Вы не отвечаете на заданные Вам вопросы, ну как минимум в общении это не вежливо! , для меня это и не важно. 2. Ну, нужны Вам все эти гигибайты истории, да и храните, я же не против, я привёл паттерн для текущей задачи. 3. Именно так создал, этот подход убираю ошибки для тестирования. 4. С песней в точку что вижу, с чем разбираюсь, про то и пою, 20 раз уже на это отвечал, если есть проблемы с памятью я записывайте, нет мне несложно повторить и 100 раз одно и тоже. 5. И уж пожалуйста, про время не нужно, оно мне интересно в рамках исполнения моих задач, описанных в скрипта. А про оптимизацию в песнях ни слова. Задачей оптимизации, следящий раз, сейчас найти приемлемое решение для задач описанных выше! 6. Возможно у такого специалиста есть рекомендации по задаче? Или "Слов из песни не выбросить"?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 18:42:24
Еще раз. Идеальный производственный паттерн работы с QUIK: В QUIK нет смысла "стримить" все свечи постоянно — нужно один раз получить исторический буфер и дальше обновлять только последнюю (текущую, незакрытую) через callback/опрос?
Тогда, Алгоритм модуля MarketData_Pro.Poller, который: а) Загружает исторические свечи (100–500 штук) в UniversalBuffer при инициализации. б) Держит кеш последней свечи (текущий бар) отдельно. с) Обновляет кеш по событию или через быстрый опрос QUIK (getParamEx / getCandlesByIndex). д) По таймфрейму??? проверяет закрытие свечи > переносит кеш в буфер и очищает кеш? е) Отдает актуальные данные любому индикатору через getValue() или прямой доступ к буферу?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 18:38:34
Существует несколько подходов к организации данных в QUIK. Нужно выбрать структуру для проекта, который будет включать в себя: а) DataPoller.lua (планировщик опросов в корутинах); б) MarketData (модуль для работы с рыночными данными); с) DataManager (менеджер данных, который объединяет все вместе).
Учитывая, что задача стоит избежать фризов и минимизировать задержки, а также обеспечить актуальность данных, предлагается следующий подход:
DataPoller будет заниматься асинхронным опросом данных (через корутины) и обновлением кэша. MarketData будет предоставлять интерфейс для доступа к данным (через метатаблицы с ленивой загрузкой и кэшированием). DataManager будет управлять созданием и жизненным циклом источников данных, а также взаимодействием между Poller и MarketData.
При этом мы можем использовать комбинацию подхода 3 (ООП-ленивый доступ) и 4 (кэш + корутина). Тогда концепция выглядит следующим образом:
1. DataPoller. Создает и управляет корутинами для периодического обновления данных. Каждый источник данных (например, тикер) регистрируется в планировщике. Планировщик обновляет кэш данных в фоновом режиме.
2. MarketData. Представляет объект-источник данных (например, свечи, стакан, параметры инструмента). При первом обращении к полю, если данных нет в кэше, они запрашиваются синхронно (редкий случай, но как fallback (запасной план) ). Основной доступ к данным идет из кэша, который асинхронно обновляется планировщиком.
3. DataManager. Инициализирует планировщик и создает источники данных. Предоставляет интерфейс для получения источника данных (например, по тикеру и интервалу для свечей). Управляет жизненным циклом данных (создание, удаление, обновление).
Пример последовательности: Пользователь запрашивает у DataManager данные по SBER (например, свечи M1). DataManager создает объект MarketData для SBER M1, если он еще не создан, и регистрирует его в DataPoller. DataPoller начинает периодически (каждые N ms) обновлять данные для SBER M1 (например, запрашивать последние свечи и класть в кэш). Пользователь обращается к объекту MarketData (например, candles:getValue("close", -1)), и получает данные из кэша. Таким образом, мы имеем асинхронное обновление данных и синхронный доступ к ним без блокировок?
Теперь код для каждого модуля. Начнем с DataPoller (адаптируем тот, что уже есть, но упростим и настроим под эту задачу).
DataPoller будет: Принимать задачи (источники данных) с callback для обновления. Запускать корутины, которые периодически вызывают callback и обновляют кэш. MarketData (источник данных) будет: Иметь метод update() (который будет вызываться планировщиком) для обновления своих данных. Иметь кэш для хранения последних данных. Предоставлять методы для доступа к данным (например, getValue). DataManager будет: Хранить все созданные источники данных (например, по ключу market_ticker_interval). Создавать новые источники, если их нет, и регистрировать их в DataPoller.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 14:24:04
Цитата
nikolz написал: Собственно задачей может быть не только функция, выполняемая в main, но и любой процесс или другой поток со своей VMLua или любом другом языке и даже в облаке или у соседа на компе.
Вот этого точно, не обсуждаю. 1 терминал, 1 маин, множество корутин или сейчас рассматриваю как предлагал альтернативу Nikolay, . Все остальное к программистам системщикам или TGB,
Цитата
nikolz написал: Свчеи хранятся в сжатом формаье (степень сжатия примерно 7 раз . 10 лет SBER на 1 мин это 2 млн свечей. Сжатый объем 28МБайт.
Но это тоже для Ваших каких то специфических задач. "Дата соурсе" в квик организовано как интерфейс получения данных о свечах, получил к примеру 100 бар в буфер, обработал расчеты допустим индикатора и все. Обновляется буфер согласно тайм фрейма. Текущее (не завершенную свечу) держим в кеш, обновляется оперативно по колбеку.
Я у Вас спрашивал как вы обрабатываете события последовательно перебираете очередь или есть приоритеты, если есть то чем обосновываете?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 14:00:46
nikolz, А можете описать полный алгоритм, и если приоритеты, если есть на чем основываете? Будет интересно, думаю не только мне.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:50:07
Асинхронность понятно что в условиях маин можно говорить про условную "асинхронность", не я придумал, ни мне отменять, а употребляется для понимания вопроса.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:46:46
Хорошо, Вы можете показать оптимальный подход в квик, для получения и обработки оперативных данных, именно оперативных?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:36:41
TGB, Мне точно Вас не хочется комментировать, и ребенок здесь похоже один, хотя и образованный. Ставлю даже 1 минуту, сказать для каких задач, или уже догадаешься?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:14:50
Имелось в виду "таблиц всех сделок", ну конечно необходимы и другие для полного функционала.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:12:06
Nikolay, Ну а сколько можно обработать таблиц высоко ликвидных инструментов? Мой скрипт, допустим отстает в стаканах, даже по лимитным заявкам, на высоко ликвидных в часы пик. Возможно подход не очень?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 13:07:39
Альтернативный способ, так называемый "Реактивный ленивый доступ", мета табличный доступ через "__index", где при чтении - получении, допусти "marketdata.LAST" автоматически вызывается getParamEx. Что хорошо для "on-demand" доступа, предоставление ресурсов или функциональности по требованию, а не постоянно, но плохо для высоко частотных опросов, каждый доступ = новый API вызов.
Тогда какие подход возможны?
1. Прямой вызов API, getParamEx() в каждом месте медленно, риск фризов редко запрашиваемые данные. 2. Опрос через корутину, отдельные циклы с sleep(), требует аккуратного управления, периодическое обновление состояния. 3. ООП-ленивый доступ (__index), автоматически тянет нужные поля, дублирует вызовы, удобно для оберток и индикаторов. 4. Кэш + корутина, кэш обновляется асинхронно, сложнее структура, пожалуй лучший баланс для скриптов с торговой логикой.
И следовательно, предварительная структура блока, состоит из модулей: * DataPoller.lua - модуль-планировщик опросов QUIK-данных в корутинах. * MarketData. * DataManager.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 12:14:01
1. Стакан все таки не очень показательно, речь идет об обработке большого количества бумаг портфеля, а информация чисто логически из выше сказанного. 2. Здесь речь про блокировку терминала, особенно в в часы пик.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 15.06.2023
05.11.2025 10:11:45
Пожалуй основной вопрос в этой задаче (ключевой вызов в QUIK Lua-интеграции) — это организация опроса данных (polling) без блокировок и с минимальной нагрузкой на терминал. Проблема опроса данных в QUIK
Все функции QUIK API синхронные. Вызовы getParamEx, getItem, getQuoteLevel2, getCandles и т.п. — блокирующие. Если их дергать часто, они начинают “затыкать” поток исполнения и могут даже вызывать таймауты при большом количестве бумаг?
Основной поток main() нельзя блокировать. main() — это кооперативная петля; если вставить бесконечный цикл без sleep, терминал “зависнет”.
Лучшее решение на мой не профессиональный взгляд опрос в отдельной корутине. Почему именно корутина?
Lua-корутины позволяют “распараллелить” логику.
Можно делать yield-циклы с sleep(1000) без потери отзывчивости терминала.
Каждая корутина может следить за своим источником данных (деньги, позиции, котировки и т.п.).