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

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

Страницы: Пред. 1 2 3 4 5 6 7 8 9 10 11 ... 21 След.
ищу программиста создать программу на платной основе, выгружать данные OHLC и индикаторы в файлик
 
Добрый день, Дмитрий, тема озвученная Вами далеко не тривиальна и дело здесь не в жлобстве. Пробежался по постам, тему обсуждали опытные пользователи, но мне показалось не до конца вникая в проблематику. В своих стратегиях я также получаю и анализирую данные с разных тайм фреймов. Под натерпелся. Каждый раз собирая новую торговую стратегию, говорю себе что последний раз переделываю структуру данных торговой системы, и эта  структура будет универсальной и использоваться во всех стратегиях. Именно задача организации структуры данных для простого, универсального, удобного использования является фундаментальной, и будет всегда актуальна. Касаемо озвученной задачи:
Цитата
Дмитрий написал:
надо выгружать в файл данные OHLC и некоторых индикаторов по всем доступным инструментам QUIK по всем доступным ТФ, для каждого ТФ свой файлт.е. ТФ 15м,30м,1час = 3 файлика в формате O,H,L,C,индикатор1,индикатор2,индикатор31 бар = 1 строчка файлика
Могу сказать как я ее решаю, правда я отказался писать в файл и очень давно.
И снова CreateDataSource
 
Вы просто выведите таблицу ds2  и посмотрите что получите. А там будут методы и служебная информация.   Функции для получения значений по индексу и дополнительному параметру. Так что не хранит ничего кроме этих методов. Если Ваш код подписку не закрывает, то и пере подписываться не нужно.
И снова CreateDataSource
 
Acaw,  Вы поймите, ds2 это  не место хранения данных, это таблица методов получения этих данных. ds2 = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1) это подписка на получение данных по коду класса по коду тикера и определённому тайм фрейму. Сами данные на сервере и обновляются не зависимо от Вашего подключения.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
О чудеса чудесные или Создание и Использование хук-функции.
Что такое хуки простыми словами? Хуки — это технология перехвата вызовов функций в чужих процессах, в моем случае механизм, позволяющий зарегистрировать действия, которые должны быть выполнены при завершении программы. Идея состоит в том, чтобы установить определенный код, который выполнится автоматически перед завершением работы робота или программы, независимо от того, завершилась ли программа корректно или аварийно. Это механизм позволяет регистрировать действия, которые будут выполнены в конце работы программы, когда все процессы будут завершены. Это полезно для "корректного завершения" программы — закрытия всех активных ордеров или выполнения другой важной логики. Вынос в отдельную функцию позволяет аккуратно и централизованно завершать работу с ордерами, упрощая управление состояниями. В моем случае это просто анонимная функция.
Вылетает квик 50 раз за сессию!, вылетает квик при работе в период торговой сессии
 
Скальперские стратегии точно не для квик, таблица текущих торгов обновляется 1раз в секунду. Допустим для сетки получаю значения из стакана и ТТТоргов и они отличаются. Но Вы не расстраивайтесь возможен же компромисс,  в место 35 оставьте 5 - 7 графиков для детализации, остальные через канал или еще варианты попробуйте. Так же если подключите на кабеле, то тянуть будет лучше, так как скорость и пропускная способность почти одно и тоже.
Вылетает квик 50 раз за сессию!, вылетает квик при работе в период торговой сессии
 
Свойства графика / диаграмма / ставим метку Оставлять трендовые линии .... Здесь нужно сказать что линии будет оставлять по все тикерам, по этому я пользуюсь в основном индикаторами они адаптируются.  
Вылетает квик 50 раз за сессию!, вылетает квик при работе в период торговой сессии
 
Лена,  Дело тут не только в памяти компьютера, дело еще в пропускной способности Вашего канала связи, система работает как сервер / клиент, а у Вас стаканы информация в которых обновляется не пойми как, да и графики тяжело отрисовываются. Свою подобную ситуацию решил, следующим образом настроил одну вкладку с таблицей текущих торгов практически с со всеми тикерами и 4 графика разных тайм фреймах, на один даже тиковая информация выводится + стакан + таблица обезличенных сделок, и так по каждому рынку. переключение идет через создание внутреннего канала (якоря на графиках и таблицах). Так все работает. Вы еще можете проверить скорость связавшись с провайдером. Удачи.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Рычажные весы как символ баланса   (смысл который автор закладывает)

Рычажные весы смысла и бессмыслицы отображают баланс между этими двумя крайностями. Статическая уравновешенность этих весов отражает статический баланс между порядком и хаосом. В рамках этого баланса действует закон сохранения, который гласит, что изменение одного элемента компенсируется изменением другого: "Что от одного тела убудет, то присовокупится к другому".

  1. Баланс (S1 / S2 = 1): Смысл и бессмыслица уравновешены, что отражает статическую гармонию системы.
  2. Дисбаланс (S1 / S2 > 1): Преобладание смысла над бессмыслицей, что символизирует порядок и структурированность.
  3. Дисбаланс (S1 / S2 < 1): Преобладание бессмыслицы, указывающее на рост энтропии и хаоса.
Таким образом, рычажные весы смысла и бессмыслицы являются мощной метафорой для описания динамических процессов самоорганизации и деградации в системах, отражающих вечную борьбу между порядком и хаосом, смыслом и бессмыслицей.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
"Смесь бульдога с носорогом" или на стыке предметов.
На основе идеи двойственности, можно создать класс для управления инвестиционным портфелем, который учитывает баланс между доходами и обязательствами, активами и пассивами, а также принцип двойственности - "Всякой твари по паре". Двойственные отношения через базисные экспоненциальные функции и их связь с множественными концепциями, включая спиральность, фазовые сдвиги и принципы симметрии. Этот подход не только затрагивает математические аспекты, такие как ряды Тейлора для экспоненциальных функций, но и более широкие концепции, относящиеся к философии, физике, и даже управлению. Этот пример класса опирается на концепции представленные М.И. Беляевым, его задача показать как помочь инвестору управлять портфелем через балансировку пар, нахождение баланса между активами, обязательствами, доходами и расходами, это своего рода такие математические весы.

