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

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

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

Правила управления объемом позиции. Объем позиции будет изменяться в зависимости от состояния условного торгового счета. Объем позиции будет увеличиваться при увеличении торгового счета и уменьшатся при уменьшении его.

Для нашей торговой системы будем использовать исторические данные цен фьючерса на нефть марки Brent за три месяца.

Рассмотрим подробнее работу с объемом позиции. Первоначальный размер торгового счета будет равняться 100000 руб. на каждые 10000 руб. будет приходиться один фьючерсный контракт. Первоначальный объем позиции будет составлять: 100000/10000 = 10, т.е. 10 контрактов. Если торговый счет увеличится и будет равняться 110000 руб. то объем позиции будет равен 11 контрактов. Если торговый счет будет больше 110000 руб. но меньше 120000 руб. то объем позиции останется равен 11 контрактов и только после того как размер торгового счета станет равен или более 120000 руб. тогда мы увеличим объем до 12 контрактов. Суть в следующем, при расчете объема позиции мы отбрасываем дробную часть. Точно таким же образом считается объем позиции при уменьшении торгового счета, например, если счет станет равным 92000 руб. тогда 92000/10000 = 9,2 отбросив дробную часть числа, получим 9 контрактов.

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

Приступим. Для начала нам необходимы исторические данные, на которых мы будем тестировать систему. Исторические данные фьючерса на нефть марки Brent мы будем брать с сайта компании “Финам” www.finam.ru. Уточню, мы будем использовать фьючерсы, торгуемые на “Московской бирже” на Срочном рынке “ФОРТС”. Обратите внимание фьючерсы на нефть марки Brent экспирируются ежемесячно.

В этом примере будут использоваться следующие исторические данные:

— BR-8.17(BRQ7) с 01.07.2017 по 31.07.2017
— BR-9.17(BRU7) с 01.08.2017 по 31.08.2017
— BR-10.17(BRV7) с 01.09.2017 по 30.09.2017

Перейдя по ссылке ниже, Вы попадаете на сайт компании “Финам” в раздел “Экспорт котировок”.

https://www.finam.ru/profile/mosbirzha-fyuchersy/br-8-17-brq7/export/?market=17&em=465382&code=BRQ7&apply=0&df=1&mf=8&yf=2017&from=01.09.2017&dt=30&mt=8&yt=2017&to=30.09.2017&p=2&f=BRQ7_170901_170930&e=.txt&cn=BRQ7&dtf=1&tmf=1&MSOR=0&mstime=on&mstimever=1&sep=1&sep2=1&datf=5

В экспорте котировок на сайте “Финам” много котировок разных финансовых инструментов. Необходимо найти нужный инструмент и настроить наиболее подходящий формат файла. Ниже представлен скриншот экрана с настройками экспорта.

Скачайте исторические данные с сайта «Финам«. Если Вы получили коды скриптов с этого сайта, то файлы с историческими данными находятся в папке со скриптами под именами BR1.txt, BR2.txt, BR3.txt. Получить коды скриптов и исторические данные.

И так, данные есть. Теперь необходимо преобразовать формат записи данных в скаченных файлах, для того чтобы язык Lua смог прочитать файл. Как преобразовывать файлы в читаемый формат для языка Lua мы рассматривали в разделе “11. Запись и чтение файла”. Формат файла с историческими данными должен иметь следующий вид.

Столбец 1 – Дата;
Столбец 2 – Время;
Столбец 3 – Цена открытия свечи;
Столбец 4 – Цена максимума свечи;
Столбец 5 – Цена минимума свечи;
Столбец 6 – Цена закрытия свечи;
Столбец 7 – Номер файла по порядку.

С первыми шестью столбцами вопросов быть не должно, а вот столбец 7 рассмотрим чуть подробнее. Первый по порядку файл это BR-8.17(BRQ7) с 01.08.2017 по 31.08.2017 второй соответственно BR-9.17(BRU7) с 01.09.2017 по 30.09.2017 и третий BR-10.17(BRV7) с 01.10.2017 по 31.10.2017. В первом файле столбец 7 будет иметь цифру 1 на протяжении всех строк, второй будет иметь цифру 2 и третий 3. Этот столбец 7 нам необходим для закрытия позиции в последнюю минуту торгов фьючерса. Файлы должны выглядеть следующим образом.

