VPM (Все сообщения пользователя)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 26 След.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Если добавить к этим модулям вспомогательную оболочку типа DataHub, которая объединит QuickDataManager и мой MarketData в одну унифицированную архитектуру (единый интерфейс “данные QUIK” и “данные с рынка”), то получим идеальную базу для торгового ядра?
Но в этом варианте в разы уваливается сложность, и требуется более профессиональный подход, в распределении ресурсов и нагрузок CPU, то о чем  нас постоянно предупреждают опытные разработчики.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Разбор полета.

Грамотная архитектура, для идеи "ленивого дата-менеджера" и улучшения её в духе реального продакшн-решения. Разберу вариант подробней, чтобы подтвердить, где попал в точку и что нужно отполировать.

1. Нормализация ключа кэша.
Сортировка ключей — идея для стабильности (иначе "a,b" и "b,a" могли бы быть разными), нужно ещё добавить firmid и client_code в начало ключа: local key_parts = {self.firmid, self.client_code, param}
Так один менеджер может обслуживать несколько клиентов без пересечений в кэше, теперь комбинация sec_code=SBER и sec_code=GAZP не будет путаться.

2. Кэш с TTL и проверкой актуальности.
self.cache_ttl = 5
self.cache_timestamps[cache_key] = os.time()

Это минимальный, но практичный шаг, QUIK не всегда требует мгновенной актуализации, но важно не держать stale-данные применим подход "time-based invalidation".
Также можно улучшить, если добавить опциональный параметр TTL при вызове?
function QuickDataManager:new(firmid, client_code, cache_ttl)
   obj.cache_ttl = cache_ttl or 5
end