Пояснения к классу:
1. Фактор двойственности. Этот фактор отражает дисбаланс между активами и обязательствами.
Когда активов больше, чем обязательств, этот фактор увеличивается, показывая, что инвестор находится в более устойчивой позиции. Если обязательств больше, то фактор будет отражать "долговую нагрузку".
2. Метод `balanceDuality. Он рассчитывает баланс между активами и обязательствами, регулируя фактор двойственности в зависимости от текущего состояния портфеля.
3. Методы для добавления и удаления активов и обязательств. После каждой операции система автоматически пересчитывает баланс.
4. Самонормировка. Вдохновленный идеей о "самонормировке экспоненциальных функций", портфель сам настраивается через фактор двойственности, который балансирует активы и обязательства.

Этот пример, подсвечивает как элегантно, автоматически проходит Самонормировка.
Код
-- Класс для управления портфелем инвестора на основе двойственного подхода
local DualityPortfolioManager = {}
DualityPortfolioManager.__index = DualityPortfolioManager
-- Конструктор
function DualityPortfolioManager:new()
    local instance = {
        assets = {},          -- Активы
        liabilities = {},     -- Обязательства
        income = 0,           -- Доходы
        expenses = 0,         -- Расходы
        dualityFactor = 1     -- Фактор двойственности (влияет на баланс активов и обязательств)
    }
    setmetatable(instance, DualityPortfolioManager)
    return instance
end
-- Метод для добавления актива
function DualityPortfolioManager:addAsset(name, value)
    self.assets[name] = (self.assets[name] or 0) + value
    self:balanceDuality()
end
-- Метод для удаления актива
function DualityPortfolioManager:removeAsset(name, value)
    if self.assets[name] then
        self.assets[name] = self.assets[name] - value
        if self.assets[name] <= 0 then
            self.assets[name] = nil
        end
    end
    self:balanceDuality()
end
-- Метод для добавления обязательства
function DualityPortfolioManager:addLiability(name, value)
    self.liabilities[name] = (self.liabilities[name] or 0) + value
    self:balanceDuality()
end
-- Метод для удаления обязательства
function DualityPortfolioManager:removeLiability(name, value)
    if self.liabilities[name] then
        self.liabilities[name] = self.liabilities[name] - value
        if self.liabilities[name] <= 0 then
            self.liabilities[name] = nil
        end
    end
    self:balanceDuality()
end
-- Метод для добавления дохода
function DualityPortfolioManager:addIncome(value)
    self.income = self.income + value
end
-- Метод для добавления расхода
function DualityPortfolioManager:addExpense(value)
    self.expenses = self.expenses + value
end
-- Метод для баланса двойственности (самонормировка)
function DualityPortfolioManager:balanceDuality()
    -- Рассчитываем соотношение активов и обязательств
    local totalAssets = self:getTotal(self.assets)
    local totalLiabilities = self:getTotal(self.liabilities)
    
    -- Применяем фактор двойственности для поддержания баланса
    if totalAssets > totalLiabilities then
        self.dualityFactor = totalAssets / totalLiabilities
    elseif totalLiabilities > totalAssets then
        self.dualityFactor = totalLiabilities / totalAssets
    else
        self.dualityFactor = 1
    end
end
-- Метод для получения общей стоимости активов или обязательств
function DualityPortfolioManager:getTotal(t)
    local total = 0
    for _, value in pairs(t) do
        total = total + value
    end
    return total
end
-- Метод для расчета чистой стоимости портфеля
function DualityPortfolioManager:calculateNetWorth()
    local totalAssets = self:getTotal(self.assets)
    local totalLiabilities = self:getTotal(self.liabilities)

    -- Рассчитываем с учетом фактора двойственности
    return (totalAssets - totalLiabilities) * self.dualityFactor
end
-- Метод для получения общей информации о портфеле
function DualityPortfolioManager:getPortfolioSummary()
    return {
        assets = self.assets,
        liabilities = self.liabilities,
        income = self.income,
        expenses = self.expenses,
        netWorth = self:calculateNetWorth(),
        dualityFactor = self.dualityFactor
    }
end

-- Пример использования класса
local investor = DualityPortfolioManager:new()
investor:addAsset("Stock A", 10000)
investor:addAsset("Real Estate", 25000)
investor:addLiability("Mortgage", 15000)
investor:addIncome(5000)
investor:addExpense(2000)

local summary = investor:getPortfolioSummary()
for k, v in pairs(summary) do
    if type(v) == "table" then
        print(k .. ":")
        for asset, value in pairs(v) do
            print("  " .. asset .. ": " .. value)
        end
    else
        print(k .. ": " .. v)
    end
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Дальнейшее развитие концепции М.И. Беляева. (Прикладной характер Структурного Анализа рыночных отношений).

Если рассматривать рынок как сложную систему, применяя структурный анализ с учетом иерархических и мульти двойственных отношений, можно организовать рынок в виде сети взаимодействий различных элементов (агентов) и факторов. Основной монадой рыночных отношений, является взаимосвязь спроса и предложения, выраженная в ценах. Как можно построить структурный анализ рынка, учитывая его сложность. Иерархическая структура рынка.
Рынок можно рассматривать как многоуровневую систему, где разные уровни отражают различные аспекты его функционирования.
Например:
а) Макроуровень — глобальные экономические и политические факторы (центральные банки, международные соглашения, денежно-кредитная политика, торговые блоки).
б) Мезоуровень — отрасли и сектора экономики, которые взаимодействуют друг с другом через спрос и предложение, производственные и логистические цепочки.
с) Микроуровень — отдельные участники рынка: компании, покупатели, продавцы, биржи, банки и т.д.
Каждый уровень этой иерархии взаимодействует с соседними уровнями через механизмы координации и субординации.

Начнем с микроуровеня. Биржевой анализ. На финансовых рынках структурный анализ может помочь понять, как взаимодействие участников рынка (инвесторов, маркет-мейкеров, регуляторов) на различных уровнях иерархии определяет динамику цен акций, облигаций и деривативов.
При анализе финансовых рынков на микроуровне важно рассматривать рыночные структуры и отношения между различными участниками, такими как инвесторы, маркет-мейкеры и регуляторы, и как их действия влияют на динамику цен финансовых инструментов (акций, облигаций, деривативов). Микроуровневый биржевой анализ в этом контексте помогает понять краткосрочные ценовые колебания, ликвидность и распределение капитала на рынке.

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

Монада рыночных отношений. Монада в этом контексте — это абстрактное представление взаимосвязанного взаимодействия между всеми рыночными параметрами, которые формируют динамику актива. Монада рыночных отношений включает:
Цена актива (в виде баров) — отражает баланс спроса и предложения за определенный период.
Количество заявок на покупку и продажу — индикатор текущего рыночного настроения и ликвидности.
Открытый интерес — объем открытых позиций, отражающий интерес участников к активу.
Объем торгов — подтверждение силы движения цены.
Волатильность — оценка уровня неопределенности и риска.
Объём ликвидности по ценовым уровням (Level 2) — распределение ликвидности на разных уровнях цены.
Эти элементы можно рассматривать как взаимосвязанные части единой системы, где каждый параметр влияет на другой. Их совместное изучение может привести к более глубокой оценке текущей рыночной ситуации.

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

Движение от микроуровня к монаде (алгоритм).
1. Исходные рыночные данные (нижний уровень). Мы начинаем с анализа микроуровневых данных, таких как:

Заявки на покупку и продажу — количество и объем.
Цены сделок — отражение фактического взаимодействия между покупателями и продавцами.
Открытый интерес — количество открытых позиций (как фьючерсов, так и опционов).
Объемы торгов — подтверждение активности на рынке.
Ликвидность — плотность заявок на разных уровнях цены.
Каждый из этих показателей может быть рассмотрен с точки зрения "весов" или структурных долей покупателей и продавцов.

2. Оценка относительной силы покупателей и продавцов (средний уровень)
На этом этапе происходит расчет весов каждой из сторон. Например, Баланс заявок на покупку и продажу: если на рынке преобладают покупатели, то их доля может быть, скажем, 0.6, а продавцов 0.4. Этот баланс может быть выражен как, Впокупатели=0.6, Впродавцы=0.4

Аналогично мы можем рассчитать и другие пропорции:

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

3. Поиск баланса или монады (верхний уровень)
После того как мы оценили силу участников (покупателей и продавцов) через микроуровневые данные, мы можем определить, как эти отношения формируют общую структуру рынка и стремятся к состоянию баланса. Этот баланс можно представить как целостную систему — монаду: M = Bпокупатели + Bпродавцы = 1 Здесь B — это доли участия каждой стороны.
Например, если Покупатели занимают 60% рынка (0.6), а Продавцы — 40% (0.4), то монада равна 1, что означает, что все силы учтены.
Таким образом, монада рыночных отношений — это итоговая оценка, показывающая, как сильно смещены силы в сторону покупателей или продавцов.

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

Если покупатели активны, их доля возрастает, и рыночные данные показывают это через:
Превышение объема заявок на покупку.
Увеличение объема сделок по покупкам.
Рост открытого интереса в сторону длинных позиций.
Если же продавцы доминируют, эти показатели начинают смещаться в их пользу:
Превышение объема заявок на продажу.
Снижение объемов покупок.
Увеличение коротких позиций.

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

Если баланс смещен в сторону покупателей (например, 0.7 покупатели и 0.3 продавцы), это может говорить о бычьем настроении, и трейдеры могут ожидать продолжения роста цен.
Если баланс смещен в сторону продавцов (например, 0.4 покупатели и 0.6 продавцы), это может указывать на медвежьи настроения, и цены, скорее всего, пойдут вниз.

Заключение
Поиск монады рыночных отношений через микроуровневые данные — это по сути построение целостной картины рынка, начиная с отдельных элементов и заканчивая общей структурой взаимодействия покупателей и продавцов. Это движение "снизу вверх" — от микроуровневого анализа данных к глобальному пониманию баланса на рынке — позволяет принимать более точные торговые решения, основанные на реальном положении дел.
Спин монады в данном случае можно представить как динамическое смещение рыночного баланса, которое отражает, в чью сторону идет движение: к покупателям (росту) или к продавцам (падению).
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Стояла задача оценить финансово хозяйственную деятельность инвестора, ничего лучше придумать не мог и взял за основу модели, финансово хозяйственную деятельность предприятия. Покопался, нашел подход описанный М. Беляев "Милогия", собрал ккласс на Lua для управления портфелем инвестора, основанного на предложенном подходе. Этот класс будет включать методы для добавления и удаления активов, расчета общей стоимости портфеля, а также получения информации о доходах и обязательствах. Создается новый портфель, добавляются активы и обязательства, рассчитываются доходы и расходы, после чего выводится сводка о состоянии портфеля.

Этот класс можно расширять, добавляя новые методы и функциональность, например, для анализа доходности активов, отслеживания динамики портфеля или интеграции с внешними API для получения рыночных данных. Создается новый портфель, добавляются активы и обязательства, рассчитываются доходы и расходы, после чего выводится сводка о состоянии портфеля. Концепция бухгалтерского учета,  перенесена на учет и анализ финансово-хозяйственной деятельности (ФХД) инвестора, применяя аналогию с "весами монады" для управления активами и пассивами. Но главное, это универсальность анализа структуры. Все тут не расскажешь, но как классно все легло по образу и подобию на деятельность Инвестора. Нет предала совершенству.

Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Добрый день nikolz,  ну вот, а то можно подумать что что то случилось? Не знаю флуд это или Ваши заблуждения, Вы по прежнему не читаете сообщения, кроме своих. Чисто из уважения к Вашему возрасту в сотый уже раз повторю, тема давно разобрана по винтикам на данном сайте и не только, вот ссылка, где очень подробно простым языком разыскано о сопрограммах https://fingercomp.gitlab.io/lua-coroutines/#code-1.3. От себя лишь добавлю если еще и этого не достаточно, создайте корутину и возьмите type().
Логика Вашего высказывания тоже не выдерживает критики, Вы привели цитату, ткните пальцем, где есть слово "ОС", или "параллельно". Сопрограмма нужна для создания асинхронности исполнения кода, нет другого варианта в луа уйти от примитивов. Вы писали что пользуетесь таблицей состояний для прерываний. Так воспользуйтесь еще раз, добавьте состояние которое будет отслеживать допустим подключение к серверу, оберните в корутину, и попробуйте, это пример элементарной асинхронности исполнения кода. Я не рассуждаю об ОС, их потоках языках от личных от луа и прочем,  меня интересует эффективное использование прикладной программы на луа. На деюсь не чем Вас не обидел.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Другой важный аспект. Учёт свойства вложенности в колебательных процессах и определение локальных максимумов и минимумов на различных временных масштабах — это ключ к более точному анализу временного ряда. Также важно учитывать лаг, который смещает фазы колебаний, чему виной часто, сам мат. аппарат применяемый в расчетах. Уже важно само понимание того, что отображение цены за интервал времени в формате свечи, это тоже отражение колебаний, которые являются следствием закона спроса и предложения, заложенного в ценообразовании на бирже. Колебательный процесс приводит к пониманию возможности применения со всей строгостью фазаво - частотных характеристик в описании этих данных. Точное определение фазы - вот наша цель! И здесь нужно вспомнить задачу Коши, зная функциональный закон и определяя начальные условия, можем формировать прогноз системы любой природы.
Тема обширна и наверно выходит за рамки данного форума, но не сказать про нее нельзя. Если кто то заинтересовался могу предложить алгоритм подобного подхода, он отличается от академических, но на мой взгляд так же строг и значительно прост в понимании.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Нечетка логика (библиотека LuaFuzzy), хорошо подходит для оценки различных рыночных условий, особенно удобно получать зоны:
перекупленность / перепроданность,
накопление / распределение,
сопротивление / поддержка,
зоны высокой ликвидности.
Все это можно получить используя выше предоставленную библиотеку нечеткой логики, сохраняя высокую степень автоматизации.

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

Использование стандартного отклонения для оценки волатильности и правило трех сигм поможет более точно определить границы для зон. Установив зависимости Волатильность = sigma = стандартное отклонение цен.
Тогда Зоны:
Высокая волатильность: если цена выходит за пределы ±3 * sigma (верояное событие)
Умеренная волатильность: если цена находится в пределах ± 3 * sigma.

Это дает нам четкие критерии для определения трендов при формирования нечетких правил.
Метод еще и универсален так как данные нормированы.
[BUG] getFuturesHolding: ошибка в работе
 
Чуть поясню о чем здесь.
В QUIK есть два подхода обработки фьючерсных позиций: 1. OnFuturesClientHolding` через обратный вызов и 2. getFuturesHolding. На первый взгляд очень соблазнительно выглядит 1 вариант, получил автоматически и забыл, про производительность можно и вообще не вспоминать. Но есть одно НО, к существенному недостатку, приводит обработка данных в неожиданный момент, что усложняет синхронизацию с другими процессами. У себя в программах контролирую момент прихода, по времени, это важно так как всегда есть две координаты {time,price}, поэтому предпочитаю пользоваться 2 вариантом. Ситуация которая заставила задуматься описана выше, чтоб избегать ее применил корутину. Корутинный подход снижает нагрузку и предоставляет больше контроля над частотой обновлений, требуется явный вызов функции. Получаем гибкость в управлении запросами и возможностью контролировать нагрузку на систему, запрашиваем там где требуется и когда требуется. Задача - данные по запросу, например, при анализе состояния позиций в определенные моменты. Корутинный подход позволяет не обращать внимания на nil, не блокировать основной поток, программа продолжает выполнение, а данные обновим при следующим запросе. Чем и как пользоваться каждый решает для себя сам, я лишь озвучил подход.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
В продолжение темы хочется "пропеть пару дифирамб - корутинам" хотя бы и в собственном исполнении. Реализация сопрограмм в луа, на мой взгляд на сколько простая на столько классная. Мало одной модульности нужен еще хороший процессинг. Что позволяет делать корутина, как и функции делить программу по функциональности, на отдельно исполняемые кусочки. Но в отличии от функции исполнение идет в собственном потоке, низко затратам, без использования задержек и блокировки основного потока, может приостанавливать исполнение и возобновлять впоследствии. Подход, в котором каждая стратегия работает в своей корутине, позволяет молниеносно обрабатывать ее, практически не влияя на производительность.  Асинхронность позволяет расставлять приоритеты при принятии решений. Как то странно, на ветке посвященной программированию на луа,  совсем, ну почти совсем это не обсуждается. А ведь сколько полезных вещей можно написать упрощая себе и продлевая программе жизнь. Например вот уже из букваря, реализованных у себя. Итераторы, Конечный автомат, Обработка ошибок, Многопоточность, и даже рисование линий (и видимо можно и объектов ведь рисуют анимации).
Вот тут все классно "разжевано"  https://fingercomp.gitlab.io/lua-coroutines/#code-1.3  
[BUG] getFuturesHolding: ошибка в работе
 
