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

При тестировании торговых алгоритмов на истории я задаю следующие условия:

————————————————

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

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

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

Исходя из сказанного, я задаю начальный размер депозита в 100 тысяч рублей (Очевидно, что для сбербанка эта сумма может быть раз в 10 больше).

————————————————-

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

Считаю такой подход далеким от реальности.  Помимо геометрического роста депозита, такой подход предполагает, что Вы никогда не забираете деньги с депозита.  Т е фактически работаете на брокера.

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

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

————————————————————

Теперь я приведу наглядный результат тестирования чернового варианта построенного мною торгового робота на истории с 2008 года по настоящее время.

Алгоритм реверсивный.  Комиссия брокера 0.035%

———————————————————

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

—————————————————————-

Результат на графике и в таблице:

kamnik_2014_5_002

 

 

 

All trades Long trades Short trades
Initial capital 100000.00 100000.00 100000.00
Ending capital 234178988.85 140498730.16 93780258.70
Net Profit 234078988.85 140398730.16 93680258.70
Net Profit % 234078.99 % 140398.73 % 93680.26 %
Exposure % 27.34 % 12.51 % 14.83 %
Net Risk Adjusted Return % 856105.41 % 1122209.61 % 631635.03 %
Annual Return % 242.01 % 215.41 % 195.83 %
Risk Adjusted Return % 885.10 % 1721.75 % 1320.40 %
Total transaction costs 24895497.18 12736301.02 12159196.15
All trades 2251 1125 (49.98 %) 1126 (50.02 %)
 Avg. Profit/Loss 103988.89 124798.87 83197.39
 Avg. Profit/Loss % 0.69 % 0.74 % 0.65 %
 Avg. Bars Held 70.50 63.59 77.40
Winners 1096 (48.69 %) 549 (24.39 %) 547 (24.30 %)
 Total Profit 386095375.34 208382366.30 177713009.04
 Avg. Profit 352276.80 379567.15 324886.67
 Avg. Profit % 2.27 % 2.31 % 2.24 %
 Avg. Bars Held 94.60 89.62 99.59
 Max. Consecutive 16 9 12
 Largest win 10473445.21 10473445.21 10014591.45
 # bars in largest win 518 518 347
Losers 1155 (51.31 %) 576 (25.59 %) 579 (25.72 %)
 Total Loss -152016386.48 -67983636.15 -84032750.34
 Avg. Loss -131615.92 -118027.15 -145134.28
 Avg. Loss % -0.80 % -0.75 % -0.85 %
 Avg. Bars Held 47.63 38.78 56.44
 Max. Consecutive 10 10 10
 Largest loss -4454553.27 -2593807.75 -4454553.27
 # bars in largest loss 74 409 74
Max. trade drawdown -4713458.18 -4616353.47 -4713458.18
Max. trade % drawdown -15.91 % -15.91 % -10.43 %
Max. system drawdown -9806466.20 -5958457.55 -10225479.88
Max. system % drawdown -23.92 % -41.20 % -26.97 %
Recovery Factor 23.87 23.56 9.16
CAR/MaxDD 10.12 5.23 7.26
RAR/MaxDD 37.01 41.79 48.96
Profit Factor 2.54 3.07 2.11
Payoff Ratio 2.68 3.22 2.24
Standard Error 23385452.60 16503545.10 7500596.87
Risk-Reward Ratio 1.58 1.38 1.89
Ulcer Index 2.56 3.85 5.87
Ulcer Performance Index 92.59 54.54 32.44
Sharpe Ratio of trades 3.61 3.60 3.76
K-Ratio 0.0073 0.0064 0.0087

 Как видим из таблицы, полученная за 6 лет и 4 месяца прибыль составила бы астрономическую сумму в 234 млн.руб, при начальном депозите в 0.1 млн.руб. т е прибыль в процентах составила бы 234 тысячи %.

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

———————————————————-

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

 kamnik_2014_5_001

 

  All trades Long trades Short trades