3. Безопасная загрузка через pcall: local success, err = pcall(function()
QUIK-функции часто возвращают nil или бросают ошибки при нестабильных данных. Это гарантия, что менеджер не уронит основной поток.

4. Методы вместо __index. Переход от хардкода (manager.depo) к явным методам (manager:get_depo()) — это повышает читаемость и контроль над параметрами.

5. Управление кэшем.
QuickDataManager:clear_cache()
QuickDataManager:refresh()
QuickDataManager:get_cache_stats()

Просто и функционально — всё, что нужно для отладки и тонкой настройки. get_cache_stats() — инструмент для мониторинга эффективности.

Что можно слегка отшлифовать.

1. Унификация вызова QUIK-функций. сделано логично:
if param == "money" then
   data = getMoneyEx(...)

Но чтобы не плодить if-ветки, можно вынести маппинг функций в таблицу:
QuickDataManager.functions = {
   money = getMoneyEx,
   depo = getDepoEx,
   portfolio = getPortfolioInfoEx,
   buy_sell = getBuySellInfoEx,
   futures_limit = getFuturesLimit,
   futures_holding = getFuturesHolding
}

А потом универсально:
local func = self.functions[param]
if not func then error("Unknown data type: " .. param) end
data = func(table.unpack(args))

Чтобы args формировать автоматически — хранить шаблоны параметров?

2. Параметры по умолчанию.
Сейчас много or "", можно централизовать дефолты:
QuickDataManager.defaults = {
   money = { tag="", currcode="SUR", limit_kind=0 },
   depo = { sec_code="", trdaccid="", limit_kind=0 },
   portfolio = { limit_kind=0 },
   buy_sell = { class_code="", sec_code="", price=0 },
   futures_limit = { trdaccid="", limit_type=0, currcode="SUR" },
   futures_holding = { trdaccid="", sec_code="", type=0 }
}
Тогда метод _loadData может начинаться с: optional_params = table.merge(self.defaults[param] or {}, optional_params or {})

3. Асинхронность или очередь обновлений. Если  добавить корутину-обновление (например, периодическое refresh), то эта структура идеально готова — просто запускаешь фоновые обновления без блокировки QUIK.

4. Универсальный интерфейс доступа. Чтобы сохранить удобство "ленивого доступа", можно вернуть синтаксическую обёртку:

setmetatable(QuickDataManager, {
   __index = function(self, key)
       if self["get_" .. key] then
           return self["get_" .. key](self)
       end
   end
})
Тогда снова можно писать:
local depo = manager.depo  -- ленивый вызов get_depo()
но при этом параметры будут управляться методами?

 Финальный вариант (сбалансированный).

function QuickDataManager:new(firmid, client_code, cache_ttl)
   local obj = setmetatable({}, self)
   obj.firmid = firmid
   obj.client_code = client_code
   obj.cache = {}
   obj.cache_timestamps = {}
   obj.cache_ttl = cache_ttl or 5
   return obj
end

function QuickDataManager:_build_cache_key(param, optional_params)
   local key_parts = {self.firmid, self.client_code, param}
   if optional_params then
       local sorted = {}
       for k in pairs(optional_params) do table.insert(sorted, k) end
       table.sort(sorted)
       for _, k in ipairs(sorted) do
           table.insert(key_parts, k .. "=" .. tostring(optional_params[k]))
       end
   end
   return table.concat(key_parts, "|")
end
Просто добавить централизованные defaults и маппинг функций.

ИТОГ. Такая версия — уже достаточно зрелая. Она:
* Решает проблему дублирования и нагрева QUIK-API;
* Гибко масштабируется под любые источники данных;
* Предусматривает отказоустойчивость;
* Простая для использования в сценариях (ленивая инициализация).

К этому обновленному, менеджеру если добавить, автоматическое обновление данных через coroutine с учётом TTL и нагрузки (чтобы QUIK не тормозил). Это позволит, например, держать кэш свежим без прямых вызовов refresh().
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
В концептуальном примере выше, используется ленивый подход (lazy loading) для получения данных, когда они действительно необходимы, а не заранее.

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

Производительность, хотя ленивый подход помогает избежать лишних запросов, важно следить за тем, чтобы не было слишком частых запросов к серверу, если объем данных большой.
Оптимизация, кэширование данных, чтобы не запрашивать данные каждый раз при обращении к параметрам, добавить кэширование результатов запросов через self.cache для параметров, чтобы избежать лишних вызовов.

Некоторые моменты, которые нужно улучшить для большей гибкости и упрощения, и настройки стабильной работы.

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

2. Модификация функции __index. Нужно немного улучшить проверку, чтобы все параметры, можно было бы загружать лениво, а не только жестко прописанные. Например, можно динамически извлекать значения для всех типов данных через getParamEx.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Цитата
nikolz написал:
В своем скрипте все параметры типа firmid, client  получаю из QUIK. Т е их не надо вводить пользователю.
Не очень понимаю этот подход, ну если с firmid все еще понятно, зависит в чей терминал скипт загружен. То с client не все очевидно, все равно приходится в водить,  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
nikolz,  Это не инструкция, это описные одного из вариантов подхода, если хотите мое виденье, выложено на обсуждение сообществу.  

"ленивая" загрузка - описание есть выше, такую возможность предоставляет ООП, если не очень понятно можно посмотреть фреймворк на который  я ссылаюсь.

Подход уже тоже устарел так как нашлись более удобные решения, например кэширует результаты и имеет авто обновление через корутину (с ограничением нагрузки),
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Что делает:

QuickDataManager:new(firmid, client_code). Конструктор создаёт экземпляр менеджера с обязательными параметрами firmid и client_code.
Это основные параметры для работы с системой QUIK. Все остальные параметры передаются как опциональные в виде таблицы в функции.

QuickDataManager:_loadData(param, optional_params). Это основная функция для ленивой загрузки данных. В зависимости от параметра (например, "money", "depo", "portfolio", и т.д.), она делает запросы к соответствующим функциям QUIK. Функция также проверяет, есть ли уже кэшированные данные для этого параметра, и если они есть — возвращает их. Если данных нет, выполняется запрос и кэшируются результаты? Здесь основной вопрос как правильно организовать работу?

QuickDataManager:__index(key). Метатаблица __index отвечает за доступ к данным через ключи, такие как money, depo, portfolio и другие. Для каждого ключа вызывается соответствующая функция ленивой загрузки, которая получает необходимые данные и кэширует их.

Параметры (например, tag, currcode, limit_kind, sec_code и другие) передаются через опциональные параметры, что позволяет адаптировать запросы под различные нужды и сохранить гибкость подхода.

Пример использования. При первом обращении к данным (manager.money, manager.depo, manager.portfolio, и т.д.) данные будут загружены, затем они будут кэшироваться для последующего использования без лишних запросов к системе. Что позволяет уменьшить нагрузку на систему и ускорить последующие операции. Как альтернатива. Если нужно избежать повторного получения одинаковых данных, можно добавить механизм для "очистки" кэша по истечении времени или по запросу.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Вариант реализации подхода, что скажите?
Код
QuickDataManager = {}
QuickDataManager.__index = QuickDataManager

-- Конструктор класса
function QuickDataManager:new(firmid, client_code)
    local obj = setmetatable({}, self)
    obj.firmid = firmid
    obj.client_code = client_code
    obj.data = {}  -- Для хранения кэшированных данных
    obj.loaded = {}  -- Для отслеживания загруженных параметров
    return obj
end

-- Функция для ленивой загрузки данных с учетом firmid и client_code
function QuickDataManager:_loadData(param, optional_params)
    -- Формируем уникальный ключ для кэширования (с учетом параметров)
    local cache_key = param .. "_" .. (optional_params or "")
    
    if self.loaded[cache_key] then
        return self.data[cache_key]  -- Возвращаем из кэша
    end

    -- Если данных нет в кэше, загружаем их
    local data
    if param == "money" then
        -- Вызов getMoneyEx для получения информации по деньгам
        data = getMoneyEx(self.firmid, self.client_code, optional_params.tag or "", optional_params.currcode or "", optional_params.limit_kind or 0)
    elseif param == "depo" then
        -- Вызов getDepoEx для получения позиций по инструментам
        data = getDepoEx(self.firmid, self.client_code, optional_params.sec_code or "", optional_params.trdaccid or "", optional_params.limit_kind or 0)
    elseif param == "portfolio" then
        -- Вызов getPortfolioInfoEx для получения информации по клиентскому портфелю
        data = getPortfolioInfoEx(self.firmid, self.client_code, optional_params.limit_kind or 0, optional_params.board_tag or "", optional_params.currency or "")
    elseif param == "buy_sell" then
        -- Вызов getBuySellInfoEx для получения параметров по заявкам
        data = getBuySellInfoEx(self.firmid, self.client_code, optional_params.class_code or "", optional_params.sec_code or "", optional_params.price or 0)
    elseif param == "futures_limit" then
        -- Вызов getFuturesLimit для получения фьючерсных лимитов
        data = getFuturesLimit(self.firmid, optional_params.trdaccid or "", optional_params.limit_type or 0, optional_params.currcode or "")
    elseif param == "futures_holding" then
        -- Вызов getFuturesHolding для получения позиций по фьючерсным счетам
        data = getFuturesHolding(self.firmid, optional_params.trdaccid or "", optional_params.sec_code or "", optional_params.type or 0)
    end
    
    -- Кэшируем загруженные данные
    self.data[cache_key] = data
    self.loaded[cache_key] = true

    return data or {}
end

-- Доступ к данным с ленивой загрузкой
function QuickDataManager:__index(key)
    if key == "money" then
        return self:_loadData("money", {tag = "default", currcode = "USD", limit_kind = 0})
    elseif key == "depo" then
        return self:_loadData("depo", {sec_code = "SBER", trdaccid = "1234", limit_kind = 0})
    elseif key == "portfolio" then
        return self:_loadData("portfolio", {limit_kind = 0, board_tag = "TQBR", currency = "RUB"})
    elseif key == "buy_sell" then
        return self:_loadData("buy_sell", {class_code = "TQBR", sec_code = "SBER", price = 1000})
    elseif key == "futures_limit" then
        return self:_loadData("futures_limit", {trdaccid = "TQBR", limit_type = 0, currcode = "USD"})
    elseif key == "futures_holding" then
        return self:_loadData("futures_holding", {trdaccid = "1234", sec_code = "SBER", type = 0})
    else
        -- Загружать другие параметры по необходимости
        return self:_loadData(key)
    end
end

-- Пример использования
local manager = QuickDataManager:new("Firm1", "Client1")

-- Ленивое обращение к данным
local money = manager.money  -- Получение информации по деньгам
local depo = manager.depo    -- Получение позиций по инструментам
local portfolio = manager.portfolio  -- Получение информации по портфелю
local buy_sell = manager.buy_sell  -- Получение информации по заявкам на покупку/продажу
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
"Едем дальше, видим больше"! На мой взгляд данный подход, нужно распространить на получение "Серверных данных". Для понимания проблематики, архитектуру предлагается использовать общею для фондового и сросного рынков?  Задача все та же.

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

Обобщенно свести квиковские в функции в удобную оболочку:

Функции взаимодействия скрипта Lua и Рабочего места QUIK

  • getDepoEx - функция для получения позиций по инструментам указанного типа
  • getMoneyEx - функция для получения информации по денежным позициям указанного типа
  • getFuturesLimit - функция для получения информации по фьючерсным лимитам
  • getFuturesHolding - функция для получения информации по фьючерсным позициям
  • getSecurityInfo - функция для получения информации по инструменту?
  • getTradeDate - функция для получения даты торговой сессии
  • CalcBuySell - функция для расчета максимально возможного количества лотов в заявке? (скорее для контроля, уж больно тяжелая?)
  • getPortfolioInfoEx - функция для получения значений параметров таблицы «Клиентский портфель» с учетом срока расчётов
  • getBuySellInfoEx - функция для получения параметров (включая срок расчётов) таблицы «Купить/Продать» (Важная для маржинальной торговли!)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
nikolz,  На счет сложности, для меня очень сложно, здесь с Вами не поспоришь. Отсюда бывает и путаница.

Не могу согласиться: "Универсальная система - это такая система, разработчик которой не имеет представления где и как ее будут применять.".  На  все известно и источники и методы, а использование их на прямую зависит от сложности самой торговой системы. Изначально думал для удобства сделать единый интерфейс рыночных данных, как то само собой добавились индикаторы и вся остальная инфраструктура и все вылилось в целый фреймворк.   Конечно нужно тестирование и оптимизация.

"Пользователь такой системы не в состоянии понять все, что включил в нее разработчик." Так ведь и задача стоит, не нужно пользователю начинка, подключил блок и пользуйся понятным простым интерфейсом. Меня "ушатала" постоянная переделка. Задача все таки, удобство получать в торговых подходах, а не упражнения в программировании.  Удобно и то что есть алгоритмы которые использует большинство, ATR, StDev, средниеи.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
TGB,  Обо всем и по порядку.

1000 раз уже на форуме говорил "Не программист, и знания мои так себе". Это раз!
Форум - это площадка для обсуждений, а не выставления амбиций. Это два!

Теперь что касается последней темы:

 1. Не надо "Кусочничить".  Я тему веду последовательно, и рассуждения читать нужно также.
 2. А Вы то понимаете сами?  Пока не создан подход, то и оптимизировать НЕ ЧЕГО, от слова совсем?
 3. Ответ на Ваш вопрос. Оптимизация - это КОМПРОМИС. Поменяйте понимание и все встанет по местам.
 4. Повторюсь мне  не сложно:
Подход - Инвестиционный (означает тф. месячный и больше, в квик их нет).
Задача - возможность торговать и управлять 1 инструментом так и портфелем (универсальность).
Структура - модульная, много разового использования.
Интерфейс - наипростейший, понятный бабушке!

Про КПД, чего Вы рассуждаете? Все КПД моего старенького направленно на эффективность торговли = увеличению баланса счета. Тем более что подход описан, и можно воспользоваться функциями без корутин.

И последнее, Вы не сомневайтесь, сомнения нужны на стадии анализа, а когда решение принято, нужно действовать. Попробуйте. Ну или обосновано возражайте.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
TGB,  Ну вот, Можете же, нормально изъясняться в пределах общения, без излишней надменности.   :wink:  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Что вышло. Это — мощный объектно-ориентированный фреймворк для рыночных данных на Lua, для QUIK. Реализует целую универсальную систему источников рыночных данных. Она объединяет котировки, свечи и индикаторы в едином интерфейсе. Система построена на метатаблицах (классическом OOP для Lua), в основу положен подход представленный в фреймворке HH.

Какие задачи решает. Код реализует полный универсальный слой доступа к рыночным данным:
------------------------------
* единый API для котировок, свечей и индикаторов;
* кэширование, буферизация и автообновление;
* поддержка любых индикаторов;
возможность расширять систему.

Чуть подробней.
-----------------------
MarketData. Работает с текущими рыночными данными (котировки Level 2, параметры инструмента).
Поддерживает:
* bids / offers (через getQuoteLevel2())
* другие параметры через getParamEx()
Умеет “подгонять” цену под шаг (fit() / move()).

Основной класс — MarketData_Pro. Это универсальный интерфейс ко всем типам данных.
Автоматически определяет источник:
* есть tag > индикатор с графика + свечи;
* есть interval > свечи или любой другой параметр таблицы текущих торгов;
* иначе > поток котировок таблица Текущих торгов или таблица Левел2.
Автоматически создаёт соответствующий объект-источник.

Методы доступа:
-----------------------
UniversalIndicatorSystem - Это глобальный реестр индикаторов. Поддерживает регистрацию, кеширование и вычисление индикаторов.

Есть встроенные индикаторы:
Название            Назначение              Тип
SMA     Простое скользящее среднее        numeric/price
EMA        Экспоненциальное скользящее среднее numeric/price
RSI       Индекс относительной силы        price
ATR        Средний истинный диапазон        price
STDDEV    Стандартное отклонение            numeric
BOLLINGER Полосы Боллинджера                price

Можно добавлять свои: GlobalIndicatorSystem:registerIndicator("MY_IND", function(buffer)
   -- код вычисления
end, "My Indicator", {"numeric"})

UniversalDataSource. Базовый класс для любых источников данных.
Позволяет:
* Получать буфер по типу (getBuffer("close"))
* Обновлять данные (updateBuffer)
* Вызывать индикаторы (getIndicator("SMA", 14))
Именно от него наследуются конкретные реализации ниже!!!

Реализации источников.
------------------------
1) CandleDataSource. Создаётся через CreateDataSource(). Загружает OHLCVТ-данные.
Обновляет буферы (close, high, low, open, volume).
Позволяет вызывать индикаторы на свечных данных.