Мало словить проблему, нужно найти ее решение. Решение оказалось на столько элегантным настолько и простым. Асинхронный подход - вызов функций qlua в сопрограммах, элегантно решет данную проблему. В чем суть, вот из "букваря". "В асинхронных программах ключевой элемент — event loop. Ивент луп — это цикл в программе, который ждёт событий и вызывает обработчиков." "Плюс корутины в том, что она умеет останавливаться несколько раз. С корутинами, Ивент луп получил событие A и вызвал корутину - обработчик. Корутина же отправила HTTP-запрос и уснула. Теперь ивент луп её разбудит, когда получит событие B, что соединение установлено. И корутина продолжит работу с того момента в коде, как уснула, что очень удобно. А пока она спит, могут работать другие корутины."
Кому стало интересно, лучше почитать здесь, все просто "разжевано", нужно только "скушать". https://fingercomp.gitlab.io/lua-coroutines/#code-1.3
Всем, хорошего кода!
Все индикаторы на Lua
 
glotov_pa@mail.ru, Вы привели пример из MetaTrader "The indicator corresponds to the ADX indicator in MetaTrader". Это не одно и тоже. Вам нужен вариант для квик, можно найти на этом сайте. Вот вариант от разработчиков, должен выводить все линии
Код
------------------------------------------------------------------
----Moving Average SMA, MMA, EMA, WMA, SMMA, VMA
------------------------------------------------------------------

local SMA,MMA,EMA,WMA,SMMA,VMA = "SMA","MMA","EMA","WMA","SMMA","VMA"
local OPEN,HIGH,LOW,CLOSE,VOLUME,MEDIAN,TYPICAL,WEIGHTED,DIFFERENCE,ANY = "O","H","L","C","V","M","T","W","D","A"

--[[Simple Moving Average (SMA)
SMA = sum(Pi) / n]]
local function F_SMA()
   local sum = {}
   local it = {p=0, l=0}
return function (I, P, VT, ds)
   if I == 1 then
      sum = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / P
      end
   end
return nil
end
end
--[[Modified Moving Average (MMA)
MMA = (MMAi-1*(n-1) + Pi) / n]]
local function F_MMA() 
   local sum = {}
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it = {p=I, l=it.l+1} 
         tmp.pp = tmp.p
      end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      if it.l <= P + 1 then
         sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
         if (it.l == P) or (it.l == P + 1) then
            tmp.p = (sum[Ip] - (sum[Ippp] or 0)) / P
         end
      else
         tmp.p = (tmp.pp*(P-1) + GetValueEX(it.p,VT,ds)) / P
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[Exponential Moving Average (EMA)
EMAi = (EMAi-1*(n-1)+2*Pi) / (n+1)]]
local function F_EMA() 
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it = {p=I, l=it.l+1} 
         tmp.pp = tmp.p
      end
      if it.l == 1 then
         tmp.p = GetValueEX(it.p,VT,ds)
      else
         tmp.p = (tmp.pp*(P-1) + 2*GetValueEX(it.p,VT,ds)) / (P+1)
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[William Moving Average (WMA)
( Previous WILLMA * ( Period - 1 ) + Data ) / Period]]
local function F_WMA()
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it={p=I, l=it.l+1}
         tmp.pp = tmp.p
      end
      if it.l == 1 then
         tmp.p = GetValueEX(it.p,VT,ds)
      else
         tmp.p = (tmp.pp * (P-1) + GetValueEX(it.p,VT,ds)) / P
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[Volume Adjusted Moving Average (VMA)
VMA = sum(Pi*Vi) / sum(Vi)]]
local function F_VMA()
   local sum = {}
   local sum2 = {}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      sum2 = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds) * GetValueEX(it.p,VOLUME,ds)
      sum2[Ip] = (sum2[Ipp] or 0) + GetValueEX(it.p,VOLUME,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / (sum2[Ip] - (sum2[Ippp] or 0))
      end
   end
return nil
end
end
--[[Smoothed Moving Average (SMMA)
SMMAi = (sum(Pi) - SMMAi-1 + Pi) / n]]
local function F_SMMA()
   local sum = {}
   local sum2 = {}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      sum2 = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         if it.l == P then
            sum2[Ip] = (sum[Ip] - (sum[Ippp] or 0)) / P
         else
            sum2[Ip] = ((sum[Ip] - (sum[Ippp] or 0)) - (sum2[Ipp] or 0)+ GetValueEX(it.p,VT,ds)) / P
         end
         return sum2[Ip]
      end
   end
return nil
end
end

local function CandleExist(I,ds)
return (type(C)=="function" and C(I)~=nil) or
   (type(ds)=="table" and (ds[I]~=nil or (type(ds.Size)=="function" and (I>0) and (I<=ds:Size()))))
end
local function Squeeze(I,P)
   return math.fmod(I-1,P+1)
end
local function ConvertValue(T,...)
local function r(V, R) 
   if R and string.upper(R)== "ON" then R=0 end
   if V and tonumber(R) then
      if V >= 0 then return math.floor(V * 10^R + 0.5) / 10^R
      else return math.ceil(V * 10^R - 0.5) / 10^R end
   else return V end
end
local arg = {...}
arg.n = select('#', ...)
   if arg.n > 0 then
      for i = 1, arg.n do
         arg[i]=arg[i] and r(arg[i] * ((T and T.Multiply) or 1), (T and T.Round) or "off")
      end
      return unpack(arg)
   else return nil end
end
local function GetValueEX(I,VT,ds) 
VT=(VT and string.upper(string.sub(VT,1,1))) or ANY
   if VT == OPEN then         --Open
      return (O and O(I)) or (ds and ds:O(I))
   elseif VT == HIGH then       --High
      return (H and H(I)) or (ds and ds:H(I))
   elseif VT == LOW then      --Low
      return (L and L(I)) or (ds and ds:L(I))
   elseif VT == CLOSE then      --Close
      return (C and C(I)) or (ds and ds:C(I))
   elseif VT == VOLUME then      --Volume
      return (V and V(I)) or (ds and ds:V(I)) 
   elseif VT == MEDIAN then      --Median
      return ((GetValueEX(I,HIGH,ds) + GetValueEX(I,LOW,ds)) / 2)
   elseif VT == TYPICAL then   --Typical
      return ((GetValueEX(I,MEDIAN,ds) * 2 + GetValueEX(I,CLOSE,ds))/3)
   elseif VT == WEIGHTED then   --Weighted
      return ((GetValueEX(I,TYPICAL,ds) * 3 + GetValueEX(I,OPEN,ds))/4) 
   elseif VT == DIFFERENCE then   --Difference
      return (GetValueEX(I,HIGH,ds) - GetValueEX(I,LOW,ds))
   else                     --Any
      return (ds and ds[I])
   end
return nil
end
local function MA() --Moving Average ("MA")
   local T_MA = {[SMA]=F_SMA(),[MMA]=F_MMA(),[EMA]=F_EMA(),[VMA]=F_VMA(),[SMMA]=F_SMMA(),[WMA]=F_WMA()}
return function (I, Fsettings, ds)
   local Fsettings=(Fsettings or {})
   local P = (Fsettings.Period or 14)
   if (P > 0) then
      return T_MA[string.upper(Fsettings.Metod or EMA)](I, P, (Fsettings.VType or CLOSE), ds)
   end
return nil
end
end

local function TR() --True Range ("TR")
   local it = {pp=0, p=0, l=0}
return function (I, ds)
   if I == 1 then
      it = {pp=0, p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      if it.l == 1 then
         return math.abs(GetValueEX(it.p,DIFFERENCE, ds))
      else
         return math.max(math.abs(GetValueEX(it.p,DIFFERENCE, ds)), 
            math.abs(GetValueEX(it.p,HIGH,ds) - GetValueEX(it.pp,CLOSE,ds)), 
            math.abs(GetValueEX(it.pp,CLOSE,ds)-GetValueEX(it.p,LOW,ds)))
      end
   end
return nil
end
end
function ADX() --Average Directional Movement Index ("ADX")
   local pDI_MA=MA()
   local mDI_MA=MA()
   local ADX_MA=MA()
   local f_TR=TR()
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)
local Fsettings=(Fsettings or {})
local P = (Fsettings.Period or 14)
local M = (Fsettings.Metod or EMA)
if (P>0) then
   if I == 1 then
      if (M==VMA) then M=SMA end
      it = {pp=0, p=0, l=0}
   end
   local i_TR = f_TR(I,ds)
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      if it.l > 1 then
         if GetValueEX(it.p,HIGH,ds) > GetValueEX(it.pp,HIGH,ds) then
            pDM = math.abs(GetValueEX(it.p,HIGH,ds)-GetValueEX(it.pp,HIGH,ds))
         else pDM = 0 end
         if GetValueEX(it.p,LOW,ds) < GetValueEX(it.pp,LOW,ds) then
            mDM = math.abs(GetValueEX(it.pp,LOW,ds)-GetValueEX(it.p,LOW,ds))
         else mDM = 0 end
         if pDM > mDM then mDM=0 end
         if mDM > pDM then pDM=0 end
         if pDM == mDM then pDM=0 mDM = 0 end
         if i_TR~=0 then pSDI = pDM / i_TR * 100 else pSDI = 0 end
         if i_TR~=0 then mSDI = mDM / i_TR * 100 else mSDI = 0 end
         local pDI = pDI_MA(it.l-1, {Period=P, Metod=M, VType=ANY}, {[it.l-1] = pSDI})
         
         local mDI = mDI_MA(it.l-1, {Period=P, Metod=M, VType=ANY}, {[it.l-1] = mSDI})
         
         if it.l>P and pDI and mDI then
            return ADX_MA(it.l-P, {Period=P, Metod=M, VType=ANY}, {[it.l-P]=math.abs(pDI-mDI)/(pDI+mDI)*100}),pDI,mDI
         else
            return nil,pDI,mDI
         end
      end
   end
end
return nil,nil,nil
end
end

Settings = {
Name = "*ADX (Average Directional Movement Index)", 
Period = 14, 
Metod = "EMA", --(SMA, MMA, EMA, WMA, SMMA, VMA)
line = {{
      Name = "Horizontal line",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "ADX", 
      Type = TYPE_LINE, 
      Color = RGB(0, 162, 232)
      },
      {
      Name = "ADX +DI",
      Type = TYPE_LINE, 
      Color = RGB(0, 206, 0)
      },
      {
      Name = "ADX -DI",
      Type = TYPE_LINE,
      Color = RGB(221, 44, 44)
      }
      },
Round = "off",
Multiply = 1,
Horizontal_line="off"
}
   local func      
function Init() 
   func = ADX()
   return #Settings.line
end
function OnCalculate(Index) 
   return tonumber(Settings.Horizontal_line),ConvertValue(Settings,func(Index, Settings))
end

[BUG] getFuturesHolding: ошибка в работе
 
Цитата
nikolz написал:
Относительно задержки процессора. Я использую Event, об этом писал и вы знаете. В результате реакция на колбек запаздывает не более, чем на 0.00001 сек, а загрузка процессора 3-7%.  
Дело тут не в задержке а в инициализации. Я использую задержки но в данном случае зачем? Сколько не задерживай получишь нил, пока не инициализируешь. И запроса здесь одного мало. И хотелось бы что то услышать от разработчиков это задумка такая или оплошность. И как поступать в алгоритме при смене тикера?
[BUG] getFuturesHolding: ошибка в работе
 
Цитата
funduk написал:
Цитата
VPM написал:
local holdings = nil --getFuturesHolding(self.firmid, self.account, symbol, self.type)
Хоть к теме и не относится, но что-то часто такие ошибки у Вас в коде...

А так -- ну да, getFuturesHolding даёт nil, если не было ордеров по тикеру с прошлого клиринга и одновременно если нет позиции. Наверняка это деталь реализации для какого-нибудь ускорения...
Это заглушка для проверки кода в среде луа (без квик), в квик просто нужно раскомментировать строку.

Так и я про это, как без этих выкрутасов можно понять как работает getFuturesHolding? И где здесь вообще логика? Сделал запрос вернулась таблица, нет запросов зачистили память.
Обломали полумесячный тест.

nikolz, Трудно представить что тут можно по другому local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)  
[BUG] getFuturesHolding: ошибка в работе
 