Initial capital 100000.00 100000.00 100000.00
Ending capital 1661762.23 931515.57 830246.66
Net Profit 1561762.23 831515.57 730246.66
Net Profit % 1561.76 % 831.52 % 730.25 %
Exposure % 13.79 % 5.82 % 7.97 %
Net Risk Adjusted Return % 11326.58 % 14294.64 % 9160.72 %
Annual Return % 56.12 % 42.43 % 39.86 %
Risk Adjusted Return % 406.98 % 729.44 % 499.99 %
Total transaction costs 157541.86 79036.83 78505.03
All trades 2251 1125 (49.98 %) 1126 (50.02 %)
 Avg. Profit/Loss 693.81 739.12 648.53
 Avg. Profit/Loss % 0.69 % 0.74 % 0.65 %
 Avg. Bars Held 70.50 63.59 77.40
Winners 1096 (48.69 %) 549 (24.39 %) 547 (24.30 %)
 Total Profit 2488016.06 1265496.02 1222520.04
 Avg. Profit 2270.09 2305.09 2234.95
 Avg. Profit % 2.27 % 2.31 % 2.24 %
 Avg. Bars Held 94.60 89.62 99.59
 Max. Consecutive 16 9 12
 Largest win 64342.89 64342.89 34597.19
 # bars in largest win 267 267 89
Losers 1155 (51.31 %) 576 (25.59 %) 579 (25.72 %)
 Total Loss -926253.83 -433980.45 -492273.38
 Avg. Loss -801.95 -753.44 -850.21
 Avg. Loss % -0.80 % -0.75 % -0.85 %
 Avg. Bars Held 47.63 38.78 56.44
 Max. Consecutive 10 10 10
 Largest loss -11069.89 -11069.89 -6801.48
 # bars in largest loss 409 409 317
Max. trade drawdown -25575.71 -25575.71 -11874.91
Max. trade % drawdown -15.91 % -15.91 % -10.43 %
Max. system drawdown -32954.56 -31317.28 -23929.78
Max. system % drawdown -9.74 % -10.64 % -8.16 %
Recovery Factor 47.39 26.55 30.52
CAR/MaxDD 5.76 3.99 4.88
RAR/MaxDD 41.77 68.58 61.27
Profit Factor 2.69 2.92 2.48
Payoff Ratio 2.83 3.06 2.63
Standard Error 193641.03 108624.41 88058.23
Risk-Reward Ratio 1.02 1.05 0.96
Ulcer Index 1.00 1.50 1.26
Ulcer Performance Index 50.95 24.64 27.42
Sharpe Ratio of trades 3.61 3.60 3.76
K-Ratio 0.0047 0.0048 0.0044

 В этом случае за 6 лет и 4 месяца мы могли бы заработать 1,6 млн. рублей при открытии позиции на сумму не более 0.1 млн.руб.

Т е прибыль составила бы 1660 %.

Т е результаты вполне правдоподобны.

————————————————

Но как быть, если необходимо торговать на сумму более 1 млн. рублей в месяц.

Возможны различные варианты торгового алгоритма.

От запуска нескольких роботов до создание пирамидальной позиции.

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

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

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

Данный робот использует скользящее временное окно размером в 3000 бар 5 минутного тайма. Торгует на акциях сбербанка .

Cделки совершаются на открытии, следующей после возникновения сигнала, свечи.

Комиссия составляет 0.035%.

Объем средств в очередной сделке определяется по объему средств, полученных в предыдущей позиции.

Робот реверсивный. Т е всегда в рынке либо в лонге , либо в шорте.

В момент написания статьи, диапазон исторических данных составляет интервал от 11 марта 2014 по 18 апреля 2014 .

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

В основе создания торгового алгоритма лежат методы нейронных сетей с обучением с учителем.

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

kamnik_14_4_1

 

 

 

 

 

 

 

Результаты работы робота приведены в таблице:

Statistics

 

All trades

Long trades

Short trades

Initial capital

100000.00

100000.00

100000.00

Ending capital

501179.00

303893.98

297285.01

Net Profit

401179.00

203893.98

197285.01

Net Profit %

401.18 %