2) QuoteDataSource. Источник потоковых котировок (через getParamEx, getQuoteLevel2). Буферы (last, bid, offer, volume).
Поддерживает вычисление индикаторов по последним значениям

3) getCandlesByIndex()? Удобен для визуализации, но не очень при обработке множества тикеров и таймфреймов, особенно когда есть небходимость их постоянно изменять, в под?

Менеджер источников - MarketData_Pro.Manager.
-----------------------------
Создаёт и кеширует все экземпляры MarketData_Pro.
а) Глобальный объект: MDP;
б) Методы:
* getOrCreate(params) — получить источник, если уже есть, иначе создать;
* registerIndicator(name, func, desc, types) — глобальная регистрация индикатора.

Ну как то так! Основная цель универсальность - возможность много кратного использования блока модулей, и удобство и простота интерфейса пользователя.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Попурри на тему "Три тополя на Плющихи" в исполнении ... .  :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!
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
nikolz,  1. Вы не отвечаете на заданные Вам вопросы, ну как минимум в общении это не вежливо!  :what: , для меня  это и не важно.
2. Ну, нужны Вам все эти гигибайты истории, да и храните, я же не против, я привёл паттерн для текущей задачи.
3. Именно так создал, этот подход убираю ошибки для тестирования.
4. С песней в точку что вижу, с чем разбираюсь, про то и пою, 20 раз уже на это отвечал, если есть проблемы с памятью я записывайте, нет мне несложно повторить и 100 раз одно и тоже.
5. И уж пожалуйста, про время не нужно, оно мне интересно в рамках исполнения моих задач, описанных в скрипта.  А про  оптимизацию в песнях ни слова. Задачей оптимизации, следящий раз, сейчас найти приемлемое решение для задач описанных выше!
6. Возможно у такого специалиста есть рекомендации по задаче? Или "Слов из песни не выбросить"?  :smile:  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Еще раз. Идеальный производственный паттерн работы с QUIK: В QUIK нет смысла "стримить" все свечи постоянно — нужно один раз получить исторический буфер и дальше обновлять только последнюю (текущую, незакрытую) через callback/опрос?