Для тех кто будет пробовать нужно добавит задержку в код, чтоб не подвешивать процессор. sleep(1000)
Код
function main()
    
   --local type = 0
   local firmid = 'SPBFUT'
    local account = 'SPBFUT00hkv'
   
    local symbol_names = {'NGU4' , 'BRQ4' , 'GDU4', 'NGU4' , 'NGX4' ,}
    working = true
   message("Robot started")
   
    local mm = MoneyManagement:new( firmid, account )-- , type
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      sleep(1000)
   end
end
В моем случае ошибка - nil получена по 3 тикерам.

Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = BRQ4; self.type = 0 number
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = GDU4; self.type = 0 number
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGX4; self.type = 0 number

Вот и возникает вопрос а что делаю не так как описано в инструкции?
[BUG] getFuturesHolding: ошибка в работе
 
Вот поправил рабочий вариант
Код
local MoneyManagement = {}
MoneyManagement.__index = MoneyManagement

function MoneyManagement:new(firmid, account )
    local self = setmetatable({}, MoneyManagement)
    
    self.firmid = firmid
    self.account = account
    self.type = 0
    self.holdings = {}

    return self
end

-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = nil --getFuturesHolding(self.firmid, self.account, symbol, self.type) 
    if holdings then
        
   self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if self.session_status ~= 'основная сессия' then
            message('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
      
    else
        message("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end

    local working = nil
   
function OnStop(stop_flag)
  message(' OnStop: '..'stop_flag = '..tostring(stop_flag) )
  working = false
end

--[[ MAIN LOOP ]]--
function main()
    
   --local type = 0
   local firmid = ''
    local account = ''
   
    local symbol_names = {'NGU4' , 'BRQ4' , 'GDU4', 'NGU4' , 'NGX4' ,}
    working = true
   message("Robot started")
   
    local mm = MoneyManagement:new( firmid, account )-- , type
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      
   end
end
[BUG] getFuturesHolding: ошибка в работе
 
Заметил не точность в строке, нужно исправить на                   local self = setmetatable({}, MoneyManagement)
[BUG] getFuturesHolding: ошибка в работе
 
nikolz,  Не понял что мешает организовать свой поток маин? Вот накидал на скорую руку, попробуйте так поставив свои данные.
Код
local MoneyManagement = {}
MoneyManagement.__index = MoneyManagement

function MoneyManagement:new()
    local self = setmetatable({}, WindowCoordinates)
    
-- поставить свои данные

    self.firmid = ''
    self.account = ''
    self.type = 0

    return self
end

-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)
    if holdings then
        self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        --self.session_status = math.floor(holdings.session_status) or 0
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if getFuturesHolding ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
    else
        Log:info("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end

    local working = nil
   
function OnStop(stop_flag)
  message(' OnStop: '..'stop_flag = '..tostring(stop_flag) )
  working = false
end

--[[ MAIN LOOP ]]--
function main()

    local symbol_names = {
                     'NGU4' 
                  , 'BRQ4' 
                        , 'GDU4'
                   ,
                        }
    working = true
   message("Robot started")
    local mm = MoneyManagement:new()
   
    while working do
   
       for _, symbol in ipairs(symbol_names) do
          mm:FuturesHolding(symbol)
      end
      
   end
end
[BUG] getFuturesHolding: ошибка в работе
 
nikolz, Функция вызова обрабатывается в потоке маин, работает правильно и со стороны пользователя защищена проверкой на nil,  
Цитата
В случае ошибки функция возвращает «nil».
На этот случай дополнительно выводится сообщение и проверяемся корректность ввода пользователем входных параметров. В случае описанном нет ошибки на стороне пользователя (все введено корректно изменился тикер)! Ошибка возникает на стороне функции (Разработчиков), так как возвращает nil то есть - ошибку (читаем документацию)! Вот я и пытаюсь получить комментарий Разработчиков, понять где не точность в функции или документации? Описание говорит что должна вернуться таблица.
[BUG] getFuturesHolding: ошибка в работе
 
nikolz, Выше я показал функцию вызова и ответ на нее. Все прекрасно работало на старом тикере. Сбой происходит в момент ввода нового тикера. Ответ на вызов
local holdings = nil? при этом все входящие данные верны, более того изменился только код тикера.
Цитата
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGU4; self.type = 0 number
 Функция возвращает таблицу Lua, не может быть здесь отсутствие самой таблицы, могут отсутствовать поля этой таблицы, но не сама таблица?

Вот из справки
Цитата

Функция предназначена для получения информации по фьючерсным позициям.

Формат вызова:

TABLE getFuturesHolding(STRING firmid, STRING trdaccid, STRING sec_code, NUMBER type)

Функция возвращает таблицу Lua с параметрами Таблицы «Позиции по клиентским счетам».

В случае ошибки функция возвращает «nil».

Я и допустил что при обновлении тикера не проходит какая - то инициализация, так как таблица отражает владение, то и активировал просто ордер по этому тикеру, сразу функция заработала нормально. Об этом мое сообщение.
[BUG] getFuturesHolding: ошибка в работе
 
funduk, Да заметил спасибо, но это дописано после, хотел уменьшить частоту вывода. Исправил
Код
if self.session_status ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
[BUG] getFuturesHolding: ошибка в работе
 
 Это ответ функции при добавлении нового тикера:
Цитата
Ошибка функции getFuturesHolding, возвращает = nil; self.firmid = SPBFUT; self.account = SPBFUT00hkv; symbol = NGU4; self.type = 0 number
Все параметры введены правильно, не должна выводить local holdings = nil? Выводит nil а правильно сказать ни чего не выводит по данному инструменту! Не понимает пока не обновил таблицу "состояние счета", то есть прогнал пустой ордер чтоб отобразился тикер. Ну почему, Все за что не возьмешься, через одно место? Программе столько лет, все уже должно идеально работать.
Вот сама функция, что не так?
Код
-- Function to get Futures Holding
function MoneyManagement:FuturesHolding(symbol)
    local holdings = getFuturesHolding(self.firmid, self.account, symbol, self.type)
    if holdings then
        self.holdings = holdings
        self.startbuy = holdings.startbuy or 0
        self.startsell = holdings.startsell or 0
        self.startnet = holdings.startnet or 0
        self.todaybuy = holdings.todaybuy or 0
        self.todaysell = holdings.todaysell or 0
        self.totalnet = holdings.totalnet or 0
        self.openbuys = holdings.openbuys or 0
        self.opensells = holdings.opensells or 0
        self.lused = holdings.cbplused or 0
        self.lplanned = holdings.cbplplanned or 0
        self.varmargin = holdings.varmargin or 0
        self.avrposnprice = holdings.avrposnprice or 0
        self.positionvalue = holdings.positionvalue or 0
        self.real_varmargin = holdings.real_varmargin or 0
        self.total_varmargin = holdings.total_varmargin or 0

        --self.session_status = math.floor(holdings.session_status) or 0
        local session_status = {
            [0] = 'не определено',
            [1] = 'основная сессия',
            [2] = 'начался промклиринг',
            [3] = 'завершился промклиринг',
            [4] = 'начался основной клиринг',
            [5] = 'основной клиринг: новая сессия назначена',
            [6] = 'завершился основной клиринг',
            [7] = 'завершилась вечерняя сессия'
        }
        self.session_status = session_status[ math.floor(holdings.session_status)]
        if getFuturesHolding ~= 'основная сессия' then
        Log:trace('Актуальный статус торговой сессии getFuturesHolding: ' .. holdings.session_status .. ' ' .. self.session_status)
        end
    else
        Log:info("Ошибка функции getFuturesHolding, возвращает = " .. tostring(holdings) ..
                     "; self.firmid = " .. tostring(self.firmid) ..
                     "; self.account = " .. tostring(self.account) ..
                     "; symbol = " .. tostring(symbol) ..
                     "; self.type = " .. tostring(self.type)..' '.. type(self.type))
    end
end
история сделок, история сделок
 
Ирина Никонова,  Данный скрипт (утилита) сохраняет сделки за торговую сессию, ровно столько сколько хранит их Квик, ТОРГОВЫЙ день "деюро" иное, можно для понимания ознакомиться на сайте биржи. Если квик отключился то и сделок нет. Когда подключаетесь то сохраненные за сессию сделки подтянутся и сохранятся. Все что нужно подключаться в режиме торговой сессии. И тут BlaZed, прав Ваша проблема скрывает два момента технический и программирования. Для решения каждой нужен отдельный специалист.
история сделок, история сделок
 
Roman Koledin,  Стандартный блокнот, сохраните с расширением .lua,  установите кодировку ANSI, сохраните. Квик: Сервисы, Луа скрипты, Добавить, Запустить.
Золотыми буквами выбить!
 
Andrey Golik QUIK clients support, своими высказываниями, Вы приоткрываете внутреннею сторону финансового бытия, а главное поясняете фундаментальный закон этого бытия, закон спроса и предложения, так как его понимает компания. Вы уже историческая личность, вошли в историю, конечно еще мало осознания от пользователей, но думаю все впереди! Нужно исправлять, или ....  Вот из другой темы некие  пояснения, автор nikolz, ничего не напоминает?
Цитата
Попробую объяснить почему это не будет сделано.
------------------------
Согласно ФЗ о рынке ЦБ сделки на бирже делает не клиент, а брокер.
QUIK лишь терминал для подачи заявок брокеру. .
Поэтому действительны лишь те сделки , которые есть в отчете брокера.
--------------------  
При этом, если Вы выключили QUIK, то историю сделок Вы не получите,
а брокер, вне зависимости от включения QUIK, обязательно Вам ее передаст согласно ГК РФ.
--------------------
В итоге то, что прислал брокер это и есть Ваши сделки.
------------------  
Если формат не устраивает, то конвертируйте в другой формат.
Это техническая задача на уровне студента.
история сделок, история сделок
 
Ирина Никонова,  Если Вас я правильно понял, Вам нужна история собственных сделок, формат csv наверняка подходит, вот код копируйте запускайте, он создаст историю по всем счетам и будет сохранять  собственные сделки, все что нужно запустить скрипт (утилиту) и забыть, остальное она сделает сама, Ваша задача выгружать в excel нужный файл и анализировать или еще чего. Если попали в точку, меня не нужно благодарить, благодарить нужно автора, возможно даже благотворительность проявлять, и здесь не важно сколько, важно как. От себя ни чего добавить не могу, так как запустил когда то и забыл, думаю что это тот самый вариант автора, судите сами. Взято https://quikluacsharp.ru/.
Код
local Run = nil; -- флаг работы цикла в main
local DataFolder = ''; -- Полный путь к папке "Данные(c)quikluacsharp.ru"
local TradesFiles = {};-- Массив дескрипторов файлов

-- Создает каталоги по всем найденным счетам
function CreateAccountsFolders()
   -- Перебирает все счета
   for i=0, getNumberOf("trade_accounts")-1 do
      -- Получает номер счета
      local Account = getItem("trade_accounts", i).trdaccid;
      -- Получает путь
      local Path = '"'..DataFolder..Account..'\\"';
      -- Если каталог не существует
      if os.execute('cd '..Path) == 1 then
         -- Создает каталог
         os.execute('mkdir '..Path); 
      end;
   end;
end;
-- Проверяет записана ли данная сделка в файл истории
function CheckTradeInFile(trade)
   -- Получает путь к файлу инструмента в папке торгового счета
   local PathAccountSec = DataFolder..trade.account..'\\'..trade.sec_code..'.csv';
   -- Пытается открыть файл текущего инструмента в режиме "чтения"
   local TradesFile = io.open(PathAccountSec,"r");
   -- Если файл не существует, то сделка не записана
   if TradesFile == nil then return false;
   else -- Если файл существует
      -- Получает индекс файла
      local FileIndex = trade.account..'_'..trade.sec_code;
      -- Если файл еще не открыт для дописывания
      if TradesFiles[FileIndex] == nil then
         -- Открывает файл текущего инструмента в режиме "дописывания"
         TradesFiles[FileIndex] = io.open(PathAccountSec,"a+");
      end;
      -- Перебирает строки файла
      local Count = 0; -- Счетчик строк
      for line in TradesFile:lines() do
         Count = Count + 1;
         if Count > 1 and line ~= "" then
            -- Если номера сделок совпадают, то сделка записана
            local i = 0;
            for str in line:gmatch("[^;^\n]+") do
               i = i + 1;
               if i == 3 and tonumber(str) == trade.trade_num then
                  TradesFile:close();
                  return true; 
               end;
            end;
         end;      
      end;
   end;
   TradesFile:close();
   return false;
end;
-- Записывает все ранее не записанные сделки из таблицы "Сделки" в файлы
function CheckAndSaveTerminalTrades()
   local trade = nil;
   -- Перебирает все сделки в таблице "Сделки"
   for i=0,getNumberOf("trades")-1,1 do      
      trade = getItem ("trades", i);
      -- Если данная сделка еще не записана в файл истории
      if not CheckTradeInFile(trade) then        
         -- Добавляет сделку в файл истории
         AddTradeInFile(trade);
      end;
   end;
end;
-- Добавляет новую сделку в файл истории
function AddTradeInFile(trade)
   local DateTime = trade and trade.datetime;
   local Date = tonumber(DateTime.year);
   local month = tostring(DateTime.month);
   if #month == 1 then Date = Date.."0"..month; else Date = Date..month; end;
   local day = tostring(DateTime.day);
   if #day == 1 then Date = Date.."0"..day; else Date = Date..day; end;
   Date = tonumber(Date);
   local Time = "";
   local hour = tostring(DateTime.hour);
   if #hour == 1 then Time = Time.."0"..hour; else Time = Time..hour; end;
   local minute = tostring(DateTime.min);
   if #minute == 1 then Time = Time.."0"..minute; else Time = Time..minute; end;
   local sec = tostring(DateTime.sec);
   if #sec == 1 then Time = Time.."0"..sec; else Time = Time..sec; end;
   Time = tonumber(Time);
   -- Если ночная сделка, смещает дату на 1 день вперед
   if Time < 90000 then
      local seconds = os.time(DateTime);
      seconds = seconds + 24*60*60;
      DateTime = os.date("*t",seconds);
      Date = tonumber(DateTime.year);
      month = tostring(DateTime.month);
      if #month == 1 then Date = Date.."0"..month; else Date = Date..month; end;
      day = tostring(DateTime.day);
      if #day == 1 then Date = Date.."0"..day; else Date = Date..day; end;
      Date = tonumber(Date);
   end;
   local Operation = "";
   if CheckBit(trade.flags, 2) == 1 then Operation = "S"; else Operation = "B"; end;
   
   -- Добавляет сделку в массив
   local Trade = {};
   Trade.Account = trade.account;
   Trade.Sec_code = trade.sec_code;
   Trade.Num = trade.trade_num;
   Trade.Date = Date;
   Trade.Time = Time;
   Trade.Operation = Operation;
   Trade.Qty = tonumber(trade.qty);
   Trade.Price = tonumber(trade.price);
   Trade.Hint = "Счет: "..Trade.Account.."_Номер: "..trade.trade_num.."_Дата: ";
   if #day == 1 then Trade.Hint = Trade.Hint.."0"..day.."/"; else Trade.Hint = Trade.Hint..day.."/"; end;
   if #month == 1 then Trade.Hint = Trade.Hint.."0"..month.."/"..DateTime.year; else Trade.Hint = Trade.Hint..month.."/"..DateTime.year; end;
   if #hour == 1 then Trade.Hint = Trade.Hint.."_Время: 0"..hour..":"; else Trade.Hint = Trade.Hint.."_Время: "..hour..":"; end;
   if #minute == 1 then Trade.Hint = Trade.Hint.."0"..minute..":"; else Trade.Hint = Trade.Hint..minute..":"; end;
   if #sec == 1 then Trade.Hint = Trade.Hint.."0"..sec; else Trade.Hint = Trade.Hint..sec; end;
   Trade.Hint = Trade.Hint.."_Количество: "..trade.qty;
   Trade.Hint = Trade.Hint.."_Цена: "..trade.price;
   
   -- Получает путь к файлу инструмента в папке торгового счета
   local PathAccountSec = DataFolder..Trade.Account..'\\'..Trade.Sec_code..'.csv';
   local FileIndex = Trade.Account..'_'..Trade.Sec_code;
   -- Если файл еще не открыт, или не существует
   if TradesFiles[FileIndex] == nil then
      -- Пытается открыть файл текущего инструмента в режиме "дописывания"
      TradesFiles[FileIndex] = io.open(PathAccountSec,"a+");
      -- Если файл не существует, то сделка не записана
      if TradesFiles[FileIndex] == nil then 
         -- Создает файл в режиме "записи"
         TradesFiles[FileIndex] = io.open(PathAccountSec,"w");
         -- Закрывает файл
         message('Закрывает файл: ' ..tostring(FileIndex))
         TradesFiles[FileIndex]:close();
         -- Открывает уже существующий файл в режиме "дописывания"
         TradesFiles[FileIndex] = io.open(PathAccountSec,"a+");
      end;
   end;
   -- Встает в начало файла
   TradesFiles[FileIndex]:seek("set",0);
   -- Если файл пустой
   if TradesFiles[FileIndex]:read() == nil then
      -- Добавляет строку заголовков
      TradesFiles[FileIndex]:write("Счет;Код бумаги;Номер сделки;Дата сделки;Время сделки;Операция;Количество;Цена;Текст подсказки", "\n");
   end;
   -- Встает в конец файла
   TradesFiles[FileIndex]:seek("end",0);
   -- Записывает сделку в файл
   TradesFiles[FileIndex]:write(Trade.Account..";"..Trade.Sec_code..";"..Trade.Num..";"..Trade.Date..";"..Trade.Time..";"..Trade.Operation..";"..Trade.Qty..";"..Trade.Price..";"..Trade.Hint, "\n");TradesFiles[FileIndex]:flush();
end;
-- Функция возвращает значение бита (число 0, или 1) под номером bit (начинаются с 0) в числе flags, если такого бита нет, возвращает nil
function CheckBit(flags, bit)
   -- Проверяет, что переданные аргументы являются числами
   if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!"); end;
   if type(bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!"); end;
   local RevBitsStr  = ""; -- Перевернутое (задом наперед) строковое представление двоичного представления переданного десятичного числа (flags)
   local Fmod = 0; -- Остаток от деления 
   local Go = true; -- Флаг работы цикла
   while Go do
      Fmod = math.fmod(flags, 2); -- Остаток от деления
      flags = math.floor(flags/2); -- Оставляет для следующей итерации цикла только целую часть от деления           
      RevBitsStr = RevBitsStr ..tostring(Fmod); -- Добавляет справа остаток от деления
      if flags == 0 then Go = false; end; -- Если был последний бит, завершает цикл
   end;
   -- Возвращает значение бита
   local Result = RevBitsStr:sub(bit+1,bit+1);
   if Result == "0" then return 0;     
   elseif Result == "1" then return 1;
   else return nil;
   end;
end;
-- Функция возвращает значение бита (0 или 1) под номером bit в числе flags
function CheckBit1(flags, bit)
    -- Проверяет, что переданные аргументы являются числами
    if type(flags) ~= "number" or type(bit) ~= "number" then
        error("Ошибка!!! CheckBit: оба аргумента должны быть числами!")
    end

    -- Проверяет, что бит под номером bit существует в числе flags
    if bit < 0 or bit >= (8 * sizeof(flags)) then
        return nil
    end

    -- Извлекает значение бита с помощью побитовой операции
    local bitValue = (bit32.band(flags, bit32.lshift(1, bit)) > 0) and 1 or 0

    return bitValue
end

-----------------
function OnTrade(trade)
   -- Если данная сделка еще не записана в файл истории
   if not CheckTradeInFile(trade) then        
      -- Добавляет сделку в файл истории
      AddTradeInFile(trade);
   end;
end;
function OnStop()
   -- Закрывает все файлы
   for key,Handle in pairs(TradesFiles) do
      if Handle ~= nil then Handle:close(); end;
   end;
   Run = false;
end;
function OnInit()
   Run = true;
   -- Получает полный путь к папке "Данные(c)quikluacsharp.ru"
   DataFolder = getWorkingFolder()..'\\Данные(c)quikluacsharp.ru\\';
   -- Создает папки по всем найденным счетам
   CreateAccountsFolders();
   -- Записывает все ранее не записанные сделки из таблицы "Сделки" в файлы
   CheckAndSaveTerminalTrades();
end;
function main()
   while Run do
      sleep(1);
   end;   
end;
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
Цитата
TGB написал:
Цитата
VPM написал:
Какую задачу хотите решить?
      В заголовке ветки написано: подключение в скрипте индикаторов папки LuaIndicators с сайта ARQA
Но это не задача, это некий сервис. Повторюсь
Цитата
VPM написал:
Не знаю как последние алгоритмы разработчиков , не пробовал, а первые это транжирство памяти, и помнится Вы мне тоже помогали с этим вопросом разбираться. Из своего опыта нельзя на прямую использовать в алгоритмах эти индикаторы!
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
Ваш код это некий сервис, по подключению алгоритмов (ну по крайней мере я так понял) наверняка он хороший и правильный, вот тока зачем? Какую задачу хотите решить?
Я показал альтернативный подход через класс луа, хотите используете в алгоритмах программ в потоке маин, хотите в виде индикатора квика, все "по образу и подобию", с контролем памяти, и однообразной инициализацией.
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
А понял, если Вы про это, только на график как индикатор и очень осторожно, так ка это путь убить КВИК на повал. Не знаю как последние алгоритмы разработчиков , не пробовал, а первые это транжирство памяти, и помнится Вы мне тоже помогали с этим вопросом разбираться. Из своего опыта нельзя на прямую использовать в алгоритмах эти индикаторы!
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
Так возвращаю результат
local out = decycler[class_names[1]][symbol_names[n]][interval_values[1]]:calculate(I)
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
Вот пример создания

-- Инициализация стратегии Decycler
           --settings.dec = {period = 60, depth = 0, wid = 0, sigma = 1}
           decycler[class][symbol][interval] = DecyclerQueue.new( {
                                         period = 120,
                                         depth = 0, wid = 0, sigma = 1,
                                         scale = feed[1].sec_scale,
                                         step = feed[1].sec_price_step
                                         }
                                         , ds[n][i]--dataSource:getDataSource(class, symbol, interval)
                                         , class, symbol, interval
                                       )
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
TGB,  Ни как не использую, выше привел код подключения модулей, в том числе алгоритмов, которые ныне упаковываю в класс луа. Вот еще из рабочей программы и здесь уже алгоритмы есть индикаторов
Код
 local FractalAnalyzer = require("FractalAnalyzerClass") --setmetatable(FractalAnalyzer, __object_behaviour)
    local BalanceTracker = require("BalanceTrackerClass")
   --local Analytics = require("Analytics")
   --local Strategy = require("Strategy")
    --local Strategy1 = require("Strategy1") --setmetatable(Strategy1, __object_behaviour)
    --local Strategy2 = require("Strategy2") --setmetatable(Strategy2, __object_behaviour)
   local ChannelPDF = require('ChannelPDFQueueClass')
    local DecyclerQueue = require('DecyclerQueueClass')
    local DetrenderQueue = require('DetrenderQueueClass')
   --local HPR = require("hprsClass") setmetatable(HPR, __object_behaviour)
    local HPR = require("HPRsClassv1") --setmetatable(HPR, __object_behaviour)
    local Result = require("ResultClass")
    local Position = require("PositionClass")
    local Instruction = require("InstructionClass")
    local Signal = require("SignalClass")
    local TimeFrameSynchronizer = require("TimeFrameSynchronizer")
    local TradeManager = require("TradeManagerClass")
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
TGB,  Вся библиотека индикаторов от любезно предоставленная разработчиками копируется и вставляется в папку LuaIndicators. Что тут можно показать? :shock:

Я про другое, это луа, здесь создается таблица и вне вставляются элементы (пусть даже алгоритмы), и затем возвращаем и читаем все ТОЧКА. Для каких целей Ваш алгоритм не очень понятно?
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
TGB,  Код я скинул и указал параметры для того чтоб показать как реализуются модули, и только.
Цитата
TGB написал:
То есть, если вам в скрипте надо использовать уже существующий индикатор, то вам интересно его программировать  и отлаживать.
Да нет просто скопировать и вставить.
Цитата
TGB написал:
Действительно, нет проблем реализовать самому любой индикатор. Но вопрос зачем, когда есть готовые коды некоторых индикаторов?
Очень редко применяю готовый код, скорее в тестерах для проверки идеи. А вот хорошую идею это да.

Основная проблема этих старых алгоритмов - это их математика, которая плохо подходит для внутри дневной торговли.  
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Эта страничка начиналась с примера нечеткой логики с использованием алгоритма, даже можно назвать программы ADX. Этот индикатор всегда нравился мне своими правильными смысла, мощью, если бы не одно но. В таком виде  "классическом" он подходит для инвестирования, то есть для использования на больших тайм фреймах, и виной тому заложенное отставание в расчетах этого алгоритма. Для примера вот так его реализовали разработчики
Код
[/CODE][SPOILER=][CODE]------------------------------------------------------------------
----Moving Average SMA, MMA, EMA, WMA, SMMA, VMA
------------------------------------------------------------------

local SMA,MMA,EMA,WMA,SMMA,VMA = "SMA","MMA","EMA","WMA","SMMA","VMA"
local OPEN,HIGH,LOW,CLOSE,VOLUME,MEDIAN,TYPICAL,WEIGHTED,DIFFERENCE,ANY = "O","H","L","C","V","M","T","W","D","A"

--[[Simple Moving Average (SMA)
SMA = sum(Pi) / n]]
local function F_SMA()
   local sum = {}
   local it = {p=0, l=0}
return function (I, P, VT, ds)
   if I == 1 then
      sum = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / P
      end
   end
return nil
end
end
--[[Modified Moving Average (MMA)
MMA = (MMAi-1*(n-1) + Pi) / n]]
local function F_MMA() 
   local sum = {}
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it = {p=I, l=it.l+1} 
         tmp.pp = tmp.p
      end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      if it.l <= P + 1 then
         sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
         if (it.l == P) or (it.l == P + 1) then
            tmp.p = (sum[Ip] - (sum[Ippp] or 0)) / P
         end
      else
         tmp.p = (tmp.pp*(P-1) + GetValueEX(it.p,VT,ds)) / P
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[Exponential Moving Average (EMA)
EMAi = (EMAi-1*(n-1)+2*Pi) / (n+1)]]
local function F_EMA() 
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it = {p=I, l=it.l+1} 
         tmp.pp = tmp.p
      end
      if it.l == 1 then
         tmp.p = GetValueEX(it.p,VT,ds)
      else
         tmp.p = (tmp.pp*(P-1) + 2*GetValueEX(it.p,VT,ds)) / (P+1)
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[William Moving Average (WMA)
( Previous WILLMA * ( Period - 1 ) + Data ) / Period]]
local function F_WMA()
   local tmp = {pp=nil, p=nil}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      tmp = {pp=nil, p=nil}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then 
         it={p=I, l=it.l+1}
         tmp.pp = tmp.p
      end
      if it.l == 1 then
         tmp.p = GetValueEX(it.p,VT,ds)
      else
         tmp.p = (tmp.pp * (P-1) + GetValueEX(it.p,VT,ds)) / P
      end
      if it.l >= P then
         return tmp.p
      end
   end
return nil
end
end
--[[Volume Adjusted Moving Average (VMA)
VMA = sum(Pi*Vi) / sum(Vi)]]
local function F_VMA()
   local sum = {}
   local sum2 = {}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      sum2 = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds) * GetValueEX(it.p,VOLUME,ds)
      sum2[Ip] = (sum2[Ipp] or 0) + GetValueEX(it.p,VOLUME,ds)
      if it.l >= P then
         return (sum[Ip] - (sum[Ippp] or 0)) / (sum2[Ip] - (sum2[Ippp] or 0))
      end
   end
