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

Страницы: Пред. 1 ... 7 8 9 10 11 След.
RSS
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Забудьте про слова асинхронность, потоки и т.д. Для начала необходимо зафиксировать все ситуации, которые могут привести к проблемам. А потому же решать вопросы про архитектуру. У Вас же все наоборот.

Представьте, что Вы в начале 90-ых, когда почти все писалось синхронно. Задачи же решались.

Цитата
Ожидание ответа в цикле main приводит к проблеме - зависанию
Потому что так делать нельзя. Любой блокирующий цикл - это зло.

OnTransReply - это колбек, ответ на отправку транзакции. Это не результат, а все лишь ответ. Он нужен чтобы прочитать ошибку отправки, чтобы не ждать ордер далее, т.к. он уже не появится. Все. В этом плане - это единственный колбек, который не вызывает вопросов.
Поэтому если отправили транзакцию на ордер, то результат - это не колбек OnTransReply, а появление записи по этому ордеру в таблице ордеров. Колбек же OnOrder - это уже следствие появления этой записи, а не наоборот. Любители обработки колбеков вынуждены решать вопросы с их приходом: гарантированность, последовательность, многократный приход, пропуск колбека за время простоя.
Т.е. если Вы решили их использовать, то сначала решите все эти вопросы на бумаге, потом уже в коде.

И подход решения этих проблем не связан с асинхронность. Я подозреваю, что Вы за этим термином понимаете просто "непоследовательность". Но это не решает вопрос, тем более, если пишите скрипт для одного инструмента.
Вот когда их много, тогда уже необходимо задумываться о разбивке одной задачи на подзадачи. Например, установить 100 ордеров при старте торговой сессии.

Задача сведется к подзадачам:

- Отправить транзакцию, с учетом лимита на число транзакций в секунду.

- Прочитать ответ транзакции. Найти ордер по транзакции. Это одна задача, т.к. ордер может появится раньше. Если ответ транзакции первый и там ошибка, то вернуться к пункту один или прекратить выполнение, в зависимости от алгоритма.

- Если это ордер с ожиданием сделок (рыночный), то если есть флаг исполнения ордера ожидать сделки по ордеру до исполнения количества. Но можно и не ждать, если алгоритм позволяет игнорировать это.

- Попутно проверять состояние ордера, т.к. он может быть снят и, возможно, его необходимо восстановить.

-- и т.д.

Т.о. выполнение задачи может быть долгим, но смысл разбиения в том, чтобы пока одна подзадача ждет результат (ждет не в блокирующем цикле), другая начала выполнение. И этот подход - это просто оптимизация. Как Вы это будете решать - дело ваше. Можете ждать колбек, может сами сканировать флаги, таблицы на новые записи.

Если вернуться к "Ожидание ответа в цикле main приводит к проблеме - зависанию", то решение - это по приходу колбека OnTransReply записать в некую таблицу результат по номеру транзакции. А уже подзадача проверки просто проверит в этой таблице на наличие записи. И сделает она это тогда, когда к этой подзадаче вернетесь, т.е. никакого ожидания с циклом. Тем более, что совершенно не понятно какое время ожидания указать. Много видел примеров с ожиданием 30 секунд. Всегда было интересно откуда эта цифра, а почему не 45? А если ордер пришел раньше ответа транзакции, то и проверка будет уже не особо нужна.

Что касается перезапуска скрипта, то здесь все очевидно - сохранение состояния скрипта, чтение при запуске, актуализация состояния по текущим данным после запуска. За время простоя ордера могли исполнится, быть сняты, руками закрыта, открыта позиция и т.д. Т.о. задача проверить все сохраненные данные и принять решения по выявленным расхождениям. Без решения этой задачи скрипт становится достаточно опасным для использования.

Т.о. рабочий скрипт будет 80% времени заниматься служебными задачами - контролем соединения; состоянием сессии; статусом торгов по инструменту; обслуживать интерфейс, если он есть; обновлять данные с сервера; проверять статусы ордеров, если не используются колбеки; проверять изменения позиции, баланса по деньгам и т.д. А так называемый алгоритм, который всего лишь автоматизирует торговые команды - это не самая большая часть скрипта. Поэтому складывается впечатление, что Вы начинаете не с того. Уж тем более не столь важно как технически реализован алгоритм, если скрипт не позволяет пользователю себя остановит и продолжить с того же места, не умеет останавливаться когда торговая сессия не идет и т.д.
 
Nikolay,  Ну я не знаю где у этой гидры хвост, а где голова. Я строю модульный вариант. 80% решается в другом модуле  DataManager + get API (Получился не большой универсальный Фреймворк)  окончательный этот вариант или нет, не могу сказать пока, ключевое здесь возможность многократного использования.  
Того же добиваюсь от AOL -  для автоматической системы надежность и вообще как он сделан имеет ключевое значение, если он не рабочий, Все остальное ни имеет смысла как бы оно не работало! Мне нужен универсальный, надежный, для многократного использования (принцип - "написал и забыл") ,  для одного инструмента - это просто упрощение.