203.89 %

197.29 %

Exposure %

99.83 %

48.13 %

51.70 %

Net Risk Adjusted Return %

401.85 %

423.63 %

381.57 %

Annual Return %

121135362.42 %

1566957.45 %

1294390.42 %

Risk Adjusted Return %

121337890.54 %

3255676.18 %

2503507.77 %


All trades

149

74 (49.66 %)

75 (50.34 %)

 Avg. Profit/Loss

2692.48

2755.32

2630.47

 Avg. Profit/Loss %

1.11 %

1.13 %

1.09 %

 Avg. Bars Held

21.84

21.26

22.41


Winners

131 (87.92 %)

64 (42.95 %)

67 (44.97 %)

 Total Profit

413737.15

210597.47

203139.68

 Avg. Profit

3158.30

3290.59

3031.94

 Avg. Profit %

1.30 %

1.34 %

1.26 %

 Avg. Bars Held

23.21

23.44

23.00

 Max. Consecutive

21

10

20

 Largest win

22342.72

22342.72

9412.16

 # bars in largest win

184

184

10


Losers

18 (12.08 %)

10 (6.71 %)

8 (5.37 %)

 Total Loss

-12558.16

-6703.49

-5854.67

 Avg. Loss

-697.68

-670.35

-731.83

 Avg. Loss %

-0.29 %

-0.26 %

-0.34 %

 Avg. Bars Held

11.83

7.30

17.50

 Max. Consecutive

2

1

2

 Largest loss

-2473.56

-2473.56

-1219.12

 # bars in largest loss

16

16

16


Max. trade drawdown

-4461.89

-4461.89

-2981.84

Max. trade % drawdown

-2.28 %

-2.28 %

-1.87 %

Max. system drawdown

-5523.12

-4461.89

-2981.84

Max. system % drawdown

-2.28 %

-2.70 %

-2.11 %

Recovery Factor

72.64

45.70

66.16

CAR/MaxDD

53200384.28

580185.98

613198.67

RAR/MaxDD

53289330.84

1205455.63

1186000.46

Profit Factor

32.95

31.42

34.70

Payoff Ratio

4.53

4.91

4.14

Standard Error

25761.69

11324.67

15689.06

Risk-Reward Ratio

118.47

135.49

96.72

Ulcer Index

0.52

0.53

0.57

Ulcer Performance Index

233088518.41

2966725.79

2264537.31

Sharpe Ratio of trades

21.09

17.19

30.30

K-Ratio

0.0706

0.0808

0.0576

 

Я не привожу график прибыли, так как при просадке в 2% он будет практически ровной линией.

 

Хочу обратить внимение читателей на следующие показатели робота:

 

Максимальная просадка в сделках (Max. trade % drawdown ) составляет не более 2.3%.

Максимальная просадка за весь период торговли (Max. system % drawdown ) не более 2.7%.

Робот совершил 149 сделок из них 131 (88% ) прибыльных.

В среднем, робот находится в лонге  2 часа, а в шорте примерно 1 час.

В итоге прибыль за месяц составила 401%.

Профит фактор составляет 33.

———————————-

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

умных роботов,т е роботов, создаваемых на основе обучаемых алгоритмов.

 

Данная заметка является введением в основы разработки роботов на встроенной в торговый терминал QUIK  виртуальной машине VM LUA.

Немного о языке LUA…

—————————————-

В настоящее время в торговый терминал QUIK встроена виртуальная машина LUA (VM LUA).

Это аналогично виртуальной машине JAVA или виртуальной машине NET.

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

На первом этапе, при загрузке скрипта, программа переводится из текстовой формы в байт код.

При этом каждая команда записывается в виде 4 -х байтового кода (формат long -целое число)

Существуют двух и трех-адресные команды.

Достоинством VM LUA является использование обращения к таблицам (массивам) по ссылке. Это позволяет существенно уменьшить требуемый объем памяти и получить высокую скорость исполнения программы.

Как и VM NET, VM LUA имеет встроенный сборщик мусора, что обеспечивает более эффективное использование оперативной памяти.

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