Файлы сохраним под именами BR1, BR2, BR3 соответственно. Такие имена необходимы для использования в скрипте. В скрипте мы пропишем цикл, который будет последовательно открывать файлы. При первой итерации скрипт откроет BR1 при второй итерации BR2 и при третьей BR3. Такой принцип именования файлов предоставляет возможность открывать большое количество файлов, используя лишь несколько строк кода.

Данные, на которых будет производиться тестирование торговой системы, готовы. Теперь мы можем приступить к написанию скрипта. Создадим новый скрипт с именем «018 Тестирование на исторических данных.lua».

Первым делом создадим таблицы Lua в которые будут записаны данные из файлов. Количество таблиц будет равняться количеству столбцов в файлах с данными. В нашем случае семь штук.

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

Далее создадим переменные, с помощью которых мы будем управлять открытием файлов с данными и переменную с помощью, которой будем перебирать строки в таблицах с данными.

Переменная count_file это счетчик прочитанных файлов. После чтения каждого файла переменная увеличится на единицу.

Name_file, переменная содержащая не полное имя файла с историческими данными. Полное имя файла будет состоять из конкатенации (склейки) переменной Name_file и переменной count_file. Name_file..count_file Получим имя файла BR1, следовательно после прочтения первого файла счетчик count_file увеличится на единицу и будет открыт следующий файл с именем BR2 и так далее.

i – переменная содержащая индекс строки для таблиц Lua в которые будут записаны исторические данные из файлов. Первоначальное значение переменной единица, следовательно, запись в таблицы будет производиться с первой строки.

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

Далее будем использовать уже знакомый нам код чтения из файла, его мы рассматривали в разделе «11. Запись и чтение файла.«.

Кратко пройдемся по строкам. Создаем логическую переменную «x» и присваиваем ей значение «истина», далее создаем цикл, который исполняется до того момента пока переменная «x» не изменит свое значение на «ложь». Переменная «x» примет значение «ложь» лишь в том случае, когда в открытом файле кончатся строки для чтения. В строке кода 16 мы считываем, построчно, дынные из открытого файла и записываем их в соответствующие переменные. Условие, в строке кода 17, проверяет, не закончились ли дынные в файле, если все строки прочитаны, то переменная «Day» будет пустой, тогда цикл считывания файла прерывается. Иначе в соответствующую таблицу записывается значение из файла. В строке кода 26 переменная «i» увеличивается на единицу для перехода к следующим строкам таблиц.

После того так цикл while x == true do разорвался скрипт переходит на строку кода 29 в которой переменная count_file увеличивается на единицу для перехода к следующему файлу. Далее скрипт переходит на строку кода 11 скрипт проверяет условие в цикле while count_file <= 3 do и если условие верно, то открывается следующий файл для считывания.

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

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

Ниже мы создадим универсальную функцию, в которой будет производиться расчет результата сделок и расчет объема позиции. Создадим функцию с именем TradeResult, которая принимает на вход следующие параметры:
— PriceEn – цена входа в позицию;
— PriceEx – цена выхода из позиции;
— SaidTrade – направление сделки, длинная позиция «L» (long), короткая позиция «S» (short);
— Depo – количество денег на торговом счете;
— GO – гарантийное обеспечение;
— Step – шаг цены;
— Price_Step – стоимость шага цены;
— PunctPlus – количество пунктов в плюс;
— PunctMinus – количество пунктов в минус;
— TradePlus – количество сделок в плюс;
— TradeMinus – количество сделок в минус;
— MoneyTradePlus – количество денег в плюс;
— MoneyTradeMinus – количество денег в минус.

В теле функции создадим три переменные. Первая с именем TradePunct – это переменная, в которую будет записан результат сделки в пунктах. Вторая с именем TradeMoney в это переменную запишем результат сделки в денежном выражении. Третья с именем Kont в ней будет содержаться количество контрактов в текущей сделке.

Далее пропишем условие, которое проверяет направление сделки, длинная позиция или короткая. В зависимости от направления сделки будет различаться расчет результата сделки в пунктах. В нашу функцию передается переменная SaidTrade, в которой указывается направление сделки. Условие будет следующим.