return nil
end
end
--[[Smoothed Moving Average (SMMA)
SMMAi = (sum(Pi) - SMMAi-1 + Pi) / n]]
local function F_SMMA()
   local sum = {}
   local sum2 = {}
   local it = {p=0, l=0}
return function(I, P, VT, ds)
   if I == 1 then
      sum = {}
      sum2 = {}
      it = {p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={p=I, l=it.l+1} end
      local Ip,Ipp,Ippp = Squeeze(it.l,P),Squeeze(it.l-1,P),Squeeze(it.l-P,P)
      sum[Ip] = (sum[Ipp] or 0) + GetValueEX(it.p,VT,ds)
      if it.l >= P then
         if it.l == P then
            sum2[Ip] = (sum[Ip] - (sum[Ippp] or 0)) / P
         else
            sum2[Ip] = ((sum[Ip] - (sum[Ippp] or 0)) - (sum2[Ipp] or 0)+ GetValueEX(it.p,VT,ds)) / P
         end
         return sum2[Ip]
      end
   end
return nil
end
end

local function CandleExist(I,ds)
return (type(C)=="function" and C(I)~=nil) or
   (type(ds)=="table" and (ds[I]~=nil or (type(ds.Size)=="function" and (I>0) and (I<=ds:Size()))))
end
local function Squeeze(I,P)
   return math.fmod(I-1,P+1)
end
local function ConvertValue(T,...)
local function r(V, R) 
   if R and string.upper(R)== "ON" then R=0 end
   if V and tonumber(R) then
      if V >= 0 then return math.floor(V * 10^R + 0.5) / 10^R
      else return math.ceil(V * 10^R - 0.5) / 10^R end
   else return V end
end
local arg = {...}
arg.n = select('#', ...)
   if arg.n > 0 then
      for i = 1, arg.n do
         arg[i]=arg[i] and r(arg[i] * ((T and T.Multiply) or 1), (T and T.Round) or "off")
      end
      return unpack(arg)
   else return nil end
end
local function GetValueEX(I,VT,ds) 
VT=(VT and string.upper(string.sub(VT,1,1))) or ANY
   if VT == OPEN then         --Open
      return (O and O(I)) or (ds and ds:O(I))
   elseif VT == HIGH then       --High
      return (H and H(I)) or (ds and ds:H(I))
   elseif VT == LOW then      --Low
      return (L and L(I)) or (ds and ds:L(I))
   elseif VT == CLOSE then      --Close
      return (C and C(I)) or (ds and ds:C(I))
   elseif VT == VOLUME then      --Volume
      return (V and V(I)) or (ds and ds:V(I)) 
   elseif VT == MEDIAN then      --Median
      return ((GetValueEX(I,HIGH,ds) + GetValueEX(I,LOW,ds)) / 2)
   elseif VT == TYPICAL then   --Typical
      return ((GetValueEX(I,MEDIAN,ds) * 2 + GetValueEX(I,CLOSE,ds))/3)
   elseif VT == WEIGHTED then   --Weighted
      return ((GetValueEX(I,TYPICAL,ds) * 3 + GetValueEX(I,OPEN,ds))/4) 
   elseif VT == DIFFERENCE then   --Difference
      return (GetValueEX(I,HIGH,ds) - GetValueEX(I,LOW,ds))
   else                     --Any
      return (ds and ds[I])
   end
return nil
end
local function MA() --Moving Average ("MA")
   local T_MA = {[SMA]=F_SMA(),[MMA]=F_MMA(),[EMA]=F_EMA(),[VMA]=F_VMA(),[SMMA]=F_SMMA(),[WMA]=F_WMA()}
return function (I, Fsettings, ds)
   local Fsettings=(Fsettings or {})
   local P = (Fsettings.Period or 14)
   if (P > 0) then
      return T_MA[string.upper(Fsettings.Metod or EMA)](I, P, (Fsettings.VType or CLOSE), ds)
   end
return nil
end
end

local function TR() --True Range ("TR")
   local it = {pp=0, p=0, l=0}
return function (I, ds)
   if I == 1 then
      it = {pp=0, p=0, l=0}
   end
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      if it.l == 1 then
         return math.abs(GetValueEX(it.p,DIFFERENCE, ds))
      else
         return math.max(math.abs(GetValueEX(it.p,DIFFERENCE, ds)), 
            math.abs(GetValueEX(it.p,HIGH,ds) - GetValueEX(it.pp,CLOSE,ds)), 
            math.abs(GetValueEX(it.pp,CLOSE,ds)-GetValueEX(it.p,LOW,ds)))
      end
   end
return nil
end
end
function ADX() --Average Directional Movement Index ("ADX")
   local pDI_MA=MA()
   local mDI_MA=MA()
   local ADX_MA=MA()
   local f_TR=TR()
   local it = {pp=0, p=0, l=0}
return function (I, Fsettings, ds)
local Fsettings=(Fsettings or {})
local P = (Fsettings.Period or 14)
local M = (Fsettings.Metod or EMA)
if (P>0) then
   if I == 1 then
      if (M==VMA) then M=SMA end
      it = {pp=0, p=0, l=0}
   end
   local i_TR = f_TR(I,ds)
   if CandleExist(I,ds) then
      if I~=it.p then it={pp=it.p, p=I, l=it.l+1} end
      if it.l > 1 then
         if GetValueEX(it.p,HIGH,ds) > GetValueEX(it.pp,HIGH,ds) then
            pDM = math.abs(GetValueEX(it.p,HIGH,ds)-GetValueEX(it.pp,HIGH,ds))
         else pDM = 0 end
         if GetValueEX(it.p,LOW,ds) < GetValueEX(it.pp,LOW,ds) then
            mDM = math.abs(GetValueEX(it.pp,LOW,ds)-GetValueEX(it.p,LOW,ds))
         else mDM = 0 end
         if pDM > mDM then mDM=0 end
         if mDM > pDM then pDM=0 end
         if pDM == mDM then pDM=0 mDM = 0 end
         if i_TR~=0 then pSDI = pDM / i_TR * 100 else pSDI = 0 end
         if i_TR~=0 then mSDI = mDM / i_TR * 100 else mSDI = 0 end
         local pDI = pDI_MA(it.l-1, {Period=P, Metod=M, VType=ANY}, {[it.l-1] = pSDI})
         
         local mDI = mDI_MA(it.l-1, {Period=P, Metod=M, VType=ANY}, {[it.l-1] = mSDI})
         
         if it.l>P and pDI and mDI then
            return ADX_MA(it.l-P, {Period=P, Metod=M, VType=ANY}, {[it.l-P]=math.abs(pDI-mDI)/(pDI+mDI)*100}),pDI,mDI
         else
            return nil,pDI,mDI
         end
      end
   end
end
return nil,nil,nil
end
end

Settings = {
Name = "*ADX (Average Directional Movement Index)", 
Period = 14, 
Metod = "EMA", --(SMA, MMA, EMA, WMA, SMMA, VMA)
line = {{
      Name = "Horizontal line",
      Type = TYPE_LINE, 
      Color = RGB(140, 140, 140)
      },
      {
      Name = "ADX", 
      Type = TYPE_LINE, 
      Color = RGB(0, 162, 232)
      },
      {
      Name = "ADX +DI",
      Type = TYPE_LINE, 
      Color = RGB(0, 206, 0)
      },
      {
      Name = "ADX -DI",
      Type = TYPE_LINE,
      Color = RGB(221, 44, 44)
      }
      },
Round = "off",
Multiply = 1,
Horizontal_line="off"
}
   local func      
function Init() 
   func = ADX()
   return #Settings.line
end
function OnCalculate(Index) 
   return tonumber(Settings.Horizontal_line),ConvertValue(Settings,func(Index, Settings))
end

[/SPOILER]Вот так переписываюlocal ADX = {}
ADX.__index = ADX


function ADX:new(settings)
   local instance = setmetatable({}, ADX)
   instance.settings = settings or {
       Name = "*ADX (Average Directional Movement Index)",
       Period = 14,
       Method = "EMA",
       line = {
           {Name = "Horizontal line", Type = TYPE_LINE, Color = RGB(140, 140, 140)},
           {Name = "ADX", Type = TYPE_LINE, Color = RGB(0, 162, 232)},
           {Name = "ADX +DI", Type = TYPE_LINE, Color = RGB(0, 206, 0)},
           {Name = "ADX -DI", Type = TYPE_LINE, Color = RGB(221, 44, 44)}
       },
       Round = "off",
       Multiply = 1,
       Horizontal_line = "off"
   }
   instance:initialize()
   return instance
end


function ADX:initialize()
   self.pDI_MA = self:createMovingAverage()
   self.mDI_MA = self:createMovingAverage()
   self.ADX_MA = self:createMovingAverage()
   self.f_TR = self:createTrueRange()
   self.it = {pp = 0, p = 0, l = 0}
end
function ADX:createMovingAverage()
   local T_MA = {
       [SMA] = self.F_SMA(),
       [MMA] = self.F_MMA(),
       [EMA] = self.F_EMA(),
       [VMA] = self.F_VMA(),
       [SMMA] = self.F_SMMA(),
       [WMA] = self.F_WMA()
   }
   return function(I, settings, ds)
       local settings = settings or {}
       local P = settings.Period or 14
       if P > 0 then
           return T_MA[string.upper(settings.Method or EMA)](I, P, settings.VType or CLOSE, ds)
       end
       return nil
   end
end
function ADX:createTrueRange()
   local it = {pp = 0, p = 0, l = 0}
   return function(I, ds)
       if I == 1 then
           it = {pp = 0, p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then it = {pp = it.p, p = I, l = it.l + 1} end
           if it.l == 1 then
               return math.abs(self:GetValueEX(it.p, DIFFERENCE, ds))
           else
               return math.max(math.abs(self:GetValueEX(it.p, DIFFERENCE, ds)),
                   math.abs(self:GetValueEX(it.p, HIGH, ds) - self:GetValueEX(it.pp, CLOSE, ds)),
                   math.abs(self:GetValueEX(it.pp, CLOSE, ds) - self:GetValueEX(it.p, LOW, ds)))
           end
       end
       return nil
   end
end
function ADX:calculate(I, settings, ds)
   local P = settings.Period or 14
   local M = settings.Method or EMA
   if P > 0 then
       if I == 1 then
           if M == VMA then M = SMA end
           self.it = {pp = 0, p = 0, l = 0}
       end
       local i_TR = self.f_TR(I, ds)
       if self:CandleExist(I, ds) then
           if I ~= self.it.p then self.it = {pp = self.it.p, p = I, l = self.it.l + 1} end
           if self.it.l > 1 then
               local pDM, mDM
               if self:GetValueEX(self.it.p, HIGH, ds) > self:GetValueEX(self.it.pp, HIGH, ds) then
                   pDM = math.abs(self:GetValueEX(self.it.p, HIGH, ds) - self:GetValueEX(self.it.pp, HIGH, ds))
               else pDM = 0 end
               if self:GetValueEX(self.it.p, LOW, ds) < self:GetValueEX(self.it.pp, LOW, ds) then
                   mDM = math.abs(self:GetValueEX(self.it.pp, LOW, ds) - self:GetValueEX(self.it.p, LOW, ds))
               else mDM = 0 end
               if pDM > mDM then mDM = 0 end
               if mDM > pDM then pDM = 0 end
               if pDM == mDM then pDM = 0 mDM = 0 end
               local pSDI = (i_TR ~= 0) and (pDM / i_TR * 100) or 0
               local mSDI = (i_TR ~= 0) and (mDM / i_TR * 100) or 0
               local pDI = self.pDI_MA(self.it.l - 1, {Period = P, Method = M, VType = ANY}, {[self.it.l - 1] = pSDI})
               local mDI = self.mDI_MA(self.it.l - 1, {Period = P, Method = M, VType = ANY}, {[self.it.l - 1] = mSDI})
               if self.it.l > P and pDI and mDI then
                   return self.ADX_MA(self.it.l - P, {Period = P, Method = M, VType = ANY}, {[self.it.l - P] = math.abs(pDI - mDI) / (pDI + mDI) * 100}), pDI, mDI
               else
                   return nil, pDI, mDI
               end
           end
       end
   end
   return nil, nil, nil
end


-- Methods for different Moving Averages (SMA, MMA, EMA, WMA, SMMA, VMA)
function ADX:F_SMA()
   local sum = {}
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           sum = {}
           it = {p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then it = {p = I, l = it.l + 1} end
           local Ip, Ipp, Ippp = self:Squeeze(it.l, P), self:Squeeze(it.l - 1, P), self:Squeeze(it.l - P, P)
           sum[Ip] = (sum[Ipp] or 0) + self:GetValueEX(it.p, VT, ds)
           if it.l >= P then
               return (sum[Ip] - (sum[Ippp] or 0)) / P
           end
       end
       return nil
   end
end
function ADX:F_MMA()
   local sum = {}
   local tmp = {pp = nil, p = nil}
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           sum = {}
           tmp = {pp = nil, p = nil}
           it = {p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then
               it = {p = I, l = it.l + 1}
               tmp.pp = tmp.p
           end
           local Ip, Ipp, Ippp = self:Squeeze(it.l, P), self:Squeeze(it.l - 1, P), self:Squeeze(it.l - P, P)
           if it.l <= P + 1 then
               sum[Ip] = (sum[Ipp] or 0) + self:GetValueEX(it.p, VT, ds)
               if (it.l == P) or (it.l == P + 1) then
                   tmp.p = (sum[Ip] - (sum[Ippp] or 0)) / P
               end
           else
               tmp.p = (tmp.pp * (P - 1) + self:GetValueEX(it.p, VT, ds)) / P
           end
           if it.l >= P then
               return tmp.p
           end
       end
       return nil
   end
end
function ADX:F_EMA()
   local tmp = {pp = nil, p = nil}
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           tmp = {pp = nil, p = nil}
           it = {p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then
               it = {p = I, l = it.l + 1}
               tmp.pp = tmp.p
           end
           if it.l == 1 then
               tmp.p = self:GetValueEX(it.p, VT, ds)
           else
               tmp.p = (tmp.pp * (P - 1) + 2 * self:GetValueEX(it.p, VT, ds)) / (P + 1)
           end
           if it.l >= 1 then
               return tmp.p
           end
       end
       return nil
   end
end
function ADX:F_VMA()
   local sum = {}
   local tmp = {pp = nil, p = nil}
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           sum = {}
           tmp = {pp = nil, p = nil}
           it = {p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then
               it = {p = I, l = it.l + 1}
               tmp.pp = tmp.p
           end
           local Ip, Ipp, Ippp = self:Squeeze(it.l, P), self:Squeeze(it.l - 1, P), self:Squeeze(it.l - P, P)
           sum[Ip] = (sum[Ipp] or 0) + self:GetValueEX(it.p, VT, ds)
           if it.l >= P then
               tmp.p = (sum[Ip] - (sum[Ippp] or 0)) / P
               return tmp.p
           end
       end
       return nil
   end
end
function ADX:F_SMMA()
   local sum = {}
   local tmp = {pp = nil, p = nil}
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           sum = {}
           tmp = {pp = nil, p = nil}
           it = {p = 0, l = 0}
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then
               it = {p = I, l = it.l + 1}
               tmp.pp = tmp.p
           end
           if it.l == P then
               sum[P] = sum[P - 1] + self:GetValueEX(it.p, VT, ds)
               tmp.p = sum[P] / P
           elseif it.l < P then
               sum[it.l] = (sum[it.l - 1] or 0) + self:GetValueEX(it.p, VT, ds)
           else
               tmp.p = (tmp.pp * (P - 1) + self:GetValueEX(it.p, VT, ds)) / P
           end
           if it.l >= P then
               return tmp.p
           end
       end
       return nil
   end
end
function ADX:F_WMA()
   local sum = {}
   local weight_sum = 0
   local it = {p = 0, l = 0}
   return function(I, P, VT, ds)
       if I == 1 then
           sum = {}
           weight_sum = 0
           it = {p = 0, l = 0}
           for i = 1, P do
               weight_sum = weight_sum + i
           end
       end
       if self:CandleExist(I, ds) then
           if I ~= it.p then it = {p = I, l = it.l + 1} end
           local sum_weights = 0
           for i = 1, P do
               if self:CandleExist(it.p - i + 1, ds) then
                   sum_weights = sum_weights + self:GetValueEX(it.p - i + 1, VT, ds) * (P - i + 1)
               end
           end
           if it.l >= P then
               return sum_weights / weight_sum
           end
       end
       return nil
   end
end


-- Helper functions
function ADX:CandleExist(I, ds)
   return ds:C(I) ~= nil
end
function ADX:GetValueEX(I, VT, ds)
   return ds[VT](ds, I)
end
function ADX:Squeeze(I, P)
   return (I - 1) % P + 1
end
return ADX
Модуль подключения индикаторов папки LuaIndicators с сайта ARQA (https://arqatech.com/ru/support/files/)
 
Цитата
TGB написал:
Интересно: нет ни вопросов, ни замечаний. То ли все ясно, то ли не понятно ничего.
Скорее не понятно, зачем? Ведь таблица луа это уже модуль. Ну к примеру моя любая программа сейчас выглядит так,
и это не все классы.
При этом память на один инструмент не более 1000 кб, быстродействие алгоритма ограничиваю чтобы не перегружать процессор. Но это только мое мнение.
Код
-- Установите путь к вашему каталогу с модулями
   local path = '...\\modules';
    package.path = path.."\\?.lua;".. package.path
   
    -- Проверка и подключение необходимых модулей
    local function safeRequire(moduleName)
        local success, result = pcall(require, moduleName)
        if not success then
          error("Failed to load module: " .. moduleName .. "\n" .. result)
        end
        return result
    end
    
    -- Модули
    --local Log = require("LogClass")
    
    local Utility = require("Utility")
    
    local Queue = require("QueueClass") -- Реализация класса `Queue` двусвязной очереди
    local Color = require("ColorClass")
    local Label = require("LabelClass")
    local WindowCoordinates = require("WindowCoordinatesClass")
    local TableSaverLoader = require("TableSaverLoader")
    
    local TimeHandler = require("TimesClass")
    local Checker = require("Checker") --setmetatable(Checker, __object_behaviour)
    local Event = require("EventClass")
    --local VersionManager = require("VersionManager")
    local StateMachine = require("StateMachine") --  Управляет состояниями и переходами между ними.
    local StateManager = require("StateManager") -- Отвечает за сохранение и загрузку состояния из файла.
     
    local DS = require("DSClass") --setmetatable(DS, __object_behaviour)
    local RiskManagement = require("rmClass") --setmetatable(rm, __object_behaviour)
    local MoneyManagement = require("mmClass") --setmetatable(mm, __object_behaviour)
    local CapitalManagement = require("cmClass") --setmetatable(CapitalManagement, __object_behaviour)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
 
Переписал Все! и продолжаю переписывать! Добрался до индикаторов, написанных ранее используя принцип замыкания, все перевожу в класс луа. а иногда и OPP,  в чем суть ниже покажу пример. А если в двух словах, всему основа структура языка луа - таблица. Таблица - это объект, то есть для примера как бы описывали автомобиль, начали бы  перечислять его  свойствами (цвет = красный, мотор = бензиновый и так далее), возможную скорость, расход топлива, уже не описать свойствами нужны методы = функции. Так и при описании позиции, бара, тренда ...  Если еще проще говорить, таблица позволяет оперировать (говорить) смыслами, создавать паттерны. Это позволяет перейти, от элементарной арифметике к векторному счислению и управлению объектами. "Аз. Буки , Ведай, Глаголь, Добро, ..." - это  остатки от языка на котором все создавалось и описывалось - это смыслы. Луа нас возвращает к возможности этим оперировать, об этом автор языка нам рассказывает.  
Хочу заказать скрипт., Хочу заказать скрипт по поиску роботов, которые покупают или продают рыночными заявками.
 
Цитата
nikolz написал:
Написал первый вариант такого скрипта.Пускаю его на тест сервере.Он обрабатывает всю таблицу  это 330 инструментов и 1 млн 100 тысяч записейДля каждого инструмента и каждой записи он ищет по истории нужных роботов.Примерно так.
Поделитесь своими чудесами?
Золотыми буквами выбить!
 
Сейчас поясню вот ссылка, https://forum.quik.ru/forum1/topic8572/  
Золотыми буквами выбить!
 
Нужно Золотыми буквами выбить подход А ПРИЧЕМ ТУТ РЫНОК?
Andrey Golik написал:
Данные манипуляции по редактированию данных для построения графиков выполняются брокером на стороне сервера. Рекомендуем по данному вопросу обратиться к Вашему обслуживающему брокеру.
Доработка индикаторов при принудительном изменении цены акции., Необходимо доработать алгоритмы расчета индикаторов при принудительном изменении цены акции.
 
Цитата
Andrey Golik написал:

Данные манипуляции по редактированию данных для построения графиков выполняются брокером на стороне сервера. Рекомендуем по данному вопросу обратиться к Вашему обслуживающему брокеру.
Данный подход нужно оформить в названии комплекса Ваших программ.  
Хочу заказать скрипт., Хочу заказать скрипт по поиску роботов, которые покупают или продают рыночными заявками.
 
Цитата
nikolz написал:
Написал первый вариант такого скрипта.
Пускаю его на тест сервере.
Он обрабатывает всю таблицу  это 330 инструментов и 1 млн 100 тысяч записей
Для каждого инструмента и каждой записи он ищет по истории нужных роботов.
Примерно так.
Ну даете, nikolz,  Вы не перестаёте меня удивлять :smile:  
Хочу заказать скрипт., Хочу заказать скрипт по поиску роботов, которые покупают или продают рыночными заявками.
 
Это небольшая но рабочая утилита, которая умеет управляться с таблицей всех сделок, то есть тиками.
Конечно это не то что Вы хотите получить, но этот не большой скрипт легко превращается в поиск необходимых Вам данных и многое еще чего, достаточно дописать фильтры.
Что делает данный скрипт, он предназначен для использования в торговой платформе QUIK, создает таблицу, отображающую баланс покупок и продаж за последние 5 минут, и обновляет ее при поступлении новых обезличенных сделок, в окно выводится баланс полученный за каждую 1 минуту.
Это "классический" вариант, алгоритм и идея которого взяты от сюда QuikLuaCSharp.ru, за что автору отдельное "большое человеческое спасибо!",
все что я сделал это превратил его в класс - модуль луа, для удобства использования в своих программах. В общем удачи.
Код
 -- Класс для отслеживания баланса покупок/продаж
local BalanceTracker = {}
BalanceTracker.__index = BalanceTracker
-- Конструктор
function BalanceTracker:new()
    local obj = setmetatable({}, BalanceTracker)
    obj.isRunning = true
    obj.array5Min = {}
    obj.lastBarSeconds = 0
    obj.t_id = nil
    obj:createTable()
    return obj
end
-- Создание таблицы
function BalanceTracker:createTable()
    self.t_id = AllocTable()
    if self.t_id == nil then
        error("Failed to allocate table")
    end

    AddColumn(self.t_id, 0, "1", true, QTABLE_INT_TYPE, 15)
    AddColumn(self.t_id, 1, "2", true, QTABLE_INT_TYPE, 15)
    AddColumn(self.t_id, 2, "3", true, QTABLE_INT_TYPE, 15)
    AddColumn(self.t_id, 3, "4", true, QTABLE_INT_TYPE, 15)
    AddColumn(self.t_id, 4, "5", true, QTABLE_INT_TYPE, 15)
    CreateWindow(self.t_id)
    SetWindowCaption(self.t_id, "Баланс покупок/продаж")
    InsertRow(self.t_id, -1)
end
-- Установка цвета
function BalanceTracker:setColor(col, color)
    SetColor(self.t_id, 1, col, color, RGB(0,0,0), color, RGB(0,0,0))
end
function BalanceTracker:red(col)
    self:setColor(col, RGB(255,128,128))
end
function BalanceTracker:yellow(col)
    self:setColor(col, RGB(240,240,0))
end
function BalanceTracker:green(col)
    self:setColor(col, RGB(128,255,128))
end
-- Добавление нового бара в массив
function BalanceTracker:addNewBarToArray5Min()
    table.insert(self.array5Min, 0)
    if #self.array5Min > 5 then
        table.remove(self.array5Min, 1)
    end
    local offset = 5 - #self.array5Min
    for i = 1, #self.array5Min do
        self:setBalance(self.array5Min[i], i + offset - 1)
    end
end
-- Установка баланса и цвет ячейки
function BalanceTracker:setBalance(newBalance, numCol)
    SetCell(self.t_id, 1, numCol, tostring(newBalance))
    if numCol == 4 then
        self.array5Min[#self.array5Min] = newBalance
    end
    if newBalance < 0 then
        self:red(numCol)
    elseif newBalance == 0 then
        self:yellow(numCol)
    else
        self:green(numCol)
    end
end
-- Проверка на новую минуту
function BalanceTracker:checkNewMin(dealDateTime)
    dealDateTime.sec = 0
    dealDateTime.mcs = 0
    local seconds = os.time(dealDateTime)
    if seconds > self.lastBarSeconds then
        self.lastBarSeconds = seconds
        return true
    else
        return false
    end
end
-- Обработка сделки
function BalanceTracker:onAllTrade(alltrade)
    if alltrade.sec_code == SEC_CODE then
        local newMinute = self:checkNewMin(alltrade.datetime)
        if newMinute then
            self:addNewBarToArray5Min()
        end

        if bit.test(alltrade.flags, 0) then
            self:setBalance(self.array5Min[#self.array5Min] - alltrade.qty, 4)
        else
            self:setBalance(self.array5Min[#self.array5Min] + alltrade.qty, 4)
        end
    end
end
-- Остановка скрипта
function BalanceTracker:onStop()
    self.isRunning = false
end
-- Главный цикл
function BalanceTracker:main()
    while self.isRunning do
        sleep(100) -- Уменьшить частоту вызова
    end
end
--return BalanceTracker

local CLASS_CODE     = "SPBFUT"     -- Класс бумаги
local SEC_CODE       = "NGN4"       -- Код бумаги

-- Создание объекта класса и функции обратного вызова
local balanceTracker = BalanceTracker:new()
function main()
    balanceTracker:main()
end
function OnAllTrade(alltrade)
    balanceTracker:onAllTrade(alltrade)
end
function OnStop()
    balanceTracker:onStop()
end
Куда все подевались?
 
funduk, Не уверен что по этому, а что же тогда будет являться обсуждением? Но в одном Вы правы.
И прежде чем продолжить, должен принести свои извинения, за излишнею грубость и хамство. nikolz,  извините.

Касаемо предмета обсуждения, фактически представлена реализация 3 вариантов кольцевого буфера с разными методами исполнения,
не смотря на то что изменения не значительны, но они сильно влияют на производительность алгоритма. Не вооруженным глазом видно что вариант1 быстрее варианта2.
Здесь рассуждение простые, вариант1 это всегда вставка(1 элемент), в то время как вариант2 это вставка(n элемент буфера).
Видимо фактор производительности, явился решающим для включения разработчиками данного подхода в свои индикаторы, но для меня оно интуитивно смущало из-за не прозрачного расчета индексов. Решил проверить вариант с двухсвязной очередью, дописал вариант для проверки на производительность.
И каково было мое удивление, ну в общем судите сами, вот варианты.
Код
local size = 100000 -- 3
 
do ---- 1.
--local F = {0, 0, 0}
local F = {}
for i = 1, size do
    F[i] = 0
end

local start_time = os.clock()
local function shiftArray(x)
    -- Сдвигаем элементы массива
    F[3] = F[2]
    F[2] = F[1]
    F[1] = x -- Записываем новый элемент в конец массива
    return F -- Возвращаем массив целиком (или можете возвращать только F[3], если нужно)
end
for I=1,size do
--print( shiftArray(I), F[1], F[2], F[3] )
shiftArray(I)
end
local end_time = os.clock()
print("1. Время выполнения для варианта 1:", end_time - start_time, "секунд")
end
do --local F = {0, 0, 0}
local F = {}
for i = 1, size do
    F[i] = 0
end

local start_time = os.clock()
local index = 0
local function addElement(x)
    index = (index % 3) + 1
    F[index] = x
   return F
end
for I=1,size do
--print(addElement(I), F[1], F[2], F[3] )
addElement(I)
end
local end_time = os.clock()
print("2. Время выполнения для варианта 1a:", end_time - start_time, "секунд")
end
do ---- 2.
--local F = {0, 0, 0}
local F = {}
for i = 1, size do
    F[i] = 0
end

local start_time = os.clock()
local index = 0
local function addElement(x)
    -- Обновляем текущий индекс с учетом кольцевого буфера
    index = (index % 3) + 1
    -- Вставляем новый элемент в текущий индекс
    F[index] = x
    
    -- Для наглядности выводим текущий массив
    local result = {}
    for i = 1, 3 do
        result[i] = F[(index - i + 3) % 3 + 1]
    end
    return result
end
for I=1,size do
--print('*',addElement(I), F[1], F[2], F[3] )
addElement(I)
end
local end_time = os.clock()
print("3. Время выполнения для варианта 2:", end_time - start_time, "секунд")
end
do ---- 3. Простой вариант с переменной currentIndex
local F = {}
for i = 1, 1000 do
    F[i] = 0
end

local start_time = os.clock()
local currentIndex = 1
local function addElement(x)
    F[currentIndex] = x
    currentIndex = currentIndex + 1
    if currentIndex > 1000 then
        currentIndex = 1
    end
    return F
end

for i = 1, 100000 do -- Повторяем операцию добавления 100000 раз
    addElement(i)
end

local end_time = os.clock()
print("4. Время выполнения для варианта 3:", end_time - start_time, "секунд")
end
А вот ответы:
1. Время выполнения для варианта 1:   0.009   секунд
2. Время выполнения для варианта 1a:   0.006   секунд
3. Время выполнения для варианта 2:   1.185   секунд
4. Время выполнения для варианта 3:   0.0050000000000001   секунд
>Exit code: 0    Time: 1.768
Страницы: Пред. 1 2 3 4 5 6 7 8 9 10 11 ... 21 След.
Наверх