Добавив в свой инвестиционный портфель облигации, с удивлением для себя обнаружил, что теряю контроль над ситуацией и тому виной те самые облигации. На вопрос что приводит к дискомфорту, ответ очевиден, нужен алгоритм оценки эффективности использования этих самых облигаций.
Нет если держать до погашения, то и ладно. Но ведь интересует сию минутная оценка, возможно средства выделенные используются не эффективно или цена этой облигации на экстремальных оценках и нужна ребалансировка?
"Нет худа, без добра!" эта бинарная конструкция (монада) или супер позиция из квантовой механики, подвинула меня разбираться с вопросом, как улучшить управляемость?
Заглянул в свои архивы. Находка первая, торговая стратегия с использованием индикаторов, опубликованных Уэллсом Уайлдером в книге (Wilder, J. Welles (1978). New Concepts in Technical Trading Systems.), ADX, RSI и SAR — это отличная идея для построения комплексного подхода к торговле. Все три индикатора помогают в создании системы принятия торговых решений, в разных аспектах анализа рынка, их нужно просто уметь комбинировать, чтобы повысить вероятность успешных сделок. Основной не достаток, это методы их расчета (математика), которая приводит к лагам (отставаниям), давно собирался по экспериментировать с этой математикой уменьшить лаг.
Вторая находка, ну а где еще искать способы повышения эффективности - это конечно работы Ральфа Винса! УПРАВЛЕНИЕ КАПИТАЛОМ ПО ВИНСУ - это отдельная особая тема, чего стоит только его основное уравнение торговли TWR = (A^2 + StD^2)^(T/2). Ранее уже реализовывал несколько модулей по его работам, концепт HPR, расчет количества на сделку и другие показатели сделок. Настало время заняться эффективностью.
Не однозначное решение вызвало интеграция State Machine с действующим рабочим кодом. На первый взгляд, задача встраивания StateMachine, для контроля состояний скрипта, в место одного флага, выглядит не совсем логично и однозначно? В место одного флага с двумя степенями свободы, добавляется в систему несколько дополнительных модулей и вспомогательных функций, не очевидных зависимостей? Что казалось бы не добавляет надежности системе?
Пришлось разбираться по порядку, устраняя сомнения, отвечая на вопрос "На фига козе баян?" Ну обо всем и по порядку:
1. Почему State Machine вместо одного флага - это полезно? State Machine не заменяет флаг, а решает принципиально другие задачи. а) Четкие переходы, запрет недопустимых сценариев (вроде перехода ERROR → RUNNING) б) Централизованная логика, вся обработка состояний в одном месте, а не размазана по коду.
2. Какие реальные преимущества?
Код
-- Было:
function OnStop()
WORKING_FLAG = false -- Резкий обрыв без очистки
end
-- Стало:
function handleStoppedState()
cancelAllOrders() -- Гарантированная отмена
closePositions() -- Корректное закрытие
releaseResources() -- Контроль утечек
Log:info("Система остановлена безопасно")
end
3. Почему дополнительные модули, это не произвольное усложнение, а разделение ответственности?
Модуль Ответственность
StateMachine Логика переходов Обработка IDLE → RUNNING ErrorCollector Централизованный сбор ошибок Логирование в OnStop() GUI Визуализация состояния Обновление таблиц
4. Проблема отладки. Конкретные ошибки из лога, решаются, добавляем заглушки с контролем и последующим разбором.
5. Как избежать "неочевидных зависимостей"? Ответ - явная инициализация в OnInit и ее проверка.
Код
function OnInit()
-- Порядок инициализации важен!
StateMachine = require("StateMachine") -- 1. Состояния
ErrorCollector = require("ErrorCollector") -- 2. Ошибки
GUI = require("GUI") -- 3. Интерфейс
-- Проверка инициализации
assert(StateMachine, "StateMachine не загружен")
assert(ErrorCollector, "ErrorCollector не загружен")
-- Конфигурация
StateMachine:configure({
transitions = cfg.transitions,
initialState = "IDLE"
})
end
6. Работоспособность кода? Выполняется с помощью ключевых проверок.
Код
-- Тест переходов между состояниями
local function testStateTransitions()
local sm = StateMachine
sm:transitionTo("RUNNING")
assert(sm:isState("RUNNING"), "Ошибка перехода в RUNNING")
sm:transitionTo("ERROR")
assert(sm:isState("ERROR"), "Ошибка перехода в ERROR")
sm:transitionTo("IDLE")
assert(not sm:isState("IDLE"), "Недопустимый переход ERROR → IDLE должен быть запрещен")
end
7. Альтернативный подход? Возможен минималистичный вариант State Machine без лишних модулей? Да.
Вот и получается, State Machine — это не усложнение ради усложнения, а 1) Защита от недопустимых сценариев; 2) Четкий контроль жизненного цикла; 3) Упрощение добавления новых состояний; 4) Централизованное логирование; ... Аллегория здесь возможно такая. Это инвестиции в будущее, в отличии от спекулятивного подхода (с флагом) Сам процесс, интеграции State Machine в код тоже имеет как минимум два решения, 1) в главном цикле; 2) асинхронный вариант. Но это уже другая тема.
В заключении отмечу, интеграция State Machine действительно добавляет некоторую сложность, но даёт: А. Снижение количества ошибок на 40-60% (не моя оценка); Б. Упрощение отладки в 2-3 раза (не моя оценка); С. Возможность формальной верификации сценариев.
Закнчивая тему рефакторинга кода, стоит добавить что на практике он уменя свелся к созданию дополнительных модулей, отвечающих за надежность уже самой системы. Вот основные из них. 1) Мониторинг производительности (QSA-PERF) модуль PerformanceMonitor; 2) Автомат защиты (QSA-CIRCUIT), модуль CircuitBreaker. Некоторому переосмысливанию логики модулей управления, например Модуль управления сопрограммами CoroutineManager, добавлены приоритеты. Осознание, что большинство критических ошибок находится на стыке взаимодействия скрипта с квиком, Привело к добавлению самостоятельного модуля Контроллер (QSA-GUI) GUIController, QSA-CORO)
От этого сложность программы не уменьшилась, а значить и надежность не очень повысилась, но есть осознание куда двигаться в целях повышения надежности и тесто пригодности. Так как модуль зачастую исполняется в собственной сопрограмме, то и задачу можно свести к тесто пригодности этого модуля. В общем, Рефакторинг это не состояние, это процесс!
Прогнозная зона графика, График цены или индикатора по оси времени можно сдвигать образуя прогнозную зону. Но как с ней работать с самописными индикаторами?
Добрый день! Разработчики предусмотрели возможность сдвигать графики по оси времени, тем самым можно создавать прогнозную зону или накладывать прошлые значения на настоящее время. На как с этими сдвигами работать? Какие индексы должен получать скрипт на луа чтоб корректно отображались расчетные значения при таких сдвигах? Как отрисовывать график при сдвиге? В общем думается проблема с индексами?
Почему важно учитывать эти стандарты при создании своего проекта? Очевидное.
1) Так как, взаимодействие проекта будет происходит с промышленной торговой системой, то не плохо чтоб и проект соответствовал таким же требованиям. 2) Задача проекта несколько упрощается, так как среда его использования (QUIK), уже должна учитывать и отвечать этим требованиям, нам лишь нужно учитывать особенности среды QUIK и языка написания Lua. 3) Это позволяет выйти на единую архитектуру структуры проекта, работать с несколькими модулями, каждый из которых будет выполнять свою функцию. Подобная структура проекта, будет ориентирована на создание модульного и масштабируемого решения, которое легко будет адаптировать и поддерживать. В данном случае, мы будем учитывать требования для надежности, безопасности, масштабируемости и соответствия нормативам, а также особенности среды QUIK. Будем опираться на принципы модульности, отказоустойчивости и масштабируемости. Архитектура должна включать компоненты для обеспечения отказоустойчивости и мониторинга, а также соблюдать строгие стандарты отчетности и аудита.
Базовая архитектура может содержать несколько ключевых модулей для такой системы. Минимальная структура должна включать: • Модуль для отправки ордеров • Модуль для получения котировок • Модуль для работы с портфелем • Модуль для анализа рисков • Модуль для генерации отчетности (согласованной с MiFID II) • Модуль мониторинга и аудита Эта структура предоставляет основу для создания торговой системы, обеспечивающей отказоустойчивость, безопасность и соответствие промышленным нормативам.
А главный цикл такой программы, для примера, может выглядеть так.
Код
-- Core/Main.lua
function main()
ConfigManager.load("config.prod.json")
Logger.init(ConfigManager.get("logging"))
local ok, err = pcall(function()
StateManager:restore()
RiskManager:init()
while StateManager:is_active() do
local signals = SignalGenerator.generate()
local filtered = RiskManager.filter(signals)
OrderExecutor.execute_all(filtered)
StateManager:update_metrics()
ReportManager.send_daily()
sleep(100)
end
end)
if not ok then
Logger:error("Critical failure", {error = err})
EmergencyShutdown.execute()
end
end
Добиваясь стабильной работы, от варианта торговой программы в асинхронном исполнении, решил посмотреть, как к этому вопросу подходят при создании профессиональных программ. Основная проблема тестирование и отладка такой асинхронной программы, нужен реал - тайм, бэк - тесты здесь не проходят, а это очень медленно (пока отлаживаешь забываешь, уже зачем все делал). По этому, важно изначально отсекать, излишние проблемы на стадии проектирования. Переработал архитектуру своей такой программы. Для этого окунулся в промышленные стандарты, что должна уметь, что должна делать, и так далее такая программа. Собственно с этого и нужно было начинать, при создании проекта, приятно был удивлен, достаточно хорошей проработке этих стандартов (и это то в финансовой сфере та ). В общем кому интересно, кто задумается над подобными вопросами, вот основные, на что стоит обратить внимание, по моему скромному мнению.
Промышленная архитектура торговой программы должна соответствовать требованиям: 1. ISO 27001 для финансовых систем; 2. MiFID II для торговых платформ; 3. SEC Regulation SCI для электронных торгов.
Блок схему своей архитектуры мне страшно даже показать, это работа для целой команды, да и реализовано еще только ядро, к которому прикручиваю отдельные модули, да и все еще не один раз поменяется. Хороших алгоритмов.
А если, реализовать "Конечный автомат состояний", например доработав функцию Ziveleos, чтоб не доводить до ошибки? 1. Чёткое разделение на состояния: Активен/Приостановлен/Авария ... 2. Автоматические действия при смене состояний (например, отмена ордеров в аварийном режиме или вашей ситуации)?
На самом деле проблема стара как этот мир (в нашем случае квик), сейчас продемонстрирую на небольшом примере. 1) Вариант просто создаю таблицу с методами. 2) "Танцы с бубнами" - Моя древняя функция боюсь ее уже даже руками трогать.
Я тоже не программист! Ваш код это дело начинающих, чтоб разобраться ка все работает. Но давайте обо всем и по порядку. 1. OnCalculate это функция обратного вызова или на ангельском (Колбэк), Не в даваясь в подробности реагирует на каждый "чих" изменения. Если Вы строите свой алгоритм от момента появления новой свечи, то текущею свечу можем получить с помощью Функции Size()! Что по факту index == Size(). В расчетах индикатора используем историю по данным, то есть index - 1, -2, -3 и так далее. То что с минусом свеча сформированная - закрытая, а текущая нет в процессе, все может поменяться (Например изменился Максимум), на этот и реагирует колбек. 2. Писать лучше в луа алгоритм в анонимной функции. Собственно в луа функция и есть замыкание! Примеров масса, на этом форуме. Я Вам могу порекомендовать библиотеку от разработчиков. Да она не идеальна но на путь истины наставляет. Удачи!
TGB написал: Давайте, подискутируем. Может быть я заблуждаюсь больше чем две недели?
TGB, Похоже остались тут вдвоем, не я бы Вам ответил, правдо зная про что? Не понимаю и Вам зачем, наверно нужно или скучно стало? Не ну ладно, я "несу всякую ахинею", разбирая свои идеи по винтикам и полочкам на примерах. А где взять базу случайных чисел? Но Вы то ...? А администраторы? Взяли заблокировали Владимира, и как нам теперь узнать как поживает его "супер- пупер" черная коробочка, думаю подался уже в "форбс" и нам не "чита"? Не я то еще тут побуду, времени на реализацию идей добавилось, даже "Бредовых". Лично от себя, не знаю как сейчас, раньше была поговорка "Будь проще народ подтянется! И Вам удачи в начинаниях!
Во дела! Снижение на американском рынке оценивают в -17%, насколько помню -20% критично для фондов. плотно зашли в медвежий тренд, и стоим на пороге ликвидации позиций крупными участниками? "За что купил, за то продал".
Karina Dmitrieva, Спасибо, с этим я разобрался, меня поразило другое, почему все отдано на откуп брокеру? Почему нет единого алгоритма расчета зашитого в программе? Или у каждого брокера своя арифметика? Перевести из процентов в валюту и затем сконвертировать? Три брокера и каждый по своему, но больше всего Сбер поразил, даже не понимают о чем говорят! Чудеса да и только!
Вот и нашлась причина укрепления рубля, кто бы мог подумать? К импортерам и годовым налогам добавились.
"Иностранные хедж-фонды вкладывают в Россию «ковбойские деньги» через дружественные юрисдикции, что заметно по динамике ОФЗ и курса рубля. Об этом заявил журналистам замминистра финансов Иван Чебесков"
Так нельзя, значения приходят в формате STRING а Вы суммируете строку.
Цитата
Дмитрий написал: bid = getParamEx2(classCode,secCode, "bid").param_value+0
Код
--Попробуйте так, но прежде проверьте код контрака действующей или нет?
--1) возвращает таблицу Lua с параметрами
local params = getParamEx2(classCode,secCode, "bid")
if not params then message( tostring(classCode) ..'; '.. tostring(secCode) ..' ?') end
if params then
--значения приходят в формате STRING, для вычислений переводим
local bid = tonumber(tab.param_value)
message( 'bid: '.. tostring(secCode) )
end
Stivins написал: Как тогда принятый через CreateDataSource массив уменьшить до последних 20 свечей?
CreateDataSource это не передача массивов, это подписка на получение необходимых данных (методы получения ds:H(I)), сами данные на сервере квик. Я Вам вчера сбрасывал скрипт там все есть, меняйте count, количество свечей в получаемом массиве. local dailyCandles = getCandles(ds_D1, 4) то есть 4 бара получаем. а в этом случае local h1Candles = getCandles(ds_H1, 5) пять, поменяйте на 20. Вам нужно мат. часть подтянуть, отсюда путаница.
Вот цитата из официального ответа: "Еврооблигации номинированы в долларах США, но приобретены в рублях по курсу на дату покупки, в связи с чем балансовая цена по данным ценным бумагам может уменьшаться и увеличиваться в связи с перерасчётом балансовой цены на курс USD."
local string_upper,string_sub=string.upper,string.sub; function Value(I,VType,ds)
local Out = nil local VType=(VType and string_upper(string_sub(VType,1,1))) or "A" if VType == "O" then --Open Out = (O and O(I)) or (ds and ds:O(I)) elseif VType == "H" then --High Out = (H and H(I)) or (ds and ds:H(I)) elseif VType == "L" then --Low Out = (L and L(I)) or (ds and ds:L(I)) elseif VType == "C" then --Close Out = (C and C(I)) or (ds and ds:C(I)) elseif VType == "V" then --Volume Out = (V and V(I)) or (ds and ds:V(I)) elseif VType == "X" then --DateTime Out = (T and T(I)) or (ds and ds:T(I)) elseif VType == "A" then --Any if ds then Out = ds[I] end end return Out end
Ну хорошо давайте, по порядку. OnCalculate(idx) это функция обратного вызова, специальная для создания индикаторов, все что она делает передает idx. Передавать ее некуда нельзя. Но можно вынести из нее алгоритм расчет в отдельную функцию PSAR(idx) и уже работать с ней. Вот для индикатора. function OnCalculate(idx) PSAR(idx) end Для работы с ней в main(), нужно подписаться на источник вот этот момент из моего примера.
local ds_D1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_D1) затем передаем, а здесь получаем свечи local dailyCandles = getCandles(ds_D1, 4) далее расчет индикатора local atr = calculateATR(ds_D1, 4)
Вместо расчета АТР поставьте расчет собственного по аналогии. Удачи.
Посмотрите это пример, он рабочий подставите свои данный и по выводите.
Код
-- Global settings
local CLASS_CODE = "SPBFUT" -- Код класса инструмента
local SEC_CODE = "CRM5" -- Код инструмента
local TRADE_ACCOUNT = "" -- Счет
local LOTS = 1 -- Количество лотов
-- Инициализация данных
local dailyTrend = "none"
local entryPrice = 0
local sl = 0
local tp = 0
-- Функция получения свечей
function getCandles(ds, count)
local candles = {}
local size = ds:Size()
--message( 'size = ' .. size)
for i = 0, count do
if size >= 1 then
candles[i] = {
high = ds:H(size - i) or 0,
low = ds:L(size - i) or 0,
open = ds:O(size - i) or 0,
close = ds:C(size - i) or 0
}
end
end
return candles
end
-- Расчет ATR
function calculateATR(ds, period)
local sumTR = 0
local size = ds:Size()
for i = 1, period do
local prevClose = ds:C(size - i + 1) or 0
local high = ds:H(size - i) or 0
local low = ds:L(size - i) or 0
local TR = math.max(
high - low,
math.abs(high - prevClose),
math.abs(low - prevClose)
)
sumTR = sumTR + TR
end
return sumTR / period
end
-- Функция определения тренда на D1
function getDailyTrend()
local ds_D1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_D1)
local dailyCandles = getCandles(ds_D1, 4)
local atr = calculateATR(ds_D1, 4)
local o0 = dailyCandles[0].open or ds_D1:O(ds_D1:Size()) or 0
--message('o0 = ' .. tostring(o0) .. '; dailyCandles[0].open = ' .. tostring(dailyCandles[0].open) )
local HH = math.max(
dailyCandles[1].high,
dailyCandles[2].high,
dailyCandles[3].high
)
local LL = math.min(
dailyCandles[1].low,
dailyCandles[2].low,
dailyCandles[3].low
)
local trend = "range"
if o0 > HH then trend = "uptrend"
elseif o0 < LL then trend = "downtrend"
else trend = "range"
end
local daily = {['trend'] = trend,
['hh'] = HH,
['ll'] = LL,
['o'] = o0,
['atr'] = atr,
['targetB'] = atr + o0,
['targetS'] = o0 - atr
}
return daily
end
-- Проверка структуры на H1
function checkH1Structure(trend)
local ds_H1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_H1)
local h1Candles = getCandles(ds_H1, 5)
local atr = calculateATR(ds_H1, 14)
local currentClose = ds_H1:C(ds_H1:Size()) or 0
if trend == "uptrend" then
return h1Candles[1].high > h1Candles[2].high and
h1Candles[2].low < h1Candles[3].low and
currentClose > h1Candles[1].high
elseif trend == "downtrend" then
return h1Candles[1].low < h1Candles[2].low and
h1Candles[2].high > h1Candles[3].high and
currentClose < h1Candles[1].low
end
return false
end
-- Поиск точки входа на M1
function checkM1Entry(trend)
local ds_M1 = CreateDataSource(CLASS_CODE, SEC_CODE, INTERVAL_M1)
local m1Candles = getCandles(ds_M1, 20)
local atr = calculateATR(ds_M1, 14)
local currentClose = ds_M1:C(ds_M1:Size()) or 0
if trend == "uptrend" then
if currentClose > m1Candles[0].high then
entryPrice = currentClose
sl = entryPrice - atr
tp = entryPrice + 2*atr
return true
end
elseif trend == "downtrend" then
if currentClose < m1Candles[0].low then
entryPrice = currentClose
sl = entryPrice + atr
tp = entryPrice - 2*atr
return true
end
end
return false
end
-- Отправка ордера
function placeOrder(direction)
local transaction = {
ACTION = "NEW_ORDER",
CLASSCODE = CLASS_CODE,
SECCODE = SEC_CODE,
ACCOUNT = TRADE_ACCOUNT,
OPERATION = direction == "uptrend" and "B" or "S",
PRICE = entryPrice,
QUANTITY = tostring(LOTS),
STOPPRICE = tostring(sl),
EXPIRY = "GTC"
}
local res = SendTransaction(transaction)
if res then
message("Order placed: "..direction..
" | Price: "..entryPrice..
" | SL: "..sl..
" | TP: "..tp)
else
message("Error placing order!")
end
end
local is_run
function OnInit()
--strategy = Strategy:new(config)
--strategy:start()
is_run = true
message('Стратегия 3ТФ инициализирована')
end
function OnStop()
--strategy:stop()
is_run = false
message('Стратегия 3ТФ остановлена')
end
function OnTransReply(r)
--strategy:handle_transaction_reply(r)
end
function OnTrade(t)
--strategy:handle_trade(t)
end
function OnOrder(o)
--strategy:handle_order(o)
end
-- Основной обработчик
function main()
message('Стратегия 3ТФ запущена')
local daily = getDailyTrend()
message( 'Стратегия 3ТФ dailyTrend = ' .. tostring(daily.trend)
..'; HH = '.. tostring(daily.hh)
..'; LL = '.. tostring(daily.ll)
..'; o0 = '.. tostring(daily.o)
..'; atr = '.. tostring(daily.atr)
..'; targetB = '.. tostring(daily.targetB)
..'; targetS = '.. tostring(daily.targetS)
)
daily.trend = "uptrend"
while is_run do
if daily.trend ~= "range" then
if checkH1Structure(daily.trend) then
if checkM1Entry(daily.trend) then
placeOrder(daily.trend)
end
end
end
sleep(1000)
end
end
Хотел на этом и завершить поднятую тему, совсем нет оппонента, возможно я не очень понятно излагаю или не интересно или еще чего ... Немного поразмыслив решил добавить, сказал "А", надо и "Б" произносить. Тема конечно огромная и не для этого форума, но постараюсь кратко, кому станет интересно и без меня разберется.
Из проективной геометрии известна следующая уникальная закономерность, характеризующая двойственные отношения между оригиналом и изображением. Это так называемое сложное отношение четырех чисел а, b, с, d. Свойства этого отношения очень хорошо и популярно описаны в книге У.У. Сойера «Прелюдия к математике" (М. "Просвещение", 1972). Сложное отношение (cross-ratio), оно инвариантно при проективных преобразованиях , при перестановке точек его значение меняется по определённым правилам. Такие перестановки образуют замкнутый цикл. Замкнутость цикла приводит к одному из 6 значений.
"На фига, козе баян?" Сложное отношение, сохраняющее инвариантность при проективных преобразованиях, может быть адаптировано для анализа финансовых данных. Выявление инвариантных паттернов, позволяет формализовать их геометрическую структуру, если четыре точки (экстремумы) образуют паттерн, их cross-ratio может служить универсальным дескриптором, инвариантным к масштабированию графика. Это помогает распознавать паттерны даже при изменении таймфрейма или волатильности. Если три точки (например, два минимума и один максимум) задают проективное преобразование, то четвертая точка (прогнозируемый уровень) вычисляется через инвариантное сложное отношение. Cross-ratio помогает анализировать гармонические паттерны (например, "Гартли", "Бабочка»), где соотношения между экстремумами следуют строгим пропорциям. Все это можно дополнять классическими методами технического анализа. Практические шаги для поиска паттерна: 1) Выделите экстремумы на графике. 2) Вычислите cross-ratio для всех комбинаций из 4 точек. 3) Сравните с эталонами (ABCD: CR ≈ 2.618, Cypher: CR ≈ 1.618, Bat: CR ≈ 0.886) 4) Фильтрация.
Но меня больше всего заинтересовало инвариантность перестановки, образуют замкнутый цикл. Но это другая тема -двойственные отношения между оригиналом и изображением!
Вот ссылка на индикатор, https://forum.quik.ru/messages/forum10/message78143/topic8506/#message78143, на что нужно обратить внимание, это в анонимной функции на передачу ds! ds = CreateDataSource, то есть мы передаем методы на которые подписаны, это делается именно для того, чтоб без извинений и переделок можно было индикатор использовать в алгоритмах, через наследование.
В классической экономике принцип двойственности (монады), рассматривается через отношения производителя и потребителя. Если произвести замену Производитель = Покупатель (ну в итоге производственный цикл заканчивается продажами товара), а Потребителя = Покупатель. Тогда задача прогнозирования рынка может быть представлена как решение системы дифференциальных уравнений, где начальные условия и алгоритм вычисления прогнозной траектории определяются фазами рынка (накопление, распределение, тренд растущий, тренд снижающийся).
Для этого можно использовать подход, где: Начальные условия — это текущие фазы состояния продавца и покупателя, которые задают начальные значения для динамических переменных (спрос, предложение и цена). Алгоритм вычисления прогноза — это система дифференциальных уравнений, которые описывают изменения спроса, предложения и цены на основе взаимодействия между продавцом и покупателем.
Математическая модель, будет описывать следующие взаимно дополнительные отношения. * Продавец влияет на рынок через предложение товара и спрос на деньги. * Покупатель влияет через предложение денег и спрос на товар. Изменение этих факторов можно выразить через дифференциальные уравнения. Учитывая тот факт что эти отношения подчинены Закону Спроса Предложения.
Важно, Цена, в этом подходе, определяется спросом и предложением, и является Мерой этих отношений!
В реальном времени решение этой системы уравнений с заданными начальными условиями позволяет прогнозировать динамику цен, тренды, а также возможные фазовые переходы в будущем. Этот подход не привязан, к таким входным параметрам, как период или длина скользящего окна. Удачи!
Задачу прогнозирования, можно свести к решению краевой задачуи Коши, для системы дифференциальных уравнений, с заданными начальными условиями. Возможность решить, такую задачу прогнозирования, заключается в определении: 1. начальных условий – фазы, 2. алгоритма вычисления прогноза - функция. Если известны начальные условия движения и алгоритм вычисления траектории, то мы можем вычислить (сделать) прогноз судьбы любой системы.
Trbot написал: ОТЦ, РД, Монада - да как хотите называйте всё это лишь бы профит был.
Для реализации профита, нужно другое согласен и это не только для алгоритмической . 1) Положительное мат. ожидание вашей торговой системы, на статистически значимом периоде. 2) Система должна показывать Профит фактор не ниже 2 и Процент прибыльных сделок более 40% 3) Для улучшение результатов торговой системы нужно адекватное управление позицией ММ. 4) А может и первое, контроль рисков, РМ. 5) Ну и конечно самодисциплина, в прочем алгоритмическая здесь сильно помогает. Вроде ничего не забыл, если ваша система отвечает этим требования вперёд!
Trbot написал: Профит есть от роботов? Я имею ввиду вообще практику применения роботов, практику алготрейдинга. Профит есть?
Профит от роботов у каждого свой, алготрейдинг - это прежде всего создание алгоритмов, кто что на ваял, то и получил. Я лишь рассуждаю о новых подходах, которые реализуемы в этих алгоритмах. И моментах торговой деятельности на бирже? Например, в своей практике, использую два уровня защиты, стоп - лосс на сделку (небольшой) , и процент проигрыша от капитала, он реализован у меня как индикатор на графике для каждого инструмента отдельно, я им иногда пренебрегаю, как Вы думаете связан алгоритм и профит. Моя практика говорит да.
Повторюсь трейдинг иллюзия заработка легких денег, это полноценная профессиональная деятельность крупных игроков Идеальная торговая стратегия: продал на верху, купил снизу. Алгоритмически это осциллятор, идеально синусоидальная волна (про которую я тут распинаюсь рассказывая) . Ее применение позволяет перейти в Фазово - частотную область, рассчитав период несущей волны и получив фазу, строим опережающий индикатор с помощью сдвига фаз. Я только что описал алгоритм, одного из подходов расчета опережающего индикатора, выше есть примеры. Для сравнения, если использовать алгоритм простой средней то лаг определяется в половину периода скользящего окна, то есть прошло половина периода пока получен сигнал на сделку. Вот и сами ответьте что лучше, получить опережающий или пропущенный на половину сигнал.
У этого подхода есть свой недостаток, для вычисления тригонометрических функций требуется указывать Период. Отсюда и родилась монадная тема. Вопрос можно поставить так, а можно ли описать алгоритмически фазовые переходы, без предварительного указания периода? Оказывается можно! Не возят цыгане в своих кибитках, вычислительные машины и библиотеки книг, все знания передаются устно.
"Сложность этого подхода - выше сложности высшей экономики. Он доступен для понимания и овладения лишь тем, кто имеет не только высокий интеллект, глубокие экономические знания, любознательность и трудолюбие, но и «души прекрасные порывы»."
Trbot написал: Проще говоря - важно наличие обратной возвращающей силы. При отклонении некой системы от положения равновесия возвращающая сила стремится вернуть её к положению равновесия
В своей "Общей теории цикла" (ОТЦ) Соколов Юрий Николаевич, такое взаимодействие называет "квант взаимодействия", мне же больше но нраву старинное название "Монада". Здесь нужно понимать что авторы на которых я ссылаюсь, говорят о единых законах миро воздания, а это значит, терминология принимаемая в физике или химии вполне себе допустима и в нашем предмете. Из теории систем известно, что любая система содержит в себе главное звено, которое нужно найти а затем, "потянув" за него можно "распутать" весь системный "клубок".
Решил человек заняться инвестициями, нужен капитал, приобретает актив, и у него остаются деньги. Мат. запись такой монады, К = А + Д. если это от нормировать, получим доступ к структурному анализу. Именно такие подходы я пытаюсь обсуждать, и применить при анализе и прогнозировании у себя. Еще один пример, вот Вы пишете:
Цитата
Trbot написал: Для механических колебаний важно наличие периодического преобразования энергии из кинетической в потенциальную.
По сути Вы говорите о фазовых переходах, посмотрите как это описывает в своей "Ритмодинамика" (РД) Иванов Юрий Николаевич. Вообще читая РД, не покидает чувство, что читаешь фантастический роман.
nikolz написал: Если nil элемент не таблица, то никакой памяти сборщик мусора не удаляет.
Ну как nil элемент, может быть таблица? Именно для запуска сборщика мусора и устанавливаем nil. А способ продемонстрируйте кодом, тогда можно, что то обсуждать, а так одна философия.
Цитата
nikolz написал: Без обид, но не стоит нести в массы отсебятину и чушь. --------------Все это можно найти в интернете.-----------------Если хотите просвещать, то дайте просто ссылку, а не пытайтесь своими словами пересказывать то, в чем сами не разбираетесь.
"Предлагаемый подход в ВУЗах не преподаётся и не изучается, так как он - тайный, хотя бы потому что не имеет учебника". Сылка на авторов работ на которые я опираюсь в своих рассуждениях я даю.
Trbot, Формирование цен отражает результат взаимодействия множества факторов, спрос / предложение, психология (страх / жадность), события экономического характера (процентные ставки, инфляция ...). Отображение цен на графике в виде бара, это отображение на плоскости. Колебания цен в записи бар — это процесс, при котором цена может двигаться вверх и вниз, создавая амплитуду колебания, а также периодичность в изменениях. Это легко проверить, кто бы что не писал, возьмем бар на интервале H1, и заполним его барами с формированными на М1, на том же самом интервале (к слову, это свойство называют фрактальностью) Колебания можно рассматривать как волновой процесс? Термин "волновой процесс", используется в техническом анализе как метафора, а не в физическом смысле (распространение колебаний в среде). Волны Эллиотта — модель, где цена движется в виде импульсных и коррекционных волн. Тренды и коррекции — их можно также условно можно назвать "волнами".
В терминале от Сбер весит сообщение, надеюсь глюки связаны с этим: "С 11 по 23 марта планируется техническое обновление QUIK.Это необходимо для дальнейшей корректной работы терминала". А версию предпочитаю ту которую брокер рекомендует, как наиболее адаптированную к серверу. Вообще работали последнее время стабильно.
nikolz, Сбер "глючит" второй день! Вчера просто без предупреждений отключали от сервера, сегодня не соединяют, от поддержки огромный ноль или даже нил. Так и хочется сменить лексику на не цензурную
Не стоит питать иллюзий: рынок — это не место для легких денег! --------------------------------------------------------------------------------------------- Позволю себе немного по философствовать и высказать свое видение на инвестиции, но это только ради пользы общего дела. Те кто сталкивался с финансовыми управляющими - аналитиками, знает что первым вопросом от них будет: "на какой временной горизонт планируете разместиться?" И это не праздный вопрос, не много в суть него нас окунул TWG. Но я хочу начать рассуждать на эти вопросы с основ.
1) Открывая график в терминале, мы видим отражение цены во времени (массив), и это колебательный процесс, что в свою очередь равносильно волновой процесс. Волновой процесс можно описать с помощь фазово - частотной характеристики.
2) Хаос и порядок * Порядок — это система, где закономерности наблюдаемы и предсказуемы. * Хаос — это не отсутствие порядка, а сложная система, которая кажется случайной из-за своей непредсказуемости. Однако в хаосе часто скрыты глубокие закономерности.
На финансовых рынках цены могут казаться хаотичными, но они подчиняются законам спроса и предложения, психологии толпы и макроэкономическим факторам. Изучая такую систему, пытаемся найти скрытые закономерности, анализируя графики, индикаторы и фундаментальные факторы. Даже в хаосе можно создать порядок, установив правила и рамки, торговая система с четкими правилами входа и выхода помогает избежать эмоциональных решений. Хаотичные системы часто меняются, поэтому важно быть гибким и готовым к изменениям (адаптироваться). Теория хаоса изучает, как малые изменения в начальных условиях могут привести к "эффект бабочки" (drastically different outcomes).
Философский взгляд, напоминает идеи стоицизма и даосизма: * Стоицизм: Принимайте то, что не можете изменить, и сосредоточьтесь на том, что можете контролировать. * Даосизм: Хаос и порядок — это две стороны одной медали (Инь и Ян). Они взаимосвязаны и дополняют друг друга. Хорошо, с практической стороны, разобраны в работе М.И. Беляева "Милогия".
Хаос — это не враг, а вызов. С ним также можно работать, если искать закономерности, создавать структуру и адаптироваться к изменениям. Если чувствовать баланс, найти тот самый ритм, вот и хаос обуздан.
* Баланс, на мой взгляд лучшее его описание - это бух. учет, нет не правила учета, а сама структура и построение этого учета, способного восстанавливать всю цепочку бинарных записей. Ну и конечно бинарность хорошо известна в программировании. * С РИТМОМ все значительно сложней, ритмом занимается - ритмодинамика. Волновая геометрия является базисом ритмодинамики. Основные постулаты РД совпадают с началами волновой геометрии. Волновая геометрия, как инструмент, предоставляет возможность моделировать процессы самоорганизации простых и сложных систем без каких-либо специфических расчётов сил взаимодействия. В основе моделирования лежит оценка состояния среды вокруг исследуемого осциллятора с последующим перемещением этого осциллятора в сторону области равновесия состояний. Состояние среды описывается через амплитуду, фазу и частоту волн. Вот мы и вернулись к математике, амплитуде, фазе и частоте волновых колебаний, балансу, ритму и ни какой философии. То есть можно писать алгоритм моделирования, и прогнозов, как это делается с помощь книги перемен или карт "Торо". И не каких чудес, практически одна математика - царица наук.
Предложенный подход paluke, t[I-3] = nil (в место limit_table_size), разложений по полочкам Nikolay,
Если просто обнулять элементы таблицы, например, t[I-3] = nil, это приведет к тому, что в таблице появятся "дыры" (nil-значения). Да, не требуется сдвигать элементы, что может быть быстрее для больших таблиц. Но при этом таблица будет содержать "дыры", что может привести к ошибкам при использовании функций, ожидающих последовательности. "В Lua таблицы с nil-значениями могут вести себя неожиданно, особенно при использовании функций, которые работают с последовательностями (например, #t, table.concat, ipairs). Память не освобождается сразу, так как в этом варианте Lua использует сборщик мусора для удаления nil-элементов. Это может привести к увеличению потребления памяти".
Из выше всего сказанного, делаем выводы. 1) limit_table_size подходит для небольших размеров таблиц 2) Подход таблица содержащая "дыры", подходит для конечных вычислений, не требующий передачи таблиц дальше для использования, как это показал нам Nikolay. 3) В подходе с выводом таблиц и функции, как это предложилNikolay, на мой не профессиональный взгляд, лучше использовать альтернативный метод как это предлагают разработчики, использовать кольцевой буфер (circular buffer). В этом случае таблица имеет фиксированный размер, и новые элементы записываются поверх старых. Вариант, избежать использования limit_table_size, но при этом не хотите сталкиваться с проблемами nil-значений, в случае дальнейшего использования таблиц. Это наиболее эффективный способ управления памятью для задач, где требуется хранить только последние N элементов. И чтоб не быть голословным вот пример.
Код
local function circular_buffer(tbl, max_size, index, value)
local pos = (index - 1) % max_size + 1
tbl[pos] = value
return tbl[pos]
end
return function(I, FSettings, ds)
local I = I or 1
local ds = ds or nil
local FSettings = FSettings or {}
local P = FSettings.period or 9
local v_t = FSettings.v_t or 'C'
-- Текущая цена
local p0 = Value(I, v_t, ds) or 0
-- Инициализация на первом баре
if I == 1 then
Ema, iFich, Cu, Cd = {}, {}, {}, {}
end
-- Используем кольцевой буфер
local ema1 = circular_buffer(Ema, P * 2, I - 1, p0)
local ema0 = p0 * k + (1 - k) * ema1
circular_buffer(Ema, P * 2, I, ema0)
-- Остальная логика
...
end
Утро начал в борьбе с квик, квик победил. Пришлось переставлять, устранил одну из проблем, но видимо есть еще, зато с с моего скрипта снято подозрение. Вариант
Цитата
Nikolay написал: function Cached.Roofing_Filter(FSettings, ds)
-- Параметры local ds = ds or nil local FSettings = FSettings or {} local v_t = FSettings.v_t or 'C' local P = FSettings.period or 48 local N = FSettings.N or 10 local x = FSettings.x or nil
-- Локальные таблицы для хранения данных между вызовами local Price, HP, SSF, Lead = {}, {}, {}, {} local alpha1, a1, b1, c2, c3, c1 = 0, 0, 0, 0, 0, 0 local I1 = 0 -- Индекс предыдущего бара
-- Функция для ограничения размера таблицы local function limit_table_size(tbl, max_size) while #tbl > max_size do table.remove(tbl, 1) end end
return function(I) -- Текущая цена local p0 = x or Value(I, v_t, ds) or 0
-- Проверка смены бара local newbar = I > I1
не совсем подходит для реализации в индикаторе, все таки перестает работать таблица Settings в анонимной функции, видимо на то она и анонимна. Но подход взял на вооружение для алгоритмов.
Цитата
Nikolay написал: Если речь про индикатор, то необходимо использовать метод OnChangeSettings и реинициализировать метод расчёта.
Показалось совсем не нужно или не понял как ею пользоваться?
Возник новая проблема:
Цитата
VPM написал: Конфликт имен при работе с DDE-сервером и одновременном использовании нескольких терминалов QUIK. DDE — один из старейших протоколов, и его использование может быть нестабильным. Возможность использования более продвинутых методов интеграции, например таких как: Экспорт данных в файлы (CSV, TXT) средствами Lua, с последующей загрузкой в Excel или Блокнот. На тыкается на проблему, чтения самой таблицы "состояние счета", или я опять что то пропустил?
неужели кроме как вывода таблицы состояния счета, нет других возможностей ее получения или ее параметров?
Конфликт имен при работе с DDE-сервером и одновременном использовании нескольких терминалов QUIK. DDE — один из старейших протоколов, и его использование может быть нестабильным. Возможность использования более продвинутых методов интеграции, например таких как: Экспорт данных в файлы (CSV, TXT) средствами Lua, с последующей загрузкой в Excel или Блокнот. На тыкается на проблему, чтения самой таблицы "состояние счета", или я опять что то пропустил?
VPM написал: Добрый день,"Ни когда не было и вот опять!". Все утро пытаюсь загрузить квик версия 11.4.1.3. Вернее не так сам квик грузится, но при входе по логину, часами зависает на "чтении информации об окнах", качает себе гигабайты и крутит колесико? Увлекательное зрелище! Проверил скорость интернета, сбросил лог., сбросил квик несколько раз для загрузки предыдущих wnd, не помогло. Позвонил брокеру, "Сервера работают нормально, пере закажите данные". НЕ помогло?
Кажется причина нашлась. Это конфликт имен, при работе с DDE-сервером и одновременном использовании нескольких терминалов QUIK. Во время одновременного запуска, двух разных терминалов и выводе ими информации через DDE-сервер в одну книгу Excel.
-- Возвращаемые значения
return Lead[I] or 0, SSF[I] or 0
end, Lead, SSF
end
local fAlgo, Lead, SSF = Cached.Roofing_Filter(FSettings, ds)
1) return Lead[I] or 0, SSF[I] or 0 можно использовать в индикаторах 2) end, Lead, SSF возвращает сам алгоритм и таблицы полностью, можно допустим выгружать в электронные таблицы и там обрабатывать и анализировать. Супер! Надо проверить будет ли этот подход в режиме индикатора пересчитывать если изменять, допустим период или другие задания?
"В Lua таблицы представляют собой ассоциативные массивы, которые могут хранить значения различных типов. Каждый элемент таблицы в Lua может быть представлен структурой TValue, которая содержит два основных поля:
Value value_ — это поле, которое хранит значение элемента. В зависимости от типа, это может быть число, строка, указатель на другую структуру и т.д.
int tt_ — это поле, которое хранит тип значения (например, LUA_TNIL, LUA_TNUMBER, LUA_TSTRING и т.д.).
Когда вы выполняете операцию t[i-1] = nil, это означает, что вы удаляете элемент из таблицы по индексу i-1. Внутри Lua это приводит к тому, что значение элемента устанавливается в nil, а тип (tt_) устанавливается в LUA_TNIL (который обычно соответствует значению 0).
Таким образом, операция t[i-1] = nil эквивалентна следующему:
Установка value_ в какое-то "пустое" значение (в случае nil это может быть просто 0 или NULL).
Установка tt_ в 0 (что соответствует типу LUA_TNIL).
Это означает, что элемент таблицы больше не содержит полезного значения и считается "удаленным" или "пустым"."
Nikolay написал:
Также я предпочитая возвращать инициализированный метод расчёта и таблицы, хранящие данные (в данном случае это Lead и SSF). Их необходимо иницализировать один раз и тогда всегда будет под рукой ссылка на весь массив данных, а нее только возвращаемые последние.Для примера:local fCalc, Lead, SSF = Cached.Roofing_Filter(FSettings, ds)И тогда расчёт выглядит элементарно:fCalc(index)А использование данных:Lead[index], Lead[index-2] и т.д. Ссылка же неизменная, а значит нет необходимости получать из метода расчёта что-то ещё, засоряя память.
Если не сложно, покажите на примере кода выше, Вашу реализацию фильтра. Как должно выглядеть?
Nikolay написал: Если речь про индикатор, то необходимо использовать метод OnChangeSettings и реинициализировать метод расчёта.
Даже не заметил когда метод добавили. Попробую Ваши рекомендации и этот метод.
Цитата
Nikolay написал: Метод table.remove не самый быстрый - очень не быстрый. Хотя, наверно, в рамках Квик это не столь критично, тем более, что расчёт раз в бар.
Метод table.remove добавил для простоты кода, да и что он делает, двигает 3 бара, в рабочем варианте, моя любимая двух факторная очередь, не плохо зарекомендовала себя.
Цитата
Nikolay написал: Я предпочитаю просто очищать данные в таблицах, сборщик мусора освободит память.
Вы имеете в виду такой подход Table[I] = x if I > I - 3 then Table = nil end
Nikolay, Вот сам вызов, я в принципе всегда так делаю. Settings={} Settings.Name = "1Roofing_Filter" Settings.v_t = "O" Settings.period = 48 Settings.N = 10 --Settings.avto = 0 -- 1 adapt
local f function Init() local cached=dofile("C:\\cached.lua") f = cached.Roofing_Filter() cached=nil Settings.line = { {Name = "lead", Color = RGB(0, 0, 0), Type = TYPE_LINE, Width = 1}, {Name = "Roofing_Filter",Color = RGB(255, 0, 0), Type = TYPE_LINE, Width = 1},
} return #Settings.line end
function OnCalculate(index) return f(index, Settings) end То есть с начало нужно инициализировать, а затем возвращаю замыкание. Если же Settings перенести Roofing_Filter(Settings), то перестает работать Settings.period когда индикатор на графике?
function Cached.Roofing_Filter()
-- Локальные таблицы для хранения данных между вызовами
local Price, HP, SSF, Lead = {}, {}, {}, {}
local alpha1, a1, b1, c2, c3, c1 = 0, 0, 0, 0, 0, 0
local I1 = 0 -- Индекс предыдущего бара
-- Функция для ограничения размера таблицы
local function limit_table_size(tbl, max_size)
while #tbl > max_size do
table.remove(tbl, 1)
end
end
return function(I, FSettings, ds)
-- Параметры
local I = I or 1
local ds = ds or nil
local FSettings = FSettings or {}
local v_t = FSettings.v_t or 'C'
local P = FSettings.period or 48
local N = FSettings.N or 10
local x = FSettings.x or nil
-- Текущая цена
local p0 = x or Value(I, v_t, ds) or 0
-- Проверка смены бара
local newbar = I > I1
if newbar then
-- Обновление индекса бара
I1 = I
-- Инициализация на первом баре
if I == 1 then
Price, HP, SSF, Lead = {}, {}, {}, {}
Price[I], HP[I], SSF[I], Lead[I] = p0, 0, 0, 0
local fi = (0.707 * 2 * math.pi / P)
alpha1 = (math.cos(fi) + math.sin(fi) - 1) / math.cos(fi)
a1 = math.exp(-1.41421356 * math.pi / N)
b1 = 2 * a1 * math.cos(1.41421356 * math.pi / N)
c2, c3, c1 = b1, -a1 * a1, 1 - c2 - c3
else
-- Обновление цены
Price[I] = p0
-- Разница цен для выделения высокочастотных компонентов
local p1 = Price[I - 1] or p0
local p2 = Price[I - 2] or p1
local noise = p0 - 2 * p1 + p2
-- Расчет HP-фильтра
local hp1 = HP[I - 1] or 0
local hp2 = HP[I - 2] or hp1
local hp = (1 - alpha1 / 2) * (1 - alpha1 / 2) * noise + 2 * (1 - alpha1) * hp1 - (1 - alpha1) * (1 - alpha1) * hp2
HP[I] = hp
-- Расчет SuperSmoother
local ssf1 = SSF[I - 1] or 0
local ssf2 = SSF[I - 2] or ssf1
local ssf = c1 * (hp + hp1) * 0.5 + c2 * ssf1 + c3 * ssf2
SSF[I] = ssf
-- Расчет опережающего сигнала (Lead)
local lead1 = Lead[I - 1] or 0
local lead = 2 * ssf - 1 * ssf2
Lead[I] = lead
end
-- Ограничение размера таблиц
limit_table_size(Price, 3) -- Храним только последние 3 бара
limit_table_size(HP, 3)
limit_table_size(SSF, 3)
limit_table_size(Lead, 3)
end
-- Возвращаемые значения
return Lead[I] or 0, SSF[I] or 0
end
end
Это реализация Roofing Filter, который состоит из двух основных компонентов:
HP Filter (High-Pass Filter): Настроен на цикл 48 баров, чтобы ослабить более длительные периоды.
SuperSmoother Filter: Настроен на цикл 10 баров, чтобы ослабить более короткие периоды.
Этот фильтр используется для выделения желаемых частотных компонентов из ценовых данных, что полезно для анализа циклов и можно использовать для генерации торговых сигналов.
Что не так с ним, в торговой стратегии подобных фильтраций несколько, особенностью QUIK - индикатор вызывается в функции обратного вызова, которая может вызываться несколько раз в рамках одного бара, при поступлении новых тиков. Если таблицы Price, HP, SSF, Lead инициализировать внутри возвращаемой функции, они будут сбрасываться при каждом вызове, что приведет к потере данных. Для корректной работы индикатора в QUIK нужно сохранять состояние между вызовами. Это можно сделать, используя локальные таблицы вне возвращаемой функции, но при этом ограничивать их размер, чтобы избежать утечек памяти.
Для тех кто торговал сегодня Si, я на нем проводил тесты, делаем ставки, про тестировали уровень сопротивления, собрали ликвидность вернемся в зону 86700 - 86800, и все до свидание налоги, куда кривая вынесет!
Trbot, Вы правы, мой подход тоже такой, нашел интересное встрял, если с ходу не получилось разобраться, вход идут "молоток и отвёртка", остались лишние запасные части "капиталисты перемудрили" - все ведь работает, ну а если не работает берем в руки инструкции и буквари. Касаемо, обсуждения, по мне так Вы перемудрили, не наверно подобная стратегия возможна, где ни будь на мало ликвидном рынке, но даже для этого, чтоб ее реализовать 1. нужны приличные средства; 2. команда амбициозных единомышленников из разных сфер; 3. инсайд. Возможно кто из маркетмейкеров и реализует, подобное но это очень сложно. У меня все гораздо проще, целый день тестирую одну стратегию, не идет ни как, "пялиться в экран занятие грустное, вот и пишу всякую чушь".
Igor_User написал: А что такое debug в QLua? В справке такого нет. Где можно почитать об этом?
Читать нужно сам язык луа не ниже версии 5.4 - это его таблица, QLua - это библиотека от разработчиков для возможности доступа и взаимодействия срипта с рабочим местом квик.
TGB, Я лишь уточняю показатель, не массовость а объёмы, которые будут участвовать в этих стратегиях, а для этого нужен маркетинг и реклама. Ну и что что допустим 1000 трейдеров будет торговать 1 контрактом? Из того что здесь я написал 10 пользователей прочитает а 1 - 2, попробуют.