Если переменная SaidTrade равна «L» то для получения результата сделки в пунктах мы вычитаем из цены выхода цену входа в позицию. Например, цена входа 100 пунктов цена выхода 105 пунктов, результат сделки 105 – 100 = 5 пунктов, положительное значение, следовательно, сделка была прибыльной.

Иначе, т.е. если переменная НЕ равна «L», поскольку переменная SaidTrade может принимать лишь два значения «L», и «S», то не равно «L» означает, что SaidTrade равно «S», следовательно позиция короткая. Для получения результата сделки в пунктах мы вычитаем из цены входа цену выхода. Например, цена входа 105 цена выхода 100. Результат сделки 105 – 100 = 5 пунктов, значение положительное, следовательно, сделка была прибыльной. Хорошо, результат сделки у нас есть далее нам нужно рассчитать количество контрактов в сделке, для количества контрактов у нас есть переменная Kont.

В строке кода 41 вычисляется количество контрактов доступное при текущем объеме торгового счета.
В строке кода 42 в переменной Kont отбрасывается дробная часть числа, количество контрактов может быть только целым числом. Отмечу, именно отбрасывается дробная часть, например, в строке кода 41 получилось 7,9 контракта, после строки кода 42 переменная Kont будет содержать значение 7 контрактов.

Теперь мы можем рассчитать результат сделки в денежном выражении, у нас есть результат сделки в пунктах и количество контрактов в сделке. Запишем строку кода.

Разберем подробно строку кода 43.
Разные фьючерсные контракты имеют разный шаг цены и разную стоимость шага цены. В качестве примера возьмем фьючерсный контракт на нефть марки Brent. На момент написания раздела, шаг цены, фьючерса на нефть марки Brent, равняется 0.01 пункта – переменная Step. Стоимость шага цены, равняется 5,75867 рубля – переменная Price_Step. Рассмотрим гипотетическую сделку. Цена входа в длинную позицию роняется 66,10 пункта, цена выхода из позиции равняется 66,50 пунктов. Результат сделки в пунктах равен 66,50 – 66,10 = 0,40 пункта – переменная TradePunct. Предположим количество контрактов равно 10 – переменная Kont. И так, переменные равны следующим значениям:
Kont = 10;
TradePunct = 0,40;
Step = 0.01;
Price_Step = 5,75867.

Рассчитаем результат сделки.

TradeMoney = 10 * ((0,40/0,01) * 5,75867) = 10 * (40 * 5,75867) = 10 * 230,3468 = 2303,46 руб.

Это универсальный расчет, подходит под любые значения шага цены и стоимости шага цены.

Теперь у нас есть результат сделки в пунктах и денежном выражении. Далее запишем код, который будет записывать результат сделки в переменные хранящие статистические данные наших сделок. Первым делом запишем условие определяющее, была сделка прибыльной или убыточное. Если переменная TradePunct больше нуля то сделка считается прибыльной и мы вносим изменения в переменные, которые содержат статистические данные для прибыльных сделок иначе, т.е. если TradePunct меньше или равна нулю записываем данные в переменные, которые содержат статистические данные для убыточных сделок.

Если сделка прибыльная.
Строка кода 45, переменная содержащая количество прибыльных сделок увеличивается на единицу.
Строка кода 46, в переменную, содержащую суммарное количество прибыли в пунктах, прибавляется текущая прибыль в пунктах.
Строка кода 47, в переменную, содержащую суммарное количество прибыли в денежном выражении, прибавляется текущая прибыль в денежном выражении.Если сделка убыточная.
Строка кода 49, переменная содержащая количество убыточных сделок увеличивается на единицу.
Строка кода 50, в переменную, содержащую суммарное количество убытка в пунктах, прибавляется текущий убыток в пунктах, переменная имеет отрицательное значение.
Строка кода 51, в переменную, содержащую суммарное количество убытка в денежном выражении, прибавляется текущий убыток в денежном выражении, переменная имеет отрицательное значение.

Далее скорректируем значение торгового счета на величину прибыли\убытка в текущей сделке и вернем результат работы функции.

Функция учета результатов сделок готова.