Тогда, Алгоритм модуля MarketData_Pro.Poller, который:
а) Загружает исторические свечи (100–500 штук) в UniversalBuffer при инициализации.
б) Держит кеш последней свечи (текущий бар) отдельно.
с) Обновляет кеш по событию или через быстрый опрос QUIK (getParamEx / getCandlesByIndex).
д) По таймфрейму???  проверяет закрытие свечи > переносит кеш в буфер и очищает кеш?
е) Отдает актуальные данные любому индикатору через getValue() или прямой доступ к буферу?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Существует несколько подходов к организации данных в QUIK. Нужно выбрать структуру для проекта, который будет включать в себя:
а) DataPoller.lua (планировщик опросов в корутинах);
б) MarketData (модуль для работы с рыночными данными);
с) DataManager (менеджер данных, который объединяет все вместе).

Учитывая, что задача стоит избежать фризов и минимизировать задержки, а также обеспечить актуальность данных, предлагается следующий подход:

DataPoller будет заниматься асинхронным опросом данных (через корутины) и обновлением кэша.
MarketData будет предоставлять интерфейс для доступа к данным (через метатаблицы с ленивой загрузкой и кэшированием).
DataManager будет управлять созданием и жизненным циклом источников данных, а также взаимодействием между Poller и MarketData.

