Система принятия решений и/или Нечеткая логика(FuzzyLogic)

Страницы: Пред. 1 ... 8 9 10 11 12
RSS
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Повторю еще раз. Подписка делается однократно при запуске робота.  Т е она не влияет на его работу никак.
 
nikolz,  И в примере выше подписка сделана один раз, перед созданием потока луа, более того подписка то прошла, ответ true? А индекс = 0? Речь идет о тиковых данных. А количество инструментов тут не причем, разве только все усугубить нужно, но проблематика прекрасна видна на одном инструменте.  Я ведь ни чего не придумал, нет тут от "себятины":

"param – необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок, если задан – данные по этому параметру.

Функция возвращает таблицу data_source в случае успешного  завершения. Если указан неверный код класса, код инструмента, интервал или  параметр, то возвращается «nil». При этом error_desc содержит  описание ошибки.  

Функцию CreateDataSource можно использовать только внутри функций main() и callback."
 
Цитата
VPM написал:
Минимальный рабочий Скрипт для 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  = 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
У Вас в скрипте ошибка
Надо подписываться   не так CreateDataSource(class_code, sec_code, 1,"last")
а так
CreateDataSource(class_code, sec_code, 1)  
 
VPM,
Поясняю.
"Все  смешалось, кони, люди"
--------------------  
Вы подписываетесь на параметр из ТТП  а ждете свечи.Вы уж определитесь.
------------------------------------------------------------------------
"А, ты за большевиков, али за коммунистов?"
 
nikolz,  Это подписка на тиковые данные согласно документации Руководство пользователя QUIK © ARQA Technologies
Цитата
VPM написал:
"param – необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок, если задан – данные по этому параметру.
 
VPM, А чему Вы удивляетесь? Это не я придумал? Таланты в стране, ни чего не поделаешь.
Цитата
nikolz написал:
"А, ты за большевиков, али за коммунистов?"
Я за индивидуальных ТРЕЙДЕРОВ, которым нужны простые рабочие варианты. По сути если обобщить получение данных из квик, есть 2 основных варианта:
1. с помощью параметров (class_code, sec_code)
2. firmid, client_code.

А есть особые случаи!!!
 
Цитата
Nikolay написал:
Т.е. кидаем запросы атомарно, создаем задачу для проверки ответа
Поясните?

Подпиской создали таблицу интерфейса для получения данных, а дальше в потоке луа получаем ds:O(I).
 
Цитата
VPM написал:
Поясните?

Подпиской создали таблицу интерфейса для получения данных, а дальше в потоке луа получаем ds:O(I).

Вы так восторгались корутинами, что подход запрос -> чтение ответа через вызов-проверка должен быть очевиден. Самое главное - у нас нет понятия сколько времени займет приход ответа. Может 100 млс, а может 5 минут.
Поэтому нельзя использовать любые подходы с циклами ожидания с какой-то заданной величиной. Да, необходима какая-то отсечка по времени, чтобы отсекать проблемные запросы.

Вот наивная реализация такого подхода. Специально добавил счетчики как задачи из прошлого примера, чтобы было видно, что можно переключаться между разного рода задачами.
Наивная реализация потому что в реальности необходимо учитывать, что задачи могут быть вытесняющие, с приоритетами, последовательными, с многими внутренними шагами и т.д.

Также стоит учитывать, что простая проверка размера ds:Size() - это слишколм просто. Я проверяю время последнего бара и время последней сделки, чтобы избежать порционного получения данных, когда размер уже не 0, но он еще не последний.
Код
local is_run = true

if _G.message then
    print = function(...) _G.message(table.concat({...}, ", ")) end
end

local task_queue = {}
local function AddActionResult(task, is_done, is_error, mes)
    if not task then return end
    if is_done then
        task.done         = true
        task.error        = false
        task.response_mes = tostring(mes or '')
    elseif is_error then
        task.done         = false
        task.error        = true
        task.response_mes = tostring(mes or '')
    end
end