Выше мы прописали вспомогательные функции для тестирования на исторических данных. Далее перейдем к основному алгоритму.

Мы будем создавать алгоритм тестирования с возможностью оптимизации параметров. Смысл его в следующем.

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

И так, оптимизация. Под оптимизацией понимается подбор параметров наилучшим образом подходящих под текущие условия. В нашей системе есть два параметра это периоды расчета скользящих средних. Для нашего скрипта мы установим диапазон значений периода быстрой скользящей средней равный от 100 до 500 и диапазон значений для медленной скользящей средней равный от 600 до 900. Также нам понадобится шаг изменения для периодов средних, установим его равным 50.

Разберем подробнее, как это будет работать. Первым делом наш скрипт установит диапазоны 100 для быстрой и 600 для медленной средней, за тем скрипт пройдет по всем историческим данным рассчитает все сделки, которые могли быть с данными параметрами, и выдаст результат.

Следующим шагом, скрипт, увеличит значения периода быстрой средней на один шаг периода, который равен 50. Диапазоны средних будут равны 150 для быстрой и 600 для медленной, за тем скрипт снова пройдет по всем историческим данным и рассчитает все сделки, которые могли быть с данными параметрами, в конце выдаст результат.

Далее скрипт снова увеличит период быстрой средней на один шаг периода, периоды станут равны 200 для быстрой и 600 для медленной средней. Так будет продолжаться до тех пор, пока период быстрой средней не дойдет до максимального значения равного 500. После этого скрипт увеличит период медленной средней на один шаг цены и установит на минимум период быстрой средней. Периоды станут равны 100 для быстрой и 650 для медленной. Скрипт пройдет по всем историческим данным, рассчитает все сделки, с текущими параметрами и выдаст результат.

Далее период быстрой средней увеличится на один шаг. Периоды станут равны 150 для быстрой средней и 650 для медленной средней. Снова пойдет расчет сделок по историческим данным с выводом результата. Все это будет продолжаться до тех пор, пока период медленной средней не станет равен максимальному значению равному 900.

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

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

Создадим две таблицы Lua, которые будут содержать значения скользящих средних.

Переменные, содержащие слово «fast» будут относиться к быстрой средней, содержащие слово «slow» для медленной средней.

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

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

Далее, результаты всех тестирований мы будем записывать в файл. Создадим переменную и откроем файл для записи.

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

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

Первый цикл готов. Весь остальной код будет прописан в теле текущего цикла, между этих двух переменных.

Запишем второй цикл, который будет увеличивать значение быстрой скользящей на один шаг. Цикл будет исполняться, пока период быстрой средней будет меньше или равен максимальному значению.

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

Строка с именами колонок получилась очень длинной, пришлось записать ее в две строки.

Точно такие же строки запишем в файл.

Далее создадим переменные, которые будут использоваться в расчетах и присвоим им необходимые значения.

Строка кода 77. Торговый счет и его размер.

Строка кода 78. Гарантийное обеспечение. В данном примере тестирования на исторических данных используется не точный размер гарантийного обеспечения, а предполагаемый причем с запасом. Например, на момент написания данного раздела, гарантийное обеспечение на фьючерсный контракт нефти Brent равняется 4194 руб. В наших расчетах мы будем использовать гарантийное обеспечение размером 10000 руб., что более чем в два раза превышает текущее значение. На самом деле очень важно использовать для расчетов и в торговле счет, более чем в два раза превышающий объем позиции. Объясню свою позицию по этому поводу. Мы точно не знаем, какое гарантийное обеспечение было в прошлые периоды, на которых мы тестируем торговую систему, может быть так, что тестируемый торговый инструмент в прошлом имел крайне высокую волатильность и по нему повышали гарантийное обеспечение. Если взять гарантийное обеспечение, для тестирования, практически равным текущему, то можно сделать ошибочные выводы по доходности системы. На исторических данных будет считаться, что система находится в позиции, а в реальности этой сделки быть не могло, поскольку гарантийное обеспечение увеличили, и на счете не хватает средств для открытия такого объема позиции.

Продолжим…

Строка кода 79. Количество контрактов в сделке. Расчет количества контрактов происходит в функции TradeResult(), эта переменная нужна лишь для того чтобы вывести на экран и записать в файл количество контрактов в сделке.