При этом мы можем использовать комбинацию подхода 3 (ООП-ленивый доступ) и 4 (кэш + корутина). Тогда концепция выглядит следующим образом:

1. DataPoller. Создает и управляет корутинами для периодического обновления данных.
Каждый источник данных (например, тикер) регистрируется в планировщике.
Планировщик обновляет кэш данных в фоновом режиме.

2. MarketData. Представляет объект-источник данных (например, свечи, стакан, параметры инструмента).
При первом обращении к полю, если данных нет в кэше, они запрашиваются синхронно (редкий случай, но как fallback (запасной план) ).
Основной доступ к данным идет из кэша, который асинхронно обновляется планировщиком.

3. DataManager. Инициализирует планировщик и создает источники данных.
Предоставляет интерфейс для получения источника данных (например, по тикеру и интервалу для свечей).
Управляет жизненным циклом данных (создание, удаление, обновление).

Пример последовательности:
Пользователь запрашивает у DataManager данные по SBER (например, свечи M1).
DataManager создает объект MarketData для SBER M1, если он еще не создан, и регистрирует его в DataPoller.
DataPoller начинает периодически (каждые N ms) обновлять данные для SBER M1 (например, запрашивать последние свечи и класть в кэш).
Пользователь обращается к объекту MarketData (например, candles:getValue("close", -1)), и получает данные из кэша.
Таким образом, мы имеем асинхронное обновление данных и синхронный доступ к ним без блокировок?

Теперь код для каждого модуля. Начнем с DataPoller (адаптируем тот, что уже есть, но упростим и настроим под эту задачу).

DataPoller будет: Принимать задачи (источники данных) с callback для обновления. Запускать корутины, которые периодически вызывают callback и обновляют кэш.
MarketData (источник данных) будет: Иметь метод update() (который будет вызываться планировщиком) для обновления своих данных. Иметь кэш для хранения последних данных. Предоставлять методы для доступа к данным (например, getValue).
DataManager будет: Хранить все созданные источники данных (например, по ключу market_ticker_interval). Создавать новые источники, если их нет, и регистрировать их в DataPoller.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Цитата
nikolz написал:
Собственно задачей может быть не только функция, выполняемая в main, но и любой процесс или другой поток со своей VMLua или любом другом языке и даже в облаке или у соседа на компе.
Вот этого точно, не обсуждаю. 1 терминал, 1 маин, множество корутин или сейчас рассматриваю как предлагал альтернативу Nikolay, . Все остальное к программистам системщикам или TGB,   :smile:

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

Я у Вас спрашивал как вы обрабатываете события последовательно перебираете очередь или есть приоритеты, если есть то чем обосновываете?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
nikolz,  А можете описать полный алгоритм, и если приоритеты, если есть на чем основываете? Будет интересно, думаю не только мне.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Асинхронность понятно что в условиях маин  можно говорить про условную "асинхронность", не я придумал, ни мне отменять, а употребляется для понимания вопроса.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Хорошо, Вы можете показать оптимальный подход в квик, для получения и обработки оперативных данных, именно оперативных?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
TGB,  Мне точно Вас не хочется комментировать, и ребенок здесь похоже один, хотя и образованный. Ставлю даже 1 минуту, сказать для каких задач, или уже догадаешься?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Имелось в виду "таблиц всех сделок", ну конечно необходимы и другие для полного функционала.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Nikolay,  Ну а сколько можно обработать таблиц высоко ликвидных инструментов? Мой скрипт, допустим отстает в стаканах, даже по лимитным заявкам, на высоко ликвидных в часы пик.  Возможно подход не очень?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Альтернативный способ, так называемый "Реактивный ленивый доступ", мета табличный доступ через "__index", где при чтении - получении, допусти "marketdata.LAST" автоматически вызывается getParamEx.
Что хорошо для "on-demand" доступа, предоставление ресурсов или функциональности по требованию, а не постоянно, но плохо для высоко частотных опросов, каждый доступ = новый API вызов.

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

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