local function Process(task)
    if not task then return end
    if not task.process then return end
    if not task.in_progress then task.in_progress = true end
    AddActionResult(task, task.process())
end

local function Dispatch()
    if not is_run then return end

    local count = 1
    while is_run and #task_queue > 0 do
        local task = task_queue[count]
        if task and not (task.done or task.error or task.stop) then
            Process(task)
        end
        if task and (task.done or task.error or task.stop) then
            task.in_progress    = false
            local response_mes  = ''
            if not task.silent or not task.done then
                if task.done then
                    response_mes = 'Задача выполнена успешно: '..tostring(task.description)
                elseif task.error then
                    response_mes = 'Задача не выполнена: '..tostring(task.description)..', по причине: '
                elseif task.stop then
                    response_mes = 'Задача остановлена: '..tostring(task.description)
                end
                print(response_mes)
                if (task.response_mes or '')~= '' then                    print('\t'..(task.response_mes or ''))
                end
                if type(task.done_callback) == 'function' then task.done_callback(task) end
                if type(task.err_callback) == 'function' then task.err_callback(task) end
            end
            table.sremove(task_queue, count)
            count = count - 1
        end
        if count + 1 >= #task_queue then
            if #task_queue == 0 then print('Очередь задач пуста') end
            return
        end
        count = count >= #task_queue and 1 or count + 1
    end
end