Строка кода 80. Шаг цены фьючерсного контракта на нефть марки Brent равно 0,01 пункт.

Строка кода 81. Стоимость шага цены фьючерсного контракта на нефть марки Brent. Стоимость шага цены меняется после каждого клиринга. Мы точно не знаем, чему был равен шаг цены в тот или иной период. В данном примере установлено значение 6. На протяжении рассматриваемого исторического периода данное значение подходит как среднее. Конечно, можно найти исторические данные по доллару, сопоставить их с нашими историческими данными и использовать точное значение шага цены, но, по моему мнению, на результат это сильно не повлияет, если конечно не было больших скачков курса USD/RUB.

Продолжим…

Строка кода 82. Цена входа в позицию.
Строка кода 83. Цена выхода из позиции.
Строка кода 84. Результат сделки в пунктах.
Строка кода 85. Суммарное количество пунктов в плюс.
Строка кода 86. Суммарное количество пунктов в минус.
Строка кода 87. Количество сделок в плюс.
Строка кода 88. Количество сделок в минус.
Строка кода 89. Суммарное количество денег в плюс.
Строка кода 90. Суммарное количество денег в минус.
Строка кода 91. Направление позиции «L» – длинная позиция, «S» – короткая позиция.
Строка кода 92. Переменная меняющее свое значение на true, после входа в позицию. Переменная остается true на протяжении всего времени нахождения в позиции. Служит фильтром, если значение true, то новая позиция не может быть открыта.

Все эти переменные прописаны именно здесь, для того чтобы их значения приводились в первоначальное состояние после перехода расчета к новым периодам скользящей средней.

Далее запишем третий цикл, который будет перебирать исторические данные от начала до конца в поисках сделок. Для цикла нам понадобится управляющая переменная, создадим ее с именем «j» и присвоим ей значение 1. В конце каждой итерации цикла «j» будет увеличиваться на единицу. Цикл будет исполняться пока «j» меньше или равна количеству строк в таблице с историческими данными.

Напомню, в строке кода 95 запись #List_Day означает количество строк в таблице List_Day. Таблица List_Day содержит исторические данные даты торгов.

Следующим шагом будет расчет значений скользящих средних.

Для расчета скользящей средней требуются исторические данные в объеме равном или превышающем ее период, т.е. мы не можем рассчитать скользящую среднюю с периодом 100 если у нас только 10 свечек. Следовательно, нам нужно дождаться пока цикл переберет определенное количество строк, а потом только начать расчет скользящей средней. Добавим условие, сравнивающее текущее количество прочитанных строк и значение периодов скользящих средних.

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

Если условие не выполняется, то приступим к расчету значений скользящих средних. Создадим две переменных, первая будет управляющей для цикла, который перебирает исторические данные, присвоим ей значение переменной «j». Для того чтобы найти среднее значение за период, необходимо суммировать все значения за этот период и разделить на этот период. Суммировать будем начинать с текущего значения вверх до расчетного. Вторая переменная будет содержать сумму значений.

Ниже запишем цикл для суммирования цен закрытия.

Строка кода 102. Цикл будет выполняться пока переменная «f» больше значения «j — SMA_fast_N». Рассмотрим работу условия на примере. Допустим j = 200, в строке кода 99 мы присваиваем переменной «f» значение переменной «j» следовательно, первоначально f = 200, текущее значение SMA_fast_N = 100, строка кода 68. Условие выгладит так 200 > 100. После первой итерации цикла в строке кода 103, переменная «f» уменьшится на единицу, условие будет выглядеть 199 > 100, и так далее. Таким образом, мы суммируем предыдущие 100 цен закрытия.

После того как цикл отработал, рассчитаем среднее значение и запишем его в таблицу.

Точно таким же образом рассчитаем значение медленной скользящей средней.

Далее перейдем к составлению условий входа и выхода из позиции.

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

За наличие позиции отвечает переменная En_YES, строка кода 92. В случае отсутствия позиции переменная имеет значение false.

Запишем условие.

Запишем условие определяющее вход в позицию.

Разберем строки кода.