И следовательно, предварительная структура блока, состоит из модулей:
* DataPoller.lua - модуль-планировщик опросов QUIK-данных в корутинах.
* MarketData.
* DataManager.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
1. Стакан все таки не очень показательно, речь идет об обработке большого количества бумаг портфеля, а информация чисто логически из выше сказанного.
2. Здесь речь про блокировку терминала, особенно в в часы пик.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Пожалуй основной вопрос в этой задаче  (ключевой вызов в QUIK Lua-интеграции) — это организация опроса данных (polling) без блокировок и с минимальной нагрузкой на терминал. Проблема опроса данных в QUIK
  1. Все функции QUIK API синхронные. Вызовы getParamEx, getItem, getQuoteLevel2, getCandles и т.п. — блокирующие.
    Если их дергать часто, они начинают “затыкать” поток исполнения и могут даже вызывать таймауты при большом количестве бумаг?

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

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

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

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

Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
"Ни когда не было и вот опять". Прежде чем разбираться с подходами Р. Винса, они направлены на управление портфелями, а задача ставилась изначально возможность работы с одним инструментом и простейшими торговыми стратегиями. Хотя и пересобрал блок "капитал менеджер", текущая задача все таки  несколько другая, не меняя важная, скорее даже основополагающая, ведь от качества полученных данных зависят все остальные расчеты.