Таким образом, при существенном упрощении настройки , обеспечивается практически такая же скорость доступа к данным, как и с помощью интерфейса DDE.

VM LUA работает существенно быстрее, чем портфель, написанный на встроенном языке QPILE.

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

Основы реализации торговых роботов на LUA

————————————————————-

Рассмотрим некоторые особенности реализации торговых алгоритмов.

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

Например, терминал QUIK получил информацию в таблицу всех сделок о совершении какой-либо сделки . Перед записью информации об этой сделке в свою внутренную таблицу, терминал вызовет функцию в скрипте LUA с именем  onAllTrade.

Таким образом, чтобы обработать данную информацию в своем скрипте мы должны написать функцию:

function onAllTrade(cl,se)

….— здесь мы пишем алгоритм обработки информации о сделке

end

 

При вызове этой функции, QUIK передаст ей значение кода класса (cl) и кода инструмента (se), по которому совершена сделка.

Так как QUIK вызывает эту функцию для всех сделок, по всем инструментам, которые мы указали в настройках терминала, а торговать мы будет, например, лишь индексом RTS, то внутри данной функции необходимо отфильтровать нужный нам инструмент:

function onAllTrade(cl,se)

            if se==»RIH4″ then

….— здесь мы пишем алгоритм обработки информации о сделках по индексу

end

end

Для работы программы на LUA в терминале QUIK необходимо написать еще минимум две  специальные функции с именами  main и onStop.

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

function main()

nkqami.init();  —Инициализация связи с амиброкером

dofile(dirNK..»Nktab.lua«)  — Загрузка графического интерфейса с пользователем

Load_ini(fileName);  — Загрузка исходных данных робота

init();    —  Чтение существующей информации из таблиц терминала

restore(nk.robot);  — обновить таблицу робота

start=true    — установить флаг — «начало работы «

nkcom.ResetEvent(event);  — сбросить системный флаг потока

nkcom.WaiteEvent(event,-1);  ожидание системного события

for idx,t in pairs(nk) do

 if type(t)==»table» and t.id~=nil  then DestroyTable(t.id); end;  

end;

end

————————

function OnStop(stop_flag)  — вызывается при закрытии скрипта в окне скриптов

nkcom.SetParent();   — установить системный флаг потока

Save_ini(fileName)  — сохранить рабочие данные робота

nkqami.close();  —закрытие связи с Амиброкером

for idx,t in pairs(nk) do

if type(t)==»table» and t.id~=nil  then  DestroyTable(t.id); end;

end;

            start=false;

            nkcom.SetEvent(event);

            nkcom.CloseHandle(EventNKwindow);

end

 

Функция onStop будет вызвана лишь один раз, если мы закроем скрипт, нажав на кнопку «остановить» в окне QUIK запуска скриптов.

Функция main вызывается терминалом QUIK при запуске скрипта.

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

Все остальные функции исполняются в потоке терминала QUIK.

В моем варианте реализации , функция main тоже исполняется лишь один раз.

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

Вам же, в своих программах, вместо моих операторов внутри цикла while необходимо написать вызов функции sleep(200). Эта функция будет останавливать дополнительный поток на 200 ms при многократном исполнении  цикла.

Вот такими будут функции main и onStop в простейшем варианте:

function main()

start=true    — установить флаг — «начало работы «

while start do    — цикл

sleep(200)  — останов потока на 200 мs

            end

end

————————

function OnStop(stop_flag)  — вызывается при закрытии скрипта в окне скриптов

            start=false;

end

Первоначально, когда Вы лишь осваиваете работу в LUA, рекомендую реализовывать весь торговый алгоритм внутри колбек-функций.

В документации имена этих функций начинаются с on

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

            Про потоки…

——————————-

Потоками назваются ядра процессора, либо процессоры в кластере.

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

Кроме этого, я в своих разработках реализовал колбек функции обработки событий от программ технического анализа, в частности от Амиброкера, а в Амиброкере — колбек функции обработки событий от терминала QUIK.

———————————-

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

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