Строка кода 116. Обратите внимание на индексы строк, которые сравниваются. Сравнивается не текущее значение скользящих, а предыдущее и пред предыдущее, т.е. -1 и -2 периода. Сделано это дабы избежать ошибки «предвидеть будущее». Если система работает в реальном времени, то может быть так, что в течении одной свечки скользящие пересекались, а под закрытие уже нет, соответственно в реальных торгах вход был а на исторических данных нет. Поэтому берем данные только с закрытых свечек.

Если условие выполняется, тогда записываем цену открытия текущей свечи в переменную для цены входа. Строка кода 117. Объясню, почему именно цену открытия свечи. Теоретически сразу после открытия новой свечи скрипт определит, были условия для входа или нет. Если брать реальные торги то в большинстве случаев не получится войти в позицию по цене открытия свечи, но цена будет где-то рядом иногда выше иногда ниже цены открытия. Для расчетов приближенных к реальности можно добавить в функцию TradeResult() значение проскальзывания при входе и выходе из позиции. Лучшим местом для добавления проскальзывания будут строки кода, в которых рассчитывается переменная TradePunct. Сейчас мы этого делать не будем, это уже тонкие настройки, которых может быть очень.

Строка кода 118. Устанавливаем значение true в переменную En_YES, этим мы указываем скрипту, что сейчас есть позиция и следует отслеживать выход из нее.

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

Выход по пересечению скользящих принципиально не отличается от входа, так что тут должно быть все понятно. Выход по окончанию фьючерса рассмотри подробнее.В файле с историческими данными, в последнем столбце содержится порядковый номер файла. Если номер на следующей свече меняется, то это означает конец обращения фьючерса. Порядковые номера файлов содержаться в таблице List_NumFile .

Запишем условие выхода.

Строка кода 121. Первые два условия определяют пересечение скользящих. Третье условие определяет конец обращения фьючерса, если текущее значения номера файла не равно предыдущему, то закрываем позицию.

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

Запишем условие, проверяющее, был ли осуществлен выход по окончанию фьючерса. Присвоим переменной PriceEx соответствующее значение.

Далее изменим состояние переменной En_YES на false, поскольку был осуществлен выход из позиции. Вызовем функцию TradeResult() для расчета результатов следки.

Вызов функции TradeResult(), строки кода 128 и 129, имеет длинную запись, для наглядности вызов функции разбит на две строки.

Далее выведем на экран результаты сделки, а также запишем их в файл.

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

Осталось добавить одну строку кода, в которой мы увеличим период быстрой скользящей средней на один шаг. Запишем строку в конце цикла while SMA_fast_N <= SMA_fast_N_max do.

Скрипт полностью готов. Сохраним и запустим его.

Скрипт отработал, на моем компьютере это заняло около 2 минут времени, в зависимости от производительности железа время может варьироваться. На экране отображаются результаты сделок. Точно такие же данные сохранены в файле. Откроем файл «Тест систем BR.txt»в блокноте.

В блокноте неудобно просматривать записи, давайте откроем дынный файл в Excel.Запустим Excel.

В главном меню откроем «Файл» далее «Открыть», перейдем в папку Lua_QUIK, в нижнем левом углу выберем из меню «Все файлы (*.*)», выберем файл, нажмем «Открыть».

В окне выберем пункт «с разделителями».

Далее. В следующем окне выберем разделитель «пробел».

В следующем окне для столбцов, в которых есть дробные значения с точкой, установим текстовый формат, для остальных оставим общий формат и нажмем «Готово»

Файл откроется в следующем виде.

В открывшемся файле дробные числа отображаются не верно, поскольку в России принят разделитель дробной расти «,» запятая а в языке программирования Lua это «.» точка. Заменим точку на запятую. Выделим столбцы с дробными числами и нажмем Ctrl+H. Найдем точку и заменим на запятую.

Нажмем «Заменить все». Замена произойдет, но это еще не все, поменяем формат ячеек в столбцах с дробными числами. Щелкним правой кнопкой мыши на выделенный столбец в контекстном меню выберем «Формат ячеек», в открывшемся окне выберем числовой формат.

В итоге получился корректный Excel файл, который удобно просматривать и анализировать с помощью обширных встроенных функций.

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