Решил «спалить грааль». Опишу тестирование торговой системы, которую можно использовать для демо-трейдинга, например, транслируя сигналы в мессенджерах и повышая свой авторитет как опытного трейдера среди аудитории. Риски использования лежат только на вас самих!
Система эксплуатирует нестационарность рынка, используя для входов и выходов моменты с повышенной волатильностью. Моменты входа и выхода зависят от одного явного параметра lookback и одного неявного greed. Торговля ведётся в лонг и шорт, может применяться на любых таймфреймах, но лучше на мелких. Подходит любой достаточно волатильный и ликвидный инструмент. Я буду демонстрировать результаты на фьючерсе на акции «Сбера» SR.

Период для тестирования выбран с начала 2015 года по конец февраля 2023 года. Торговля идёт фиксированной суммой на весь капитал по номиналу. Комиссия и проскальзывание установлены на уровне 0,03%. Склейка фьючерсов не используется, в конце дня, предшествующего дню экспирации, позиции закрываются и на следующий день открываются уже в новом фьючерсе. Таймфрейм 5 минут, чтобы было удобно оперативно транслировать сигналы через интернет.

На рынке имеются различные группы участников, каждая из которых ведёт свою игру. Сфокусируемся на одной из них, достаточно многочисленной или обладающей достаточным капиталом, чтобы влиять на цену. Мы хотим увидеть закономерности в действиях этой группы и как-то начать эксплуатировать их в свою пользу.
В следующем ниже тексте я хочу с помощью аналогий и мысленного эксперимента показать, что это трудная задача, и пояснить, почему.
--
-- Выполнение действий с массивами.
--
local pairs = pairs
local type = type
module(...)
--- Создать копию массива (таблицы)
-- @return копию массива (таблицы)
function copy(array)
local copy_array = {}
if type(array) ~= "table" then
return array
end
for k, v in pairs(array) do
if type(v) == "table" then
copy_array[k] = copy(v)
else
copy_array[k] = v
end
end
return copy_array
end
--- Узнать, начинается ли индексация в массиве с нуля или с единицы.
-- @return 0 или 1
function base(array)
if array[0] ~= nil then
return 0
else
return 1
end
end
--- Вычислить число элементов в массиве.
-- @return число элементов в массиве
function size(array)
local n = 0
for _, _ in pairs(array) do
n = n + 1
end
return n
end
--- Проверить пустой или нет массив.
-- @return true/false
function isEmpty(array)
for _, _ in pairs(array) do
return false
end
return true
end
--- Получить первый индекс массива, где ничего не записано. Поиск начинается с 1.
-- @return первый индекс массива, где ничего не записано
function firstEmptyIndex(array)
local i = 1
while array[i] ~= nil do
i = i + 1
end
return i
end