Организация получения данных удобным способом, есть одна из главных задач, собственно с нее то и нужно было начинать, но как понять что необходимо под конкретную задачу, мой подход "ввязаться в бой". Думаю нужен универсальный подключаемый модуль, чтоб не заниматься переделками каждый раз. Тогда задачу условно можно разделить на 2 этапа: получение данных и их управление. Нужно собрать дата менеджер.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Важное замечание!
В рамках системы Винса, когда мы говорим о управлении капиталом, важно учитывать не только отдельные тикеры или активы, но и влияние каждого из них на общий капитал.

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

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 жизненных цикла, простая торговая стратегия все та же, выдает приказы (Что сделаешь Важная командует)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
 Возможные подходы к организации жизненного цикла "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:  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 

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

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

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

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

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

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

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

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

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

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

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

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

  • Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    И так обсудили разные подходы по организации полного жизненного цикла заявки. Каким подходом пользоваться, каждый определяет для себя сам. Это архитектурная дилемма. Так как окончательного мнения у меня не сложилось, буду пользоваться наиболее понятными для меня подходами. Задача все еще прежняя, собрать модульную структуру в которой торговые стратегии работают независимо отдавая приказы на исполнение. И технологическая, все это дело обслуживает.

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

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

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

    Если я Вас правильно понимаю, фоновые решения предлагаете решать через "замыкания"? И решения поиска ордеров и сделок в таблицах квик?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Ну и как Вам задачка для обычного пользователя QUIK!  :unamused:  
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Нет все таки упустил.

    Нужна машина состояний - FSM (finite state machine) — для описания переходов состояний ордера.
    Очередь событий или coroutine - менеджер обработки событий, следовательно  Асинхронную модель.
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Lua-модуль,  реализующий атомарный жизненный цикл заявок (Atomic Order Lifecycle) в QUIK.

    Должен быть построен по принципу:

    * независим от стратегии,
    * обрабатывает все три потока событий (OnTransReply, OnOrder, OnStopOrder),
    * поддерживает атомарность и согласованность данных,
    * частичное исполнение,
    * восстановления текущих ордеров и стоп-заявок при запуске  или сбоях из данных таблиц QUIK,
    * проводить периодическую сверку с данными таблиц  QUIK,
    * логирование,
    * таймауты.

    Для реализации стабильной работы AOL-контроллера необходимо чтоб его архитектура соответствовала асинхронной модели? Я ни чего не упустил?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Вот и пришли с чего начали. Для создания стабильно работающего AOL-контроллера необходимо переработать его архитектуру в соответствии с асинхронной моделью?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Обработка OnTransReply.  Ожидание ответа в цикле main приводит к проблеме - зависанию. Асинхронная модель: реагирует на события в колбэках, не ожидая их в основном потоке не блокирует его?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    nikolz,  Хотя читать тяжеловато логика понятна, решение "класс". Не понял только как в Вашем варианте поступать с "частичное исполнение" и восстановления текущих ордеров и стоп-заявок при запуске  или сбоях из данных QUIK?

    Да вон еще Nikolay, страстей написал? Получается и периодическую сверку запускать нужно? Ну либо вообще от подхода отказаться?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Тогда Архитектура:
    1.  Trading Strategy.
        (логика входа/выхода, анализ данных, решения)
    +-------------------------------------------------------------+

    2.  OrderManager (AOL).
       (отправка, принятие, исполнение, таймаут, отмена)
    +-------------------------------------------------------------+
    3.  RiskManager:
        (контроль капитала, просадки, стопы)
    +-------------------------------------------------------------+
    4.  QUIK API Layer:
       ( DataManager:  getParamEx, ...
       sendTransaction,
       OnTransReply, OnOrder, OnTrade)  
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    6. Таймаут и отмена ордера.
    Код
    function OrderManager:check_timeouts()
        local now = os.time()
        for trans_id, ctx in pairs(self.pool) do
            if ctx.status == "SENT" and now - ctx.timestamp > self.timeout_sec then
                ctx.status = "TIMEOUT"
                log(string.format("[%s] x Таймаут ордера, отправляем отмену", ctx.sec))
                self:cancel(ctx)
            end
        end
    end
    
    function OrderManager:cancel(ctx)
        if not ctx.order_num then return end
        local txn = {
            ACCOUNT     = ACCOUNT,
            CLIENT_CODE = CLIENT_CODE,
            CLASSCODE   = ctx.class,
            SECCODE     = ctx.sec,
            ACTION      = "KILL_ORDER",
            ORDER_KEY   = ctx.order_num,
            TRANS_ID    = tostring(math.random(1000000,9999999))
        }
        sendTransaction(txn)
        ctx.status = "CANCELLED"
    end
    
    7. Использование стратегии.   Теперь стратегия не работает напрямую с sendTransaction, она обращается к менеджеру:
    Код
    local ctx = {
        sec = "SBER",
        class = "TQBR",
        base_price = nil,
        drop_trigger = 0.002,
        qty = 1
    }
    
    local function strategy_tick()
        local price = tonumber(getParamEx(ctx.class, ctx.sec, "LAST").param_value)
        if not price or price <= 0 then return end
    
        if not ctx.base_price then
            ctx.base_price = price
            return
        end
    
        local change = (price - ctx.base_price)/ctx.base_price
        if change <= -ctx.drop_trigger then
            OrderManager:send({
                class = ctx.class,
                sec = ctx.sec,
                operation = "B",
                price = price,
                qty = ctx.qty
            })
        elseif change >= ctx.drop_trigger then
            OrderManager:send({
                class = ctx.class,
                sec = ctx.sec,
                operation = "S",
                price = price,
                qty = ctx.qty
            })
        end
    end
    
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    1. Структура данных ордера.
    Код
    OrderManager = {
        pool = {},       -- все активные ордера по TRANS_ID
        timeout_sec = 10 -- время ожидания исполнения
    }
    
    Каждый ордер хранит:
    Код
    -- контекст ордера
    local order_ctx = {
        trans_id   = "12345", -- уникальный локальный ID
        class      = "TQBR",
        sec        = "SBER",
        operation  = "B",     -- B / S
        price      = 123.45,
        qty        = 1,
        status     = "NEW",   -- NEW / SENT / PARTIALLY_FILLED / FILLED / CANCELLED / REJECTED / TIMEOUT
        order_num  = nil,     -- номер заявки на сервере QUIK
        trades     = {},      -- массив исполненных частей
        timestamp  = os.time()
    }
    
    2. Отправка ордера (атомарный цикл).
    Код
    function OrderManager:send(order)
        local trans_id = tostring(math.random(1000000,9999999))
        order.trans_id = trans_id
        order.status = "NEW"
        order.timestamp = os.time()
        self.pool[trans_id] = order
    
        local txn = {
            ACCOUNT     = ACCOUNT,
            CLIENT_CODE = CLIENT_CODE,
            CLASSCODE   = order.class,
            SECCODE     = order.sec,
            ACTION      = "NEW_ORDER",
            OPERATION   = order.operation,
            PRICE       = tostring(order.price),
            QUANTITY    = tostring(order.qty),
            TYPE        = "L",
            TRANS_ID    = trans_id
        }
    
        local result = sendTransaction(txn)
        if result ~= "" then
            log(string.format("[%s] x Ошибка отправки: %s", order.sec, result))
            order.status = "REJECTED"
            return false
        else
            order.status = "SENT"
            log(string.format("[%s] v Ордер отправлен (TRANS_ID=%s)", order.sec, trans_id))
            return true
        end
    end
    
    3. Колбэк OnTransReply.
    Код
    function OnTransReply(tr)
        local ctx = OrderManager.pool[tr.trans_id]
        if not ctx then return end
    
        if tr.status == 3 then
            ctx.order_num = tr.order_num
            log(string.format("[%s] v Ордер принят биржей (order_num=%s)", ctx.sec, ctx.order_num))
        elseif tr.status >= 4 then
            ctx.status = "REJECTED"
            log(string.format("[%s] x Ордер отклонен: %s", ctx.sec, tr.result_msg))
            OrderManager.pool[tr.trans_id] = nil
        end
    end
    
    4. Колбэк OnOrder (обновление состояния).
    Код
    function OnOrder(ord)
        for _, ctx in pairs(OrderManager.pool) do
            if ctx.order_num and ctx.order_num == ord.order_num then
                ctx.balance = ord.balance
                if ctx.balance == 0 then
                    ctx.status = "FILLED"
                    log(string.format("[%s] v Ордер полностью исполнен", ctx.sec))
                elseif ord.balance < ctx.qty then
                    ctx.status = "PARTIALLY_FILLED"
                    log(string.format("[%s] v Частичное исполнение: %d/%d", ctx.sec, ctx.qty-ord.balance, ctx.qty))
                end
            end
        end
    end
    
    5. Колбэк OnTrade (фиксируем сделки).
    Код
    function OnTrade(trade)
        for _, ctx in pairs(OrderManager.pool) do
            if ctx.order_num and ctx.order_num == trade.order_num then
                table.insert(ctx.trades, {
                    trade_num = trade.trade_num,
                    qty       = trade.qty,
                    price     = trade.price,
                    dir       = trade.flags % 2 == 0 and "B" or "S"
                })
            end
        end
    end
    
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Тогда, Atomic Order Lifecycle (AOL) контроллер для QUIK на Lua.

    Идея: мы создаём отдельный модуль OrderManager, который обеспечивает атомарный жизненный цикл ордера независимо от стратегии.
    Стратегия просто говорит: «открыть лонг / шорт», а менеджер следит за статусом, частичным исполнением, таймаутами и отменами. Следовательно:
    [*]

    Вся логика отправки, ожидания, исполнения, таймаута и отмены — централизована в OrderManager.

    [*]

    Стратегия просто делает запрос на ордер и получает атомарное событие исполнения.

    [*]

    Поддерживается частичное исполнение, таймаут, отмена.

    [*]

    Состояние ордера можно сохранить на диск и восстановить при перезапуске.

    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Как адаптировать AOL к реальности?

    ПроблемаТеория AOLРеальный подход
    Частичное исполнениеНарушает атомарностьСчитать атомарным весь ордерный контекст, а не сделку
    Разные IDОдин идентификаторВвести сопоставление ID между уровнями
    Перезапуск / сбойНе допускаетсяВосстанавливать состояние из текущих таблиц QUIK
    Ошибки транзакцийОткат всей операцииРеагировать по статусам OnTransReply и отменять при status > 3
    ТаймаутНет отдельного понятияРеализовать вручную (watchdog coroutine)
    ┌──────────────┐
    │ sendTransaction()
    └──────┬───────┘
                     │ TRANS_ID
                    ▼
    ┌──────────────┐
    │ OnTransReply(status=0..1)
    └──────┬───────┘
                     │ order_num
                    ▼
    ┌──────────────┐
    │ OnOrder(update)
    └──────┬───────┘
                     │ trade_num
                    ▼
    ┌──────────────┐
    │ OnTrade() — исполнение
    └──────┬───────┘
                     │
                    ▼
    ┌──────────────┐
    │ FILLED / CANCELLED
    └──────────────┘
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    А если жизненный цикл (путь), расписать по шагам в конкретные процедуры (как Nikolay, ) подход сам напрашивается. И что делать с ожиданиями? Нужен фоновый подход?
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Разбираюсь с жизненным циклом заявки, наткнулся на подход Atomic Order Lifecycle (AOL) представляет собой последовательность этапов, через которые проходит ордер в торговой системе. Все этапы жизненного цикла ордера — от его создания и отправки до исполнения, таймаута или отмены — должны быть атомарными, т.е. все операции должны завершаться

    * либо успехом (ордер выполнен),
    * либо ошибкой (ордер отменён или отказан).

    Это гарантирует, что трейдер или торговая система всегда знает, в каком состоянии находится ордер и что с ним происходит.

    Процесс жизненного цикла ордера в торговой системе можно разбить на следующие этапы:

    1. Создание ордера

    2. Отправка ордера

    3. Ожидание принятия

    4. Ожидание исполнения

    5. Исполнение

    6. Таймаут или отказ

    7. Отмена ордера

    Правильная обработка каждого из этих этапов и корректная реакция на возможные ошибки позволяют эффективно управлять ордерами и минимизировать риски на финансовых рынках. Но что делать в ситуации когда нет атомарной гарантии "all-or-nothing":   ПРОБЛЕМА: Частичное исполнение нарушает атомарность? Или другая,  ПРОБЛЕМА: Разные идентификаторы на разных этапах? Непонятно?

    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Nikolay,  Супер подход, на каждом шаге процедура, так? Я даже не задумывался о такой возможности.
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     

    Как поступлю. Адаптируем “умный” блок (SmartOrder, reply, sdelka, обработчики событий QUIK) в уже готовый скрипт, чтобы он:

    • поддерживал открытие / закрытие позиций (лонг и шорт),

    • корректно работал через callbacks,

    • не зависел от ожиданий (основной поток не блокируется),

    • сохранял информацию о транзакциях и сделках в reply / sdelka,

    • и синхронизировался с реальными ордерами QUIK.

    Что изменилось и почему это круто, судите сами;
    БылоСтало
    send_and_wait с циклом ожиданияsend_order_async — не блокирует поток, обрабатывает ответ асинхронно
    Прямые проверки result_msgПереход на централизованное хранилище SmartOrder.pool
    Потеря информации о транзакцииВся история сохраняется в reply и sdelka
    Не обновлялась позицияПозиции обновляются автоматически при OnTrade
    Возможна гонка данныхКаждая транзакция отслеживается независимо через свой trans_id
    Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
     
    Теперь относительно самого кода: Что можно сделать и что важно знать?
    1. Отрицательные / нулевые цены — проверяем и игнорируем, пока не придёт реальная сделка (OnTrade).

    2. Пакеты приходят неупорядоченно — полагаемся на локальную метку - os.time(), при несоответствии времени пакета можно игнорировать «старые» пачки.

    3. sendTransaction ≠ сделка — сделать транзакционный цикл: (отправка → ожидание принятия → ожидание исполнения → таймаут → отмена).

    4. OnOrder / OnTrade — обязательные точки контроля. Без них нельзя корректно знать цену исполнения и состояние позиции?

    5. Закрытие позиций на стоп — реализовать опционально флаг CLOSE_POS_STOP.

    6. Адаптация к брокеру / версии QUIK — нужно проверить реальные поля, которые приходят в OnOrder / OnTrade от брокера, и использовать парсер.

    7. Обратите внимание что в этом подходе есть скрытые зависимости и они могут вносить свою лепту.

    Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 26 След.
    Наверх