local function create_ds(ctx, done_callback, err_callback, wait_time)
    if not ctx then return end

    local ds, err = _G.CreateDataSource(ctx.class_code, ctx.sec_code, ctx.interval)
    if not ds then
        print(err, 3)
        return
    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)

    wait_time       = wait_time or 60
    local lt        = os.time()

    local task = {description = 'Заказ данных '..ds.description, ctx = ctx}

    task.process = function()
        if os.time() - lt >= wait_time then return false, true, 'Не удалось инициализировать инструменты за время '..tostring(wait_time)..'сек.' end
        local size = ds:Size()
        if size == 0 then return end
        ds.done_request = true
        return true, false, 'Получены бары '..ds.description..', размер: '..tostring(size)
    end
    task.done_callback  = done_callback
    task.err_callback   = err_callback

    task_queue[#task_queue+1] = task
end

local function counter(i, limit)
    local x = 0
    local task = {description = 'Счетчик до '..tostring(limit)}
    task.process = function()
        x = x + 1
        if x >= limit then
            return true, false, string.format('%i: Счетчик до %i завершен', i, limit)
        end
    end
    task_queue[#task_queue+1] = task
end

local  sec_list = {}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 1}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 2}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 5}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 10}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 20}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 10}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 2}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 5}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'LKOH', interval = 5}
sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'FEES', interval = 5}
sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'SiZ5', interval = 5}
sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 5}
sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 15}
sec_list[#sec_list+1] = {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
        Dispatch()
        sleep(100)
    end
end

function OnStop()
    is_run = false
end

В итоге можно заказать много потоков, но пока не принято решение, что данные получены, есть задача проверки. И не важно сколько времени это займет. Также и с транзакциями. Например, сегодя с утра один из брокеров обрабатывал транзакции 2 минуты, хотя обычно менее секунды. Но т.к. нельзя сказать сколько времени займет процедура запрос-ответ, то и просто ждать 30 секунд нельзя. Да и 2 минуты нельзя, т.к. завтра может придется ждать 5 минут.
 
Запустил у себя, лог:
Код
   Тип   Дата   Время   Сообщение
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   Очередь задач пуста

Все задачи Выполнены.
Но ведь это тот же самый вариант? Отличие Ваш скрипт ждет подписки (скорее подписка чем получение), а наш блокирует исполнение, привлекая внимание пользователя, передавая ему управление. (Смысл - Допустим, заблокируй не рабочий тикер, и запусти по новой).
В Вашем подходе будет все висеть пока все тикеры не подпишутся. Допустим сменился тикер у фьючерса, пользователь в надежде  что все работает в автомате? (Это просто частный случай, Вы сами утверждаете, что ситуация мало прогнозируема). А основной поток луа (цикл) остается не рабочем? Тогда уж, все исполнять нужно в основном цикле, с фиксацией состояния подписки, чтоб не повторять запросы?
 
Я не понял комментарий. Есть контекст. В нем открываем ds и запускаем задачу. У ds есть признак done_request.
В очередь задач кидаем функцию проверки размера. Эта задача ничего не блокирует, т.е. можно в рамках контекста выполнять другие задачи, например, обработать сделки, совершенные пользователем, команды интерфейса и т.д.
А процедура, которая зависит от ds, просто ждет когда признак done_request изменится.

Код
В Вашем подходе будет все висеть пока все тикеры не подпишутся

Что будет висеть? Вызов Dispatch() - это один из методов main, коих может быть бесчисленно число. Т.е. обработали задачи, какие-то завершились, а какие-то нет. Но это не значит, что висит, просто переходим к дальнейшему выполнению main, после возврата из Dispatch(), т.к. он не блокирующий. В нем просто перебираем накопившиеся задачи и выходим после прохода по очереди.
 
Теперь я ничего не понял? Вот это место:  
Код
    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
 
 
Цикл for i = 1, #sec_list do - это просто пример организации заказа данных. Он выполняется однократно и ничего не блокирует. С тем же успехом можно было бы вставить где-то в другом месте вызов заказа данных.

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

       count = count + 1
       if count > #task_queue then
           if #task_queue == 0 then print('Очередь задач пуста') end
           return
       end
 
Так и в нашем упрощённом варианте предусмотрен выход из цикла подписки.  Либо передача управления в основной цикл (поток луа), либо вообще остановка скрипта, так как данных нет, обрабатывать дальше не чего. Но это уже на усмотрение архитектуры решаемых задач.

Переписал с помощью корутин, здесь их применение наиболее показательно.
Код
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
 
 
Кажется я уловил идею, цикл до основного потока это отдельная не блокирующая основной цикл задача! Супер.
 
Цитата
VPM написал:
Так и в нашем упрощённом варианте предусмотрен выход из цикла подписки.
Может я, конечно, невнимательно смотрел примеры, но все одни предполагали ожидание через цикл. Т.е. заказали - и тут же ждем. В итоге заказ 100 источников растягивается во времени, т.к. последний будет заказан только через 100*время ожидания. Что долго. Подход заказали все сразу в цикле и потом ждем все в цикле лучше, но тоже заблокирует скрипт пока ждем циклом. Здесь же заказ всех сразу. И периодически просто атомарно  "тыкаем палочкой" на предмет данных. Пришли - можем делать что-то с данными. Нет - переходим к другим задачам, а эта пока путь остается. Т.е. ожидание не мешает другим задачам не связанным с данными, коих может быть много в скрипте.
 
Не, не Вы правы это я невнимателен, не сразу рассмотрел идею. "Доходит до утки, на третьи сутки" из этой области.
 
С этим разобрались, идея классная и правильная! Но мой эксперимент сводился к получению данных с использованием 4  необязательного параметра, задача получить ("LAST", "NUMCONTRACTS", "NUMBIDS", "NUMOFFERS", "BIDDEPTHT", "OFFERDEPTHT")  в виде свечей и применить к ним технический анализ?

Ни ужели не кто ни использует?  
 
Цитата
Nikolay написал:
Цитата
VPM написал:
Так и в нашем упрощённом варианте предусмотрен выход из цикла подписки.
Может я, конечно, невнимательно смотрел примеры, но все одни предполагали ожидание через цикл. Т.е. заказали - и тут же ждем. В итоге заказ 100 источников растягивается во времени, т.к. последний будет заказан только через 100*время ожидания. Что долго. Подход заказали все сразу в цикле и потом ждем все в цикле лучше, но тоже заблокирует скрипт пока ждем циклом. Здесь же заказ всех сразу. И периодически просто атомарно  "тыкаем палочкой" на предмет данных. Пришли - можем делать что-то с данными. Нет - переходим к другим задачам, а эта пока путь остается. Т.е. ожидание не мешает другим задачам не связанным с данными, коих может быть много в скрипте.
А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
 
Круто нагородили.
 
Цитата
nikolz написал:
А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
Только то что могут ни когда не прийти! Или на низко ликвидных завтра подойти!
 
Ведь особенность такого заказа local ds, err = _G.CreateDataSource(ctx.class_code, ctx.sec_code, ctx.interval) "Если параметр не задан, то заказываются данные на основании таблицы обезличенных сделок". Следовательно если сделок нет по инструменту то и нет подписки, ну или ds:Size() = 0, как это было в моем примере?

Кстати не понятно почему, откуда взялся 0, почему не nil?
 
Цитата
nikolz написал:
А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
Не так, что этот колбек будет вызываться на всех барах истории, начиная с 1. Также он будет дергаться на каждую сделку. Это все лишние телодвижения. По крайней мере мне необходимо пройтись по последним, скажем 100 барам, а далее один раз на новый бар. Но да, можно и так, если организовать доп. проверки в этом колбеке.
 
Цитата
Nikolay написал:
Цитата
nikolz написал:
А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
Не так, что этот колбек будет вызываться на всех барах истории, начиная с 1. Также он будет дергаться на каждую сделку. Это все лишние телодвижения. По крайней мере мне необходимо пройтись по последним, скажем 100 барам, а далее один раз на новый бар. Но да, можно и так, если организовать доп. проверки в этом колбеке.
Вы не правы.
он дергается основным потоком ровно тогда когда тот запихивает данные в хранилище.
Если нам не надо реагировать на незакрытую свечу, то в колбеке просто ее игнорируем.
при приходе очередной закрытой свечи заданного тайма колбек вызовет функцию инструмента которому эти данные пришли.
Таким образом никаких лишних телодвижений в потоке main нам делать не надо. И не надо тыкать куда-то чтобы проверить есть или нет данных.
---------------------------
История тоже распознается без проблем
------------------------
Все доп проверки решаются парой операторов if  Это примерно 300 наносекунд затрат времени.
 
Цитата
nikolz написал:
он дергается основным потоком ровно тогда когда тот запихивает данные в хранилище.
Если нам не надо реагировать на незакрытую свечу, то в колбеке просто ее игнорируем.
Я же написал, что для меня - это лишние телодвижения. Нет желания разбираться какой это вызов колбека, холостой на истории или по закрытию бара, или по сделкам внутри бара. Я точно также одним if сравню последний размер выборки с текущим. Плюс уже просто личные субъективные предпочтения - не использую колбеки основного потока.
Это уже дело вкуса. Но как говорится, кому-то подавай ООП со всеми излишествами, мне же простой C - лучший выбор.
 
Вот еще информация к размышлению.
В одном из вариантов робота реализовал подписку в колбеке Onparam.
------------------------
Размер кода функции подписки для любого числа инструментов  12 строк. (Двенадцать строк)
--------------------------
Работает без задержек т е асинхронно.
-----------------------
Вот лог файл работа такой подиписки.  
Время указано в ms ( для справки ms - 1/1000 секунды)
Подписка на 10 интервалов занимает примерно 0.006 сек.  В первой строке список инструментов на которы подписываемся и список интервалов
Когда подписка закончилась то задержка работы колбека  из-за вызова этой функции составляет  4 мкс это 0.000004 сек.
Код
ns={[1]=SBER,[2]=ROSN,[3]=GAZP,[4]=PLZL,[5]=GMKN,[6]=CHMF,[7]=HYDR,[8]=LKOH,[9]=MOEX,[10]=SNGS,[0]=10}
Tint={INTERVAL_TICK,INTERVAL_M1,INTERVAL_M2,INTERVAL_M3,INTERVAL_M4,INTERVAL_M5,INTERVAL_M6,INTERVAL_M10,INTERVAL_M15,INTERVAL_M20,INTERVAL_M30,INTERVAL_H1}; Tint[0]=#Tint;

t(ms)=0.8372,GAZP,QJSIM,int=1,N=11,ds=table: 0000014C184142F0
t(ms)=1.5296,GAZP,QJSIM,int=60,N=10,ds=table: 0000014C18414730
t(ms)=2.1807,GAZP,QJSIM,int=30,N=9,ds=table: 0000014C18416C70
t(ms)=2.8129,GAZP,QJSIM,int=20,N=8,ds=table: 0000014C18416AB0
t(ms)=3.437,GAZP,QJSIM,int=15,N=7,ds=table: 0000014C18418470
t(ms)=4.0609,GAZP,QJSIM,int=10,N=6,ds=table: 0000014C184197B0
t(ms)=4.687,GAZP,QJSIM,int=6,N=5,ds=table: 0000014C183F9870
t(ms)=4.7432,GAZP,QJSIM,int=5,N=4,ds=table: 0000014C183F9D70
t(ms)=5.3711,GAZP,QJSIM,int=4,N=3,ds=table: 0000014C183F9D30
t(ms)=6.0284,GAZP,QJSIM,int=3,N=2,ds=table: 0000014C183FA070
t(ms)=6.7003,GAZP,QJSIM,int=2,N=1,ds=table: 0000014C1804B2D0
t(ms)=6.7394
t(ms)=0.2054,LKOH,QJSIM,int=1,N=11,ds=table: 0000014C1804B590
t(ms)=0.4092,LKOH,QJSIM,int=60,N=10,ds=table: 0000014C1804A850
t(ms)=0.6107,LKOH,QJSIM,int=30,N=9,ds=table: 0000014C1804B010
t(ms)=0.81,LKOH,QJSIM,int=20,N=8,ds=table: 0000014C1804AAD0
t(ms)=1.0044,LKOH,QJSIM,int=15,N=7,ds=table: 0000014C1804B890
t(ms)=1.2009,LKOH,QJSIM,int=10,N=6,ds=table: 0000014C1804BA90
t(ms)=1.3916,LKOH,QJSIM,int=6,N=5,ds=table: 0000014C1804BAD0
t(ms)=1.5861,LKOH,QJSIM,int=5,N=4,ds=table: 0000014C1804C250
t(ms)=1.7787,LKOH,QJSIM,int=4,N=3,ds=table: 0000014C1804BF50
t(ms)=1.9693,LKOH,QJSIM,int=3,N=2,ds=table: 0000014C1804BE10
t(ms)=2.1587,LKOH,QJSIM,int=2,N=1,ds=table: 0000014C1804D550
t(ms)=2.1975
t(ms)=0.1918,PLZL,QJSIM,int=1,N=11,ds=table: 0000014C1804C9D0
t(ms)=0.3954,PLZL,QJSIM,int=60,N=10,ds=table: 0000014C1804CA90
t(ms)=0.597,PLZL,QJSIM,int=30,N=9,ds=table: 0000014C1804CA50
t(ms)=0.7938,PLZL,QJSIM,int=20,N=8,ds=table: 0000014C1804CBD0
t(ms)=0.9937,PLZL,QJSIM,int=15,N=7,ds=table: 0000014C1804E590
t(ms)=1.1861,PLZL,QJSIM,int=10,N=6,ds=table: 0000014C1804D8D0
t(ms)=1.4026,PLZL,QJSIM,int=6,N=5,ds=table: 0000014C1804DF10
t(ms)=1.5999,PLZL,QJSIM,int=5,N=4,ds=table: 0000014C1804DB50
t(ms)=1.7913,PLZL,QJSIM,int=4,N=3,ds=table: 0000014C1804DF90
t(ms)=1.9999,PLZL,QJSIM,int=3,N=2,ds=table: 0000014C1804EF10
t(ms)=2.2249,PLZL,QJSIM,int=2,N=1,ds=table: 0000014C1804E910
t(ms)=2.266
t(ms)=0.003
t(ms)=0.0016
t(ms)=0.0014
t(ms)=0.7523,SBER,QJSIM,int=1,N=11,ds=table: 0000014C1804F3D0
t(ms)=1.3591,SBER,QJSIM,int=60,N=10,ds=table: 0000014C1804F250
t(ms)=2.0204,SBER,QJSIM,int=30,N=9,ds=table: 0000014C18050750
t(ms)=2.616,SBER,QJSIM,int=20,N=8,ds=table: 0000014C1804F8D0
t(ms)=3.1893,SBER,QJSIM,int=15,N=7,ds=table: 0000014C1804FF50
t(ms)=3.2431,SBER,QJSIM,int=10,N=6,ds=table: 0000014C1804FB90
t(ms)=3.8635,SBER,QJSIM,int=6,N=5,ds=table: 0000014C1804F850
t(ms)=3.9166,SBER,QJSIM,int=5,N=4,ds=table: 0000014C1804FC10
t(ms)=4.5119,SBER,QJSIM,int=4,N=3,ds=table: 0000014C18051190
t(ms)=5.1614,SBER,QJSIM,int=3,N=2,ds=table: 0000014C18050A50
t(ms)=5.9995,SBER,QJSIM,int=2,N=1,ds=table: 0000014C18051610
t(ms)=6.0391
t(ms)=0.0043
t(ms)=0.0042
...
t(ms)=0.0016
t(ms)=0.0035
t(ms)=0.3254,CHMF,QJSIM,int=1,N=11,ds=table: 0000014C1804AD50
t(ms)=0.5977,CHMF,QJSIM,int=60,N=10,ds=table: 0000014C1804B610
t(ms)=0.8343,CHMF,QJSIM,int=30,N=9,ds=table: 0000014C1804B550
t(ms)=1.051,CHMF,QJSIM,int=20,N=8,ds=table: 0000014C1804B390
t(ms)=1.2606,CHMF,QJSIM,int=15,N=7,ds=table: 0000014C1804AC50
t(ms)=1.4699,CHMF,QJSIM,int=10,N=6,ds=table: 0000014C1804BE50
t(ms)=1.6765,CHMF,QJSIM,int=6,N=5,ds=table: 0000014C1804C6D0
t(ms)=1.8828,CHMF,QJSIM,int=5,N=4,ds=table: 0000014C1804BC10
t(ms)=2.0797,CHMF,QJSIM,int=4,N=3,ds=table: 0000014C1804C650
t(ms)=2.2755,CHMF,QJSIM,int=3,N=2,ds=table: 0000014C1804D350
t(ms)=2.4727,CHMF,QJSIM,int=2,N=1,ds=table: 0000014C1804CD10
t(ms)=2.5117
t(ms)=0.0018
t(ms)=0.2665,ROSN,QJSIM,int=1,N=11,ds=table: 0000014C1804CF10
t(ms)=0.485,ROSN,QJSIM,int=60,N=10,ds=table: 0000014C1804D010
t(ms)=0.703,ROSN,QJSIM,int=30,N=9,ds=table: 0000014C1804E410
t(ms)=0.9127,ROSN,QJSIM,int=20,N=8,ds=table: 0000014C1804E350
t(ms)=1.1188,ROSN,QJSIM,int=15,N=7,ds=table: 0000014C1804E6D0
t(ms)=1.3883,ROSN,QJSIM,int=10,N=6,ds=table: 0000014C1804DA90
t(ms)=1.5976,ROSN,QJSIM,int=6,N=5,ds=table: 0000014C1804DD50
t(ms)=1.806,ROSN,QJSIM,int=5,N=4,ds=table: 0000014C1804F010
t(ms)=2.0091,ROSN,QJSIM,int=4,N=3,ds=table: 0000014C1804E850
t(ms)=2.2303,ROSN,QJSIM,int=3,N=2,ds=table: 0000014C1804F390
t(ms)=2.4309,ROSN,QJSIM,int=2,N=1,ds=table: 0000014C1804F610
t(ms)=2.4736
t(ms)=0.0013
t(ms)=0.0038
t(ms)=0.0019
...
t(ms)=0.0013
t(ms)=0.0013
t(ms)=0.0031
t(ms)=0.002
t(ms)=0.0028
t(ms)=0.3455,MOEX,QJSIM,int=1,N=11,ds=table: 0000014C180528D0
t(ms)=0.5907,MOEX,QJSIM,int=60,N=10,ds=table: 0000014C18052E10
t(ms)=0.8181,MOEX,QJSIM,int=30,N=9,ds=table: 0000014C18052E90
t(ms)=1.03,MOEX,QJSIM,int=20,N=8,ds=table: 0000014C18052A10
t(ms)=1.234,MOEX,QJSIM,int=15,N=7,ds=table: 0000014C18052FD0
t(ms)=1.4321,MOEX,QJSIM,int=10,N=6,ds=table: 0000014C18053750
t(ms)=1.63,MOEX,QJSIM,int=6,N=5,ds=table: 0000014C18053B50
t(ms)=1.8317,MOEX,QJSIM,int=5,N=4,ds=table: 0000014C180543D0
t(ms)=2.0248,MOEX,QJSIM,int=4,N=3,ds=table: 0000014C18054510
t(ms)=2.2182,MOEX,QJSIM,int=3,N=2,ds=table: 0000014C18053850
t(ms)=2.41,MOEX,QJSIM,int=2,N=1,ds=table: 0000014C18054190
t(ms)=2.4523
t(ms)=0.0014
t(ms)=0.0013
t(ms)=0.0045
t(ms)=0.0029
t(ms)=0.0031
...
t(ms)=0.0036
t(ms)=0.0018
t(ms)=0.0014
t(ms)=0.0012
t(ms)=0.4719,GMKN,QJSIM,int=1,N=11,ds=table: 0000014C18057690
t(ms)=0.8918,GMKN,QJSIM,int=60,N=10,ds=table: 0000014C18056A90
t(ms)=1.2724,GMKN,QJSIM,int=30,N=9,ds=table: 0000014C18056FD0
t(ms)=1.6336,GMKN,QJSIM,int=20,N=8,ds=table: 0000014C180569D0
t(ms)=1.9807,GMKN,QJSIM,int=15,N=7,ds=table: 0000014C18057110
t(ms)=2.3227,GMKN,QJSIM,int=10,N=6,ds=table: 0000014C18058350
t(ms)=2.6585,GMKN,QJSIM,int=6,N=5,ds=table: 0000014C180579D0
t(ms)=3.0039,GMKN,QJSIM,int=5,N=4,ds=table: 0000014C18058210
t(ms)=3.3355,GMKN,QJSIM,int=4,N=3,ds=table: 0000014C18058750
t(ms)=3.6669,GMKN,QJSIM,int=3,N=2,ds=table: 0000014C18058310
t(ms)=3.995,GMKN,QJSIM,int=2,N=1,ds=table: 0000014C18057DD0
t(ms)=4.0628
t(ms)=0.0028
t(ms)=0.0025
t(ms)=0.0034
t(ms)=0.0019
t(ms)=0.0017
t(ms)=0.0015
...
t(ms)=0.0014
t(ms)=0.0032
t(ms)=0.0015
t(ms)=0.0014
t(ms)=0.0044
t(ms)=0.0036
t(ms)=0.0022
t(ms)=0.3542,HYDR,QJSIM,int=1,N=11,ds=table: 0000014C18055210
t(ms)=0.6975,HYDR,QJSIM,int=60,N=10,ds=table: 0000014C18056010
t(ms)=3.5457,HYDR,QJSIM,int=30,N=9,ds=table: 0000014C180563D0
t(ms)=3.8542,HYDR,QJSIM,int=20,N=8,ds=table: 0000014C18055F10
t(ms)=4.1337,HYDR,QJSIM,int=15,N=7,ds=table: 0000014C18055C50
t(ms)=4.4013,HYDR,QJSIM,int=10,N=6,ds=table: 0000014C18056350
t(ms)=4.6567,HYDR,QJSIM,int=6,N=5,ds=table: 0000014C180570D0
t(ms)=7.2891,HYDR,QJSIM,int=5,N=4,ds=table: 0000014C18056E90
t(ms)=7.5775,HYDR,QJSIM,int=4,N=3,ds=table: 0000014C18057710
t(ms)=7.8695,HYDR,QJSIM,int=3,N=2,ds=table: 0000014C180577D0
t(ms)=8.1107,HYDR,QJSIM,int=2,N=1,ds=table: 0000014C18058190
t(ms)=8.1587
t(ms)=0.0017
t(ms)=0.0012
t(ms)=0.0041
 
Цитата
VPM написал:
Переписал с помощью корутин, здесь их применение наиболее показательно.
  Это можно сделать короче:
Код
RUN = true
function main()
   -- Функции для асинхронного запроса свечей ---
-- 1. Массовый запрос свечей BulkRequestCandles.
-- Параметр: таблица {{class_code, sec_code, interval}}
-- Результат: {{class_code, sec_code, interval, ds}}
   local BulkRequestCandles = function(par)
      for i = 1, #par do
         par[i].ds = CreateDataSource(par[i].class_code, par[i].sec_code, par[i].interval)
      end
   end
----------------------------------------

   -- 2. Проверка запроса свечей CheckingCandleRequest.
   -- Параметр: таблица {{class_code, sec_code, interval, ds}}
   -- Результат в таблице парамктров : {{class_code, sec_code, interval, ds, ok}}
   -- Значения ok: true - данные начали поступать; nil данные еще не поступили; 
   --              false - ошибка в параметрах запроса
   -- Знвчение функции: количеситво источников еще ожидающих данные --
   local CheckingCandleRequest = function(par)
      local N = #par
      local ds
      for i = 1, #par do
         ds = par[i].ds
         if type(ds) == 'string' then -- обнаруженная ранее ошибка в параметрах запроса
             N = N - 1
         else
            if par[i].ok == nil then  -- еще не дождались данных
               if ds == nil then      -- обнаружена ошибка
                  par[i].ds = '  *** Ошибка в параметрах запроса'
                  par[i].ok = false
               else
                  -- проверка поступления данных
                  if ds:Size() > 0 then -- есть данные 
                     par[i].ok = true
                     N = N - 1 
                  end
               end
            else 
               N = N - 1 
            end
         end
      end
      return N
   end
   -------------------------------------------------
   local  sec_list = {}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 1}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 2}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 10}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'SBER', interval = 20}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 10}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 2}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'GAZP', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'LKOH', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'QJSIM', sec_code = 'FEES', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'SiZ5', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 5}
   sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'RIZ5', interval = 15}
   sec_list[#sec_list+1] = {class_code = 'SPBFUT', sec_code = 'SRZ5', interval = 30}

   BulkRequestCandles(sec_list)
   --------------
   local DS = false
   while RUN do
      -- Проверка поступления свечей (без блокирования цикла обработки)
      
      if CheckingCandleRequest(sec_list) == 0 and not DS then
         DS = true
         -- Отладочная печать --
         for i = 1, #sec_list do
            if sec_list[i].ok == true then 
               message(sec_list[i].sec_code ..'  ds:size() = ' .. sec_list[i].ds:Size()
                        ..'  interval = ' .. sec_list[i].interval)
            else  -- Ошибка задания параметров
               message(sec_list[i].sec_code..'  interval = ' .. sec_list[i].interval
                        .. sec_list[i].ds )
            end
         end
      end
      
      --  Выполнение заданий скрипта --
      
      sleep (100)
   end 
end

function OnStop(signal)
   RUN = false
   return 5000
end
Страницы: Пред. 1 ... 8 9 10 11 12
Читают тему
Наверх