Если я Вас правильно понимаю, фоновые решения предлагаете решать через "замыкания"? И решения поиска ордеров и сделок в таблицах квик?
 
Я не навязываю никаких решений. Боле того, не использую термин "фоновое", т.к. такого нет в Lua.

Задачи с ожиданием решаются через переключение. Как это делать - вопрос второй, хотите корутины - делайте. Дискуссия была про то, что корутины это не единственное, и уж те более не идеальное решение. Не более.

Если есть ожидание, то просто переключаетесь на другую подзадачу и она становится активной. Прошлая не становится фоновой, а просто на стеке запоминается ее состояние, чтобы при переключении на неё, можно было бы выполнять её не с самого начала заново. Но это не делает её фоновой, т.к. она ничего не делает, как только мы вышли из неё.

Если у Вас уже есть решение по обработки серверных данных, то и используйте его. Речь была про то, что это решение должно быть независимым от реализации алгоритма. Это просто набор методов, предоставляющий интерфейс. Соответственно скрипт должен просто дергать его методы, принимать решения по ответам.
 
Но Вы же сами пишите, с чем можно сталкиваться, то не пришло, то не то пришло, а с таймерами вообще не понятно что делать, сколько ждать, ждать или не ждать? (Вечный философский вопрос: "Быть или не Быть?"  :smile:  ).  Да и вопрос встает как опрашивать, последовательно перебирая, но ведь приходят ни пойми как? Накидал асинхронный вариант с машиной состояний и процедурный (после всех выкрутасов конечно проще, но отвечает ли в полной мере на все вопросы?).
 
Цитата
Nikolay написал:
Поэтому если отправили транзакцию на ордер, то результат - это не колбек OnTransReply, а появление записи по этому ордеру в таблице ордеров. Колбек же OnOrder - это уже следствие появления этой записи, а не наоборот.
Вы ошибаетесь, как раз наоборот
Сначала будет колбек,OnOrder, а потом появится запись в таблице заявок.
 
Цитата
nikolz написал:
OnOrder
Как это придет в терминал не детерминировано. Зато известно за что отвечает колбек OnOrder - за изменение информации о ордере. Информация записывается в таблицу ордеров и вызывается колбек. Я пока еще не видел сообщений от разработчиков о том, что колбек всегда приходит раннее информации о ордере в таблице ордеров. Допускаю что это приходит в одном информационном пакете. Как его разберет терминал тоже неизвестно.
Т.е. вероятно, что может прийти ранее. А может и нет.
 
Цитата
Nikolay написал:
Любая процедура, вызванная из main не блокирует QUIK. Любая. Хоть завернутая в корутину, хоть вызванная напрямую, хоть в замыкании.
Присоединяюсь  
 
Замечу, что замыкание можно заменить обычной функцией с передачей ей таблицы с параметрами, которые хранятся в замыкании.
Такая реализация проще в понимании и полностью эквивалентна замыканию.
 
И так обсудили разные подходы по организации полного жизненного цикла заявки. Каким подходом пользоваться, каждый определяет для себя сам. Это архитектурная дилемма. Так как окончательного мнения у меня не сложилось, буду пользоваться наиболее понятными для меня подходами. Задача все еще прежняя, собрать модульную структуру в которой торговые стратегии работают независимо отдавая приказы на исполнение. И технологическая, все это дело обслуживает.

Таким образом можно выделить 3 главных блока, которые взаимодействуют ка между собой так и с апи  квик.
А. полный жизненный цикл заявки.
Б. полный жизненный цикл  сделки.
С. полный жизненный цикл money.

Следовательно в блоках можно условно выделить основное взаимодействие, это пары:
1. заявка / сделка = depo;
2. актив depo / актив money, что в свою очередь можно представить как depo + money = capital.

Следовательно, следующая задача,  нужно организовать жизненный цикл money.
 

В этом случае образуется еще одна пара depo / money, которая непосредственно влияет на capital, и требует добавления еще одного жизненного цикла, чтобы контролировать и управлять деньгами, используемыми в торговых операциях. Это важная составляющая системы для адекватного управления капиталом, рисками и средствами, доступными для торговли.

Принципиальное понимание, весь торговый капитал делится на 2 составляющие:

  1. Активный и Пассивный капитал:

    • Пассивный капитал — это средства, которые зарезервированы для покрытия рисков и не используются напрямую в торговле. Эти деньги могут быть зарезервированы для предотвращения убытков или для удовлетворения маржинальных требований, если используем плечо.

    • Активный капитал — это средства, которые мы используем для торговых операций. Из этих средства нужно будет выделить на конкретные тикеры (позиции), которые будут торговаться. Чем больше активных позиций (тикеров), тем больше капитал должен быть задействован для каждой торговой операции.

  • Жизненный цикл Money:

    • Суть этого цикла — это управление средствами, которые будут выделяться для торговли. Этот процесс включает в себя:

      • Распределение средств по активным позициям и тикерам.

      • Контроль за балансом между активами и средствами, доступными для торговли.

      • Актуализация данных по торговым операциям (открытым позициям, маржинальным требованиям и т.д.).

      • Перераспределение средств между различными торговыми активами (тикерами).

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

  •  
     Возможные подходы к организации жизненного цикла "Money". Есть несколько основных подходов для организации такого жизненного цикла, которые могут зависеть от сложности системы и наших бизнес-правил.

    1. Цикл распределения средств (активно-торговые деньги).
    Это подход, при котором для каждого тикера или позиции выделяется определенная сумма из активного капитала, которая будет использоваться для торговли на этом тикере.

    Пример:
    * У вас есть капитал ( C ), и вы хотите распределить его по 10 тикерам.
    * Таким образом, каждый тикер получит сумму ( C / 10 ) для торговли.

    Пример кода:
    Код
    function Trading:allocate_money_for_trading()
        local total_active_capital = self:get_active_capital()  -- Общее количество активных средств
        local total_tickers = self:get_number_of_tickers()      -- Количество активных тикеров
        
        local capital_per_ticker = total_active_capital / total_tickers
        
        -- Для каждого тикера выделяем средства
        for i = 1, total_tickers do
            self:allocate_ticker_capital(i, capital_per_ticker)
        end
    end
    
    function Trading:allocate_ticker_capital(ticker_id, amount)
        -- Логика выделения средств для конкретного тикера
        log_info(string.format("Для тикера %d выделено %.2f средств на торговлю.", ticker_id, amount))
        -- Дополнительная логика управления средствами для конкретного тикера...
    end

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

    Пример:
    * Для более рисковых тикеров (например, с большой волатильностью) вы выделяете меньшую сумму, чтобы уменьшить возможные потери.
    * Для более стабильных тикеров (с низкой волатильностью) выделяется больше средств.

    Пример кода:
    Код
    function Trading:allocate_money_based_on_risk()
        local total_active_capital = self:get_active_capital()
        local ticker_risks = self:get_ticker_risks()  -- Структура риска для каждого тикера
        
        -- Распределяем капитал пропорционально рискам
        for i, risk in ipairs(ticker_risks) do
            local capital_for_ticker = self:calculate_risk_adjusted_capital(total_active_capital, risk)
            self:allocate_ticker_capital(i, capital_for_ticker)
        end
    end
    
    function Trading:calculate_risk_adjusted_capital(total_capital, risk)
        -- Логика расчета капитала с учетом рисков
        return total_capital * (1 - risk)
    end

    3. Цикл обновления и перераспределения капитала (динамическое распределение).
    Этот подход заключается в том, что мы регулярно обновляем капитал, выделенный на торговлю, в зависимости от текущего состояния рынка и состояния активных позиций.
    Например:
    * Когда прибыль с позиции увеличивается, мы можем перераспределить часть этого капитала на другие, более прибыльные тикеры.
    * Если риски становятся слишком высокими, мы можем заморозить капитал на определенных тикерах, чтобы уменьшить возможные потери.

    Пример кода:
    Код
    function Trading:reallocate_capital_based_on_market_conditions()
        local total_active_capital = self:get_active_capital()
        local market_conditions = self:get_market_conditions() -- Получаем текущие рыночные условия
        
        for i, condition in ipairs(market_conditions) do
            if condition == "high_volatility" then
                self:reduce_capital_for_ticker(i)
            elseif condition == "stable_market" then
                self:increase_capital_for_ticker(i)
            end
        end
    end
    
    function Trading:reduce_capital_for_ticker(ticker_id)
        -- Логика уменьшения капитала для данного тикера
        log_info(string.format("Уменьшаем капитал для тикера %d из-за высокой волатильности.", ticker_id))
    end
    
    function Trading:increase_capital_for_ticker(ticker_id)
        -- Логика увеличения капитала для данного тикера
        log_info(string.format("Увеличиваем капитал для тикера %d из-за стабильного рынка.", ticker_id))
    end
    Есть и другие подходы, но на этом этапе нам важно собрать полный жизненный цикл, а оптимизацией можно и потом заняться.

    Что следует учесть:

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

    2. Прочие элементы жизненного цикла:
      * Отслеживание маржи. Если используется маржа (например, при использовании заемных средств для торговли), нам нужно контролировать, сколько капитала выделяется на поддержание маржи для открытых позиций.
      * Риски и лимиты. Управление рисками — это ключевая часть жизни капитала. Нужно учитывать лимиты на потери для каждого тикера и корректно перераспределять капитал, если актив выходит за пределы допустимого.

    Следовательно. Для эффективной работы жизненного цикла money стоит предусмотреть следующие моменты:

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

    Таким образом, жизненный цикл money должен быть организован с учетом наших специфических требований по управлению средствами, рисками и капиталом, что обеспечит гибкость и точность в процессе торговли.
    Как задачка?  :what:  
     
    Цитата
    VPM написал:
    И так обсудили разные подходы по организации полного жизненного цикла заявки. Каким подходом пользоваться, каждый определяет для себя сам. Это архитектурная дилемма. Так как окончательного мнения у меня не сложилось, буду пользоваться наиболее понятными для меня подходами. Задача все еще прежняя, собрать модульную структуру в которой торговые стратегии работают независимо отдавая приказы на исполнение. И технологическая, все это дело обслуживает.

    Таким образом можно выделить 3 главных блока, которые взаимодействуют ка между собой так и с апи  квик.
    А. полный жизненный цикл заявки.
    Б. полный жизненный цикл  сделки.
    С. полный жизненный цикл money.

    Следовательно в блоках можно условно выделить основное взаимодействие, это пары:
    1. заявка / сделка = depo;
    2. актив depo / актив money, что в свою очередь можно представить как depo + money = capital.

    Следовательно, следующая задача,  нужно организовать жизненный цикл money.
    Уу меня получилась два конечных автомата и менеджер задач.
    1) обрабатывает события по OnOrder, OnStopOrder,OnTanseReblay, и все колбеки в которых нет sec_сode.
    2)  обрабатывает колбеки, в которых есть sec_code, кроме указанных ранее.
    3) менеджер задач  запускает задачи торгуемых инструментов.
    2) и 3) объединены в одну функцию для оптимизации скорости работы и затрат памяти.
    ---------------------
    Список существующих задач определяемся в файле init
    -----------------------------------
    Каждая задача записывается в отдельном файле как отдельная функция
    ------------------------------  
    Объем скрипта   составляет 500 операторов(строк),
    из который 300 исполняются лишь при старте скрипта.
     
    Что бы не изобретать очередной велосипед возьму свою систему управления капиталом. Вот структура  и согласование модулей между собой:

    1. Иерархия модулей.

    VinceCapitalManager (верхний уровень)
       v Наследует
    AdaptiveCapitalManager (средний уровень)  
       v Наследует
    CapitalManager (базовый уровень)

    2. Поток данных между модулями.

    CapitalManager > AdaptiveCapitalManager:

    - `total_capital`, `active_capital`, `passive_capital`
    - `money_positions`, `depo_positions`
    - `allocated_capital` - распределение по инструментам
    - Статистика использования капитала

    AdaptiveCapitalManager > VinceCapitalManager:

    - Рыночные режимы и волатильность
    - Метрики риска (VaR, Expected Shortfall)
    - Производительность инструментов (Sharpe, просадки)
    - Система алертов

    В этом случае все что от меня требуется, подключиться к разрабатываемой торговой системе, то есть  по сути согласовать 3 жизненных цикла, простая торговая стратегия все та же, выдает приказы (Что сделаешь Важная командует)
     
    Важное замечание!
    В рамках системы Винса, когда мы говорим о управлении капиталом, важно учитывать не только отдельные тикеры или активы, но и влияние каждого из них на общий капитал.

    Механизм «постоянного доминирования» — это не просто расчет доли капитала для каждого инструмента по отдельности, а полноценное управление всей портфельной позицией с учетом того, как изменения в одной части капитала влияют на общий баланс и в совокупности на капитал как таковой.
    К моему велосипеду еще нужны педали?  :sad:  
     
    "Ни когда не было и вот опять". Прежде чем разбираться с подходами Р. Винса, они направлены на управление портфелями, а задача ставилась изначально возможность работы с одним инструментом и простейшими торговыми стратегиями. Хотя и пересобрал блок "капитал менеджер", текущая задача все таки  несколько другая, не меняя важная, скорее даже основополагающая, ведь от качества полученных данных зависят все остальные расчеты.

    Организация получения данных удобным способом, есть одна из главных задач, собственно с нее то и нужно было начинать, но как понять что необходимо под конкретную задачу, мой подход "ввязаться в бой". Думаю нужен универсальный подключаемый модуль, чтоб не заниматься переделками каждый раз. Тогда задачу условно можно разделить на 2 этапа: получение данных и их управление. Нужно собрать дата менеджер.  
     
    Пожалуй основной вопрос в этой задаче  (ключевой вызов в QUIK Lua-интеграции) — это организация опроса данных (polling) без блокировок и с минимальной нагрузкой на терминал. Проблема опроса данных в QUIK
    1. Все функции QUIK API синхронные. Вызовы getParamEx, getItem, getQuoteLevel2, getCandles и т.п. — блокирующие.
      Если их дергать часто, они начинают “затыкать” поток исполнения и могут даже вызывать таймауты при большом количестве бумаг?

    2. Основной поток main() нельзя блокировать. main() — это кооперативная петля; если вставить бесконечный цикл без sleep, терминал “зависнет”.

    Лучшее решение на мой не профессиональный взгляд опрос в отдельной корутине. Почему именно корутина?
    • Lua-корутины позволяют “распараллелить” логику.

    • Можно делать yield-циклы с sleep(1000) без потери отзывчивости терминала.

    • Каждая корутина может следить за своим источником данных (деньги, позиции, котировки и т.п.).

     
    Цитата
    VPM написал:
    Если их дергать часто, они начинают “затыкать” поток исполнения и могут даже вызывать таймауты при большом количестве бумаг?
    Откуда эта информация? Я как-то писал скрипт записи в базу данных состояние стакана. А другой скрипт читал из нее. Для проверки были запущены два скрипта с окнами этого стакана и выведен сам стакан терминала, что банально сравнить визуально данные. Так вот на глаз между тремя окнами очень трудно было заметить различия.

    Цитата
    VPM написал:
    Можно делать yield-циклы с sleep(1000) без потери отзывчивости терминала.
    Как только Вы вставите в любое место задержку на 1 секунду, цикл main встанет. Не важно где это будет - в самом main или в функции, корутине из этого main. И самое главное - зачем эта задержка аж целую секунду. Чтобы что?
     
    1. Стакан все таки не очень показательно, речь идет об обработке большого количества бумаг портфеля, а информация чисто логически из выше сказанного.
    2. Здесь речь про блокировку терминала, особенно в в часы пик.
     
    Большого это сколько в граммах? Скрипты без интерфейса без проблем обрабатывают тысячу и более инструментов. С интерфейсом 500. Правда здесь стоит учитывать, что для интерфейса желательно задать задержку 50 млс.
     
    Альтернативный способ, так называемый "Реактивный ленивый доступ", мета табличный доступ через "__index", где при чтении - получении, допусти "marketdata.LAST" автоматически вызывается getParamEx.
    Что хорошо для "on-demand" доступа, предоставление ресурсов или функциональности по требованию, а не постоянно, но плохо для высоко частотных опросов, каждый доступ = новый API вызов.

    Тогда какие подход возможны?

    1. Прямой вызов API, getParamEx() в каждом месте медленно, риск фризов редко запрашиваемые данные.
    2. Опрос через корутину, отдельные циклы с sleep(), требует аккуратного управления, периодическое обновление состояния.
    3. ООП-ленивый доступ (__index), автоматически тянет нужные поля, дублирует вызовы, удобно для оберток и индикаторов.
    4. Кэш + корутина, кэш обновляется асинхронно, сложнее структура, пожалуй лучший баланс для скриптов с торговой логикой.

    И следовательно, предварительная структура блока, состоит из модулей:
    * DataPoller.lua - модуль-планировщик опросов QUIK-данных в корутинах.
    * MarketData.
    * DataManager.
     
    Nikolay,  Ну а сколько можно обработать таблиц высоко ликвидных инструментов? Мой скрипт, допустим отстает в стаканах, даже по лимитным заявкам, на высоко ликвидных в часы пик.  Возможно подход не очень?
     
    Имелось в виду "таблиц всех сделок", ну конечно необходимы и другие для полного функционала.
     
    Цитата
    VPM написал:
    Можно делать yield-циклы с sleep(1000) без потери отзывчивости терминала.
      А тогда почему бы не sleep(10000)?  Сделайте у себя и не забудьте потом рассказать об успехах торговли роботом. Терминал у вас точно будет отзывчатым.
      Вообще, я не стал бы вас комментировать, но на форуме могут быть дети :smile:, в вы такое несете.
     
    Цитата
    VPM написал:
    мета табличный доступ через "__index"
    Это медленно. Объекты нужны там где это действительно надо. А надо это редко.

    Как бы вы не обернули и назвали процедуру получения данных из терминала - это все равно будет через один из методов qlua. В данном случае через getParamEx. Можно дополнить кешированием по времени пакета, хотя чтобы его получить тоже придется обратиться к данным терминала.

    Квик, к сожалению, не предоставляет удобных методов, позволяющих отслеживать изменение параметров в реальном времени. Точнее - их нет. Есть событие, что что-то изменилось. А что - уже нет. Поэтому вы просто вынуждены читать их сами. И если цикл алгоритма длинный (сам алгоритм или много бумаг), то за время последнего обращения к параметру в алгоритме (именно в нем), сам параметр мог изменится уже 10 раз. Поэтому и чтение последней цены надо организовывать сложнее чем просто в момент принятия решения. Хотя это все зависит от алгоритма, и может достаточно понять что есть именно сейчас.

    Цитата
    VPM написал:
    Кэш + корутина, кэш обновляется асинхронно
    И опять про асинхронно. Да не выйдет у вас сделать это полноценно хорошо, т.к. эту корутину все равно надо самому вызвать, чтобы она прочитала данные. Сама она, без вызова, ничего не сделает. Поэтому данные обновятся тогда, когда вернетесь в эту корутину. Сколько раз вызовете, столько раз и обновятся.

    Можно использовать колбек OnParam и в нем читать данные, обновляя некую таблицу. А алгоритм уже будет ее читать. И это без всяких корутин. И будет условно "асинхронно", т.к. колбек приходит от терминала, а не по вызову из кода.

    Можно написать скрипт, читающий данные, только это. И, например, сохраняющий в in_memorу database или как-то иначе. А других скрипты уже читают это. Т.о. будет действительно некое подобие распараллеливания. Думать о чтении данных не надо - они есть. Хотя это мало чем отличается от прямого чтения через getParamEx, если принимать решение только на базе текущих данных, а не за историю.
     
    TGB,  Мне точно Вас не хочется комментировать, и ребенок здесь похоже один, хотя и образованный. Ставлю даже 1 минуту, сказать для каких задач, или уже догадаешься?
     
    Хорошо, Вы можете показать оптимальный подход в квик, для получения и обработки оперативных данных, именно оперативных?
     
    Асинхронность понятно что в условиях маин  можно говорить про условную "асинхронность", не я придумал, ни мне отменять, а употребляется для понимания вопроса.
     
    Цитата
    VPM написал:
    Основной поток main() нельзя блокировать. main() — это кооперативная петля; если вставить бесконечный цикл без sleep, терминал “зависнет”.   Лучшее решение на мой не профессиональный взгляд опрос в отдельной корутине. Почему именно корутина?   Lua-корутины позволяют “распараллелить” логику.    Можно делать yield-циклы с sleep(1000) без потери отзывчивости терминала.    Каждая корутина может следить за своим источником данных (деньги, позиции, котировки и т.п.).  
    Решаю эти проблемы так.
    -------------------
    Если main делать нечего, то  ждет события от колбеков.
    ------------------------------
    Колбеки свои события складывают в очередь.
    ------------------------------
    Если очередь не пустая, то main обслуживает очередь.
    -----------------------------------------
    Задачи тоже могут создавать события.
    -------------------------
    Собственно задачей может быть не только функция, выполняемая в main,
    но и любой процесс или другой поток со своей VMLua или любом другом языке и даже в облаке или у соседа на компе.
    --------------------------------
     
     
    nikolz,  А можете описать полный алгоритм, и если приоритеты, если есть на чем основываете? Будет интересно, думаю не только мне.  
     
    Сделал автомат получения свечей с биржи по списку торгуемых инструментов.
    Свчеи хранятся в сжатом формаье (степень сжатия примерно 7 раз .
    10 лет  SBER на 1 мин это 2 млн свечей. Сжатый объем 28МБайт.
    При считывании автоматом распаковываются.
    В результате разработку торговой системы можно делать на истории любой глубины на таймах от 1 мин.
    Текущий торговый день сохраняю из QUIK в несжатом виде.
    На следующий день данные записываются в архив в сжатом виде с биржи.
     
    Цитата
    VPM написал:
    nikolz,  А можете описать полный алгоритм, и если приоритеты, если есть на чем основываете? Будет интересно, думаю не только мне.  
    А смысл? Время уйдет много и не факт что это имеет смысл
    -------------------------
    Могу отвечать на конкретные вопросы,  
     
    посмотрел объем сохраненных данных  за период 10 лет по 26 инструментам.
    Всего   603МБ. сжатых 7Z.  
     
    Цитата
    nikolz написал:
    Собственно задачей может быть не только функция, выполняемая в main, но и любой процесс или другой поток со своей VMLua или любом другом языке и даже в облаке или у соседа на компе.
    Вот этого точно, не обсуждаю. 1 терминал, 1 маин, множество корутин или сейчас рассматриваю как предлагал альтернативу Nikolay, . Все остальное к программистам системщикам или TGB,   :smile:

    Цитата
    nikolz написал:
    Свчеи хранятся в сжатом формаье (степень сжатия примерно 7 раз .  10 лет  SBER на 1 мин это 2 млн свечей. Сжатый объем 28МБайт.
    Но это тоже для Ваших каких то специфических задач.
    "Дата соурсе" в квик организовано как интерфейс получения данных о свечах, получил к примеру 100 бар в буфер, обработал расчеты  допустим индикатора и все. Обновляется буфер согласно тайм фрейма. Текущее (не завершенную свечу) держим в кеш, обновляется оперативно по колбеку.

    Я у Вас спрашивал как вы обрабатываете события последовательно перебираете очередь или есть приоритеты, если есть то чем обосновываете?
     
    Цитата
    VPM написал:
    Цитата
    nikolz написал:
    Собственно задачей может быть не только функция, выполняемая в main, но и любой процесс или другой поток со своей VMLua или любом другом языке и даже в облаке или у соседа на компе.
    Вот этого точно, не обсуждаю. 1 терминал, 1 маин, множество корутин или сейчас рассматриваю как предлагал альтернативу Nikolay, . Все остальное к программистам системщикам или TGB,   ::

    Цитата
    nikolz написал:
    Свчеи хранятся в сжатом формаье (степень сжатия примерно 7 раз .  10 лет  SBER на 1 мин это 2 млн свечей. Сжатый объем 28МБайт.
    Но это тоже для Ваших каких то специфических задач.
    "Дата соурсе" в квик организовано как интерфейс получения данных о свечах, получил к примеру 100 бар в буфер, обработал расчеты  допустим индикатора и все. Обновляется буфер согласно тайм фрейма. Текущее (не завершенную свечу) держим в кеш, обновляется оперативно по колбеку.

    Я у Вас спрашивал как вы обрабатываете события последовательно перебираете очередь или есть приоритеты, если есть то чем обосновываете
    Приоритеты не имеет смысла делать, так как очередь пока короткая.
    У моего робота реакция на колбек составляет  не более 0.1 ms.
     
    Т е примерно в 10000 раз меньше, чем у Вас, если Вы поставите sleep на 1 сек
     
    Существует несколько подходов к организации данных в 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.
     
    Еще раз. Идеальный производственный паттерн работы с QUIK: В QUIK нет смысла "стримить" все свечи постоянно — нужно один раз получить исторический буфер и дальше обновлять только последнюю (текущую, незакрытую) через callback/опрос?

    Тогда, Алгоритм модуля MarketData_Pro.Poller, который:
    а) Загружает исторические свечи (100–500 штук) в UniversalBuffer при инициализации.
    б) Держит кеш последней свечи (текущий бар) отдельно.
    с) Обновляет кеш по событию или через быстрый опрос QUIK (getParamEx / getCandlesByIndex).
    д) По таймфрейму???  проверяет закрытие свечи > переносит кеш в буфер и очищает кеш?
    е) Отдает актуальные данные любому индикатору через getValue() или прямой доступ к буферу?
     
    Цитата
    VPM написал:
    Еще раз. Идеальный производственный паттерн работы с QUIK:  В QUIK нет смысла "стримить" все свечи постоянно — нужно один раз получить исторический буфер и дальше обновлять только последнюю (текущую, незакрытую) через callback/опрос?

    Тогда, Алгоритм модуля MarketData_Pro.Poller, который:
    а) Загружает исторические свечи (100–500 штук) в UniversalBuffer при инициализации.
    б) Держит кеш последней свечи (текущий бар) отдельно.
    с) Обновляет кеш по событию или через быстрый опрос QUIK (getParamEx / getCandlesByIndex).
    д) По таймфрейму???  проверяет закрытие свечи > переносит кеш в буфер и очищает кеш?
    е) Отдает актуальные данные любому индикатору через getValue() или прямой доступ к буферу?
    Вы ошибаетесь.
    История торгов нужна не для того, чтобы постоянно ее обрабатывать. На истории проверяют идеи торгов. Я на истории обучаю роботов.
     
    Цитата
    VPM написал:
    Существует несколько подходов к организации данных в 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.
    Вы это сделали или просто рассуждаете?
    Если сделали то покажите профиль задержек на тестах и оцените сколько инструментов вы сможете обрабатывать. Какие у Вас результаты на истории?
     
    VPM,
    Не в обиду, но мне Ваши опусы напоминают песню ямщика:
    -Ямщик - ты о чем поешь?
    -Так что вижу, так  о том и пою.
     
    VPM,
    Если вы останавливаете корутины, то теряете время на их остановке и запуске. Это дорогая процедура.
    Но Вам же время не важно.
     
    nikolz,  1. Вы не отвечаете на заданные Вам вопросы, ну как минимум в общении это не вежливо!  :what: , для меня  это и не важно.
    2. Ну, нужны Вам все эти гигибайты истории, да и храните, я же не против, я привёл паттерн для текущей задачи.
    3. Именно так создал, этот подход убираю ошибки для тестирования.
    4. С песней в точку что вижу, с чем разбираюсь, про то и пою, 20 раз уже на это отвечал, если есть проблемы с памятью я записывайте, нет мне несложно повторить и 100 раз одно и тоже.
    5. И уж пожалуйста, про время не нужно, оно мне интересно в рамках исполнения моих задач, описанных в скрипта.  А про  оптимизацию в песнях ни слова. Задачей оптимизации, следящий раз, сейчас найти приемлемое решение для задач описанных выше!
    6. Возможно у такого специалиста есть рекомендации по задаче? Или "Слов из песни не выбросить"?  :smile:  
     
    Цитата
    VPM написал:
    nikolz,  1. Вы не отвечаете на заданные Вам вопросы, ну как минимум в общении это не вежливо!   , для меня  это и не важно.
    2. Ну, нужны Вам все эти гигибайты истории, да и храните, я же не против, я привёл паттерн для текущей задачи.
    3. Именно так создал, этот подход убираю ошибки для тестирования.
    4. С песней в точку что вижу, с чем разбираюсь, про то и пою, 20 раз уже на это отвечал, если есть проблемы с памятью я записывайте, нет мне несложно повторить и 100 раз одно и тоже.
    5. И уж пожалуйста, про время не нужно, оно мне интересно в рамках исполнения моих задач, описанных в скрипта.  А про   оптимизацию в песнях ни слова . Задачей оптимизации, следящий раз, сейчас найти приемлемое решение для задач описанных выше!
    6. Возможно у такого специалиста есть рекомендации по задаче? Или " Слов из песни не выбросить "?  ::  
    У Вас много слов в песне, возможно пропустил Ваш вопрос.  Если не сложно, то повторите.  
     
    Попурри на тему "Три тополя на Плющихи" в исполнении ... .  :smile:

    Зацените на сколько удобен интерфейс конечного пользователя в этом подходе.

    Код
    -- Примеры использования универсальной системы:
    
    -- Глобальный экземпляр
    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!
     
    Цитата
    VPM написал:
    вы обрабатываете события последовательно перебираете очередь или есть приоритеты, если есть то чем обосновываете?
       Nikolay вам объяснил, что не надо обрабатывать события. Зачем вам изучать жизнь событий? Когда для принятия решений достаточно (наряду с определением текущего состояния вашего счета, индикаторами принятия решений): определить как и когда выполняются ваши заявки. Все это можно увидеть в таблицах состояния QUIK (orders, stop_orders и т.д.), которые вы можете опрашивать циклически. Это вы можете делать в том порядке, который вам нужен в вашей стратегии торгов. Единственный коллбек, который имеет смысл обрабатывать (с учетом того, что он может потеряться) это OnTransReply, так как в нем может быть информация о причине невыполнения вашей транзакции. Все остальные коллбеки - от "лукавого". Нужно понимать что "реактивность" (задержка выполнения команд) QLua ~1- 60 сек.  
      Все это не однократно обсуждалось на этом форуме: читайте историю (все украли до нас :smile: ).
     
    Что вышло. Это — мощный объектно-ориентированный фреймворк для рыночных данных на 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) — глобальная регистрация индикатора.

    Ну как то так! Основная цель универсальность - возможность много кратного использования блока модулей, и удобство и простота интерфейса пользователя.  
     
    TGB,  Ну вот, Можете же, нормально изъясняться в пределах общения, без излишней надменности.   :wink:  
     
    VPM,  и все таки мне интересно, вы понимаете, что, если корутина, при своем вызове выполняет, пусть 50 простых (не циклических)  операций (эквивалентных по затратам процессорного времени ~2 вызовам пустых функций), то КПД использования процессорного времени вашего ПК: 25 / 125 = 20 %.  Вы понимаете, что ресурс процессорного времени является общим? И если вы его расходуете в своем скрипте, то медленнее выполняются функции QUIK.
       Покажите, где у вас корутина в цикле выполняет > 20 простых операций. Вы же "печетесь":
    Цитата
    VPM написал:
    Вы можете показать оптимальный подход в квик, для получения и обработки оперативных данных, именно оперативных?
       Вы понимаете, термин оптимальный? По простому, лучше не бывает. В каких условиях (ограничениях)?
      Зачем вы пишите о том, чего не понимаете?
     
    Цитата
    VPM написал:
    Это — мощный объектно-ориентированный фреймворк для рыночных данных на Lua, для QUIK.
      Не буду утверждать точно (в отличие от вас я всегда сомневаюсь :smile: ), но мне кажется, что это ваши очередные иллюзии.
     
    Цитата
    VPM написал:
    TGB ,  Ну вот, Можете же, нормально изъясняться в пределах общения, без излишней надменности.  
        Вы почитали историю? Там есть ответы на все ваши (характерные для начинающих) вопросы. Похоже, нет.
    Страницы: Пред. 1 ... 7 8 9 10 11 След.
    Читают тему
    Наверх