Від ідеї до розробки: що потрібно знати про створення стратегій для торгівлі на біржі. Частина III



В попередніх матеріалах, які розкривають головні тези циклу статей автора блогу Financial Hacker, ми поговорили про використання неэффективностей ринку на прикладі історії з ціновим обмеженням для швейцарського франка і розглянули важливі фактори, які потрібно враховувати при створенні стратегій для торгівлі на біржі.

В цей раз мова піде про загальні принципи розробки модель-орієнтованих трейдінгових систем.

Розробка «ідеальної» стратегії

Як і в багатьох інших випадках, коли справа стосується розробки стратегій для торгівлі на біржі, є два шляхи: ідеальний і реальний. Для початку розглянемо ідеальний процес розробки стратегії.

Крок 1. Вибір моделі
Для початку вам слід вибрати одну з описаних раніше неэффективностей ринку або виявити нову. Цілком можливо, що якісь ідеї з'являться при аналізі цінової кривий, коли що-небудь підозріле буде відповідати певній логіці ринку. Годиться і протилежний варіант – від теорії поведінкового патерну до його перевірки на реальних даних. Правда, всі закономірності та неефективності, швидше за все, вже відкриті і вивчені іншими учасниками ринку за багато років.

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



В нашому випадку (Ci) – тривалість, (Di) — фаза і (ai) – амплітуда. Один з найуспішніших фондів в історії — Renaissance Medallion — запевняє, що зміг домогтися гарних результатів, використовуючи модель циклів разом з прихованої марківської моделі.

Крок. 2. Пошуки
Потрібно також переконатися, що обрана аномалія дійсно проявляє себе в ціновій кривий активів, якими трейдер збирається торгувати. Перевірити це можна за допомогою історичних даних — D1, M1 і тикові значення, що показують розподіл аномалії по тимчасовій осі. Весь питання, наскільки глибоко в минуле потрібно копати? Відповідь: наскільки це можливо. Поки не з'ясуються умови виникнення аномалії. Потім доведеться написати скрипт, який буде знаходити і демонструвати аномалію на ціновій кривої. У нашому прикладі це буде частотний спектр для пари євро/долар:



Необхідно з'ясувати, як змінюється спектр за умовні проміжки часу – місяці і роки, а потім порівняти його зі спектром випадкових даних (в деяких мовах програмування, начебто Zorro, є спеціальні функції для рандомізації кривих). Якщо ніяких ознак аномалії і відмінностей від випадкового розподілу не виявлено, трейдеру доведеться удосконалити метод виявлення аномалії. І якщо нічого не вийде – то повернутися до кроку 1.

Крок 3. Алгоритм
Наступний крок передбачає написання алгоритму, який буде генерувати торгові сигнали на відкриття і закриття позицій, дотримуючись обраної аномалії. У звичайній ситуації неефективність ринку слабо впливає на цінову криву. Тому алгоритм повинен бути налаштований досить тонко, щоб відокремлювати прояв аномалії від випадкового шуму. У той же самий час він повинен бути настільки простим, наскільки це взагалі можливо, і ґрунтуватися на мінімальному числі вільних параметрів. В нашому варіанті скрипт змінює позицію на кожній западині і піке синусоїди, яка йде поверх домінуючого циклу:

function run()
{
vars Price = series(price());
var Phase = DominantPhase(Price,10);
vars Signal = series(sin(Phase+PI/4));

if(valley(Signal))
reverseLong(1); 
else if(peak(Signal))
reverseShort(1);
}

Це ядро системи. Тепер настає час для бэктестинга. Точність виконання завдання в даному випадку не так важлива, потрібно просто визначити межі дії алгоритму. Чи зможе він здійснити серію вигідних угод в конкретних ринкових ситуаціях? Якщо ні, залишається два варіанти: переписати або створити заново, використовуючи інший метод. На даному етапі не треба напихати алгоритм трейлінг-стопами та іншою начинкою. Вони спотворять результат і створять ілюзію вигоди на порожньому місці. Алгоритм повинен навчитися просто отримувати прибуток хоча б у разі закриття позицій по часу.

На даному етапі також потрібно визначитися з даними для бэктеста. Для робочого тесту досить M1 і тикових котирувань. Добові дані не годяться. Обсяг даних залежить від тривалості аномалії (яка була визначена на другому етапі) і її природи. Зазвичай, чим довший період, тим точніше тест. Не має сенсу закопуватися глибше, ніж на 10 років. Принаймні, якщо мова йде про реально існуючому поведінкою ринку через десяток років ринок змінюється критично. Застарілі дані дадуть невірний результат.

Крок 4. Фільтр
Жодна неефективність не триває вічно. Будь-який ринок проходить через періоди довільного поведінки котирувань. Тому для кожної успішної трейдингової системи критично мати фільтр, який би визначав наявність або відсутність неефективності. Фільтр також важливий, як і сигнал, якщо не ще важливіше. Але, з різних причин, про нього часто забувають. Нижче приклад скрипта, що встановлює фільтр для торговельної системи:

function run()
{
vars Price = series(price());
var Phase = DominantPhase(Price,10);
vars Signal = series(sin(Phase+PI/4));
vars Dominant = series(BandPass(Price,rDominantPeriod,1));
var Threshold = 1*PIP;
ExitTime = 10*rDominantPeriod;

if(Amplitude(Dominant,100) > Threshold) {
if(valley(Signal))
reverseLong(1); 
else if(peak(Signal))
reverseShort(1);
}
}

Тут застосовано смуговий фільтр, центрований по періоду домінантного циклу до цінової кривій і вимірює його амплітуду. Якщо амплітуда перевищує встановлену межу, то можна бути впевненим, що неефективність є, і діяти відповідно. Тривалість операції тепер також обмежена максимум 10 циклами, оскільки на другому етапі ми з'ясували, що домінантний цикл з'являється і зникає на відносно невеликих тимчасових відрізках.

Що тут може піти не так? Помилкою буде додавати фільтр просто тому, що він покращує результат тесту. Будь фільтр повинен мати за собою раціональне обґрунтування, відштовхуючись від поведінки ринку або сигналів алгоритму.

Крок 5. Оптимізація параметрів
Всі параметри системи, так чи інакше, впливають на результат. Але лише кілька з них безпосередньо визначають точки входу і виходу з позиції, грунтуючись на ціновій кривої. Необхідно виявити і оптимізувати ці адаптуються параметри. У нашому прикладі відкриття позиції визначається фазою прогнозування поведінки кривої і порогом, встановленим фільтром. Час закриття угоди визначено точкою виходу. Інші параметри, такі як постійні фільтра DominantPhase і функція BandPass, потрібно оптимізувати, оскільки їх значення залежать від ситуації на ринку.

Частенько оптимізацію трактують неправильно. Метод генетичної або насильной оптимізації – це спроба знайти пік вигоди в багатовимірному просторі параметрів. В більшості випадків це не має відношення до роботи живої системи. Хоча може вийти унікальна комбінація параметрів, яка дасть відмінний результат тесту. Навіть зовсім трохи відрізняються один від одного історичні періоди дають абсолютно різні піки. Замість того, щоб ганятися за значенням максимуму прибутку на історичній кривий, оптимізація повинна йти наступним шляхом:

  • Вона може визначати чутливість системи до значень параметрів. Якщо система пропускає свої кордони при мінімальній зміні параметрів, краще повернутися до кроку 3. Якщо виправити ситуацію не виходить – назад до першого етапу.
  • Через оптимізацію можна знайти активні точки параметрів. Це зона, де параметри найбільш надійні, тобто, де навіть невелика зміна не робить істотного ефекту на позитивний результат. Це не вузькі піки, як можна було б подумати, а широкі пагорби в просторі параметрів.
  • Вона може адаптувати систему до різних активів і дозволити працювати з портфелем акцій при мінімальній зміні параметрів.
  • Вона може збільшити термін служби системи через адаптацію параметрів поточної ринкової ситуації на регулярних інтервалах, паралельно з процесом «живий» торгівлі.
Ось приклад скрипта для оптимізації параметрів:

function run()
{
vars Price = series(price());
var Phase = DominantPhase(Price,10);
vars Signal = series(sin(Phase+optimize(1,0.7,2)*PI/4));
vars Dominant = series(BandPass(Price,rDominantPeriod,1));
ExitTime = 10*rDominantPeriod;
var Threshold = optimize(1,0.7,2)*PIP;

if(Amplitude(Dominant,100) > Threshold) {
if(valley(Signal))
reverseLong(1); 
else if(peak(Signal))
reverseShort(1);
}
}

Два оптимізованих виклику використовують стартове значення 1.0 і діапазон (0,7..2,0) для визначення активних точок двох основних параметрів. На діаграмі коефіцієнта прибутку ці точки відзначені червоними стовпцями:





В даному варіанті оптимізатор вибирає значення близьке до 1,3 для фази синусоїди і значення 1,0 (не 0,9 для піка) для амплітуди порогу для поточного співвідношення в парі євро/долар. Час виходу тут не оптимізовано.

Крок 6. Аналіз за межами вибірки
Оптимізація параметрів покращує якість перевірочного тесту. Але наша система все ще не підігнана до цінової кривої. Тому результати тесту для поки марні. Тепер треба розділити дані на цикли у вибірці і за її межами. Вибірка використовується для навчання системи, аналіз за межами вибірки — для тестування. Стандартний метод для цього – форвардний аналіз. Він використовує динамічну вибірку або ковзне вікно для історичних даних для поділу двох циклів.

На жаль, форвардний аналіз додає два нових параметра до системи: час навчання і час тестування. Друге не критично, головне, щоб воно було порівняно невеликим. Але ось час навчання має значення. Занадто коротке навчання не дозволить отримати достатню кількість даних за ціною для ефективної оптимізації. Занадто довге також негативно позначиться на результаті. Ринок може «переварити» зміни, поки буде проходити навчання. Тому час навчання саме по собі потребує оптимізації.

Форвардний аналіз з кроком в п'ять циклів (виставимо NumWFOCycles = 5 в попередньому скрипті) знижує продуктивність бэктеста зі 100% річної виручки до більш реалістичним 60%. Для того щоб уникнути занадто оптимістичних результатів та помилок в аналізі, можна запустити його кілька разів з трохи розрізняються між собою умовами симуляції. Якщо система має свою межу, результати не повинні дуже різнитися. В іншому випадку буде потрібно повернутися до кроку 3.

Крок 7. Випробування реальністю
Навіть пройшовши стадію аналізу за межами вибірки, ми все ще маємо якісь спотворення результату. Викликані вони обмеженням самої системи або недоліками в процесі розробки (вибору активу, алгоритму, часу перевірки і так далі)? З'ясувати це – найскладніша частина роботи над трейдингової стратегією.

Оптимальний варіант – використовувати для цього метод під назвою Тестування реальності за методом Уайта (white's Reality Check). Він же і найменш практичний, так як вимагає строгого порядку при виборі параметрів алгоритму. Два інших методу не так гарні, але більш зручні в застосуванні:

  • Монте-Карло. Передбачає рандомізацію цінової кривий за допомогою перетасування даних без їх зміни. Потім необхідно провести навчання системи і протестувати її знову, а потім виконати все ще раз і згенерувати розподіл результатів. Рандомізація видалить всі цінові аномалії. Але якщо результат реальної цінової кривий виявиться не так далеко від піку випадкового розподілу, він ймовірно також викликаний випадковістю. Що це означає? Потрібно повернутися до кроку 3.
  • Варіанти. Цей метод є протилежністю попереднього. Він пристосовує обучающуюся систему до різних варіантів цінової кривий, щоб отримати позитивний результат. Варіанти, що підтримують більшість аномалій, відносяться до дискретизації з підвищеною частотою, усувають вплив тренда або інвертують цінову криву. Якщо система залишається у виграші з такими варіантами, але не з випадковими цінами, ви дійсно підібрали щось вартісне.
  • ROOS-тест (Really-out-of-sample). Передбачає повне виключення в процесі розробки даних за останній рік (в прикладі — 2015-й) аж до видалення даних про рух цін з комп'ютера. І тільки, коли система буде повністю завершена, потрібно завантажити дані за цей рік і запустити тест. Тут потрібно зібрати всю волю в кулак, щоб не стати переробляти систему, якщо вона на цьому останньому тесті не покаже бажаних результатів. Потрібно просто відкласти її убік і повернутися до кроку 1.
Крок 8. Управління ризиками
Отже, система пережила всі перевірки. Тепер можна сконцентрувати зусилля на зниження ризиків і підвищення її продуктивності. Більше не потрібно повертатися до вхідних даних алгоритму та його параметрами. Потрібно оптимізувати те, що буде отримано на виході. Замість простого обмеження по часу і скасування для виходу можна використати механізми різних трейлінг-стопів. Наприклад:

  • Замість виходу після заданого проміжку часу, потрібно встановити стоп-лосс на значення втрат для кожної години. Ефект буде однаковим, але тепер закриття невдалих угод буде відбуватися швидше, а вдалих пізніше.
  • Слід розмістити стоп-лосс при досягненні певного значення профіту над точкою відкату значень. Навіть якщо фіксація відсотка прибутку не поліпшить загальну продуктивність, це все одно буде корисно.
Ось приклад скрипту, який встановлює стоп-лоси:

function run()
{
vars Price = series(price());
var Phase = DominantPhase(Price,10);
vars Signal = series(sin(Phase+optimize(1,0.7,2)*PI/4));
vars Dominant = series(BandPass(Price,rDominantPeriod,1));
var Threshold = optimize(1,0.7,2)*PIP;

Stop = ATR(100);
for(open_trades)
TradeStopLimit -= TradeStopDiff/(10*rDominantPeriod);

if(Amplitude(Dominant,100) > Threshold) {
if(valley(Signal))
reverseLong(1); 
else if(peak(Signal))
reverseShort(1);
}
}

Зрозуміло, тепер доведеться ще раз пройти процес оптимізації і форвардний аналіз параметрів виходу.

Крок 9. Розподіл грошових коштів
Процес управління коштами переслідує три мети. По-перше, реинвестирвоать доходи. По-друге, грамотно розподілити капітал всередині портфеля. По-третє, вчасно зрозуміти, що торговий портфель марний. У будь-якому підручнику по трейдингу можна знайти рада інвестувати 1% сумарного капіталу за угоду. Ці речі пишуть люди, які не заробили жодного цента в реальній торгівлі.

Позначимо обсяг інвестицій за фіксований час через V(t). Якщо система приносить дохід, в середньому капітал C буде пропорційно зростати з коефіцієнтом с.



Якщо слідувати порадам авторів розумних книг і інвестувати фіксований відсоток p від капіталу, V(t) = p C(t), то капітал повинен рости по експоненті p c.

image

До нещастя, в цей же час капітал буде відчувати на собі вплив випадкових коливань. Такі осідання будуть пропорційні торгуемому обсягом коштів V(t). Це можна розрахувати за допомогою формули, де максимальна глибина осідання Dmax збільшуватиметься пропорційно квадратному кореню від t.

image

Таким чином, при фіксованому значенні інвестування отримуємо:

image

І у даному випадку T = 1/(q p)2

image

З цих розрахунків можна бачити, як за період T просадка з'їсть всі гроші на рахунку. Не має значення, наскільки хороша сама торгова система, і який відсоток інвестування трейдер виставив. Тому рада «вкладати за раз 1%» — погана порада. Ось чому автор блогу Financial Hacker радить своїм клієнтам не піднімати торговий обсяг пропорційно до акумульованої прибутку, але робити це на квадратний корінь. Поки сама стратегія не вичерпає себе, це буде тримати трейдера на безпечній відстані від маржин-колла.

В залежності від того, працює чи трейдер з одним активом і одним алгоритмом або з їх наборами, оптимальний обсяг інвестицій можна визначити кількома методами. Наприклад, за формулою OptimalF Ральфа Вінса або за формулою Келлі від Еда Торпа. У більшості випадків логічно піти від великовагового коду для реалізації процесу реінвестування, тому обсяг інвестицій можна розрахувати і за межами алгоритму. Особливо, якщо трейдер збирається знімати або класти гроші на рахунок час від часу. Зручну формулу для таких речей можна знайти в мануалі мови Zorro.

Крок 10. Підготовка до реальної торгівлі
Прийшов час визначитися з користувальницьким інтерфейсом для трейдингової системи. Для цього необхідно зрозуміти, які параметри потрібно буде міняти в режимі реального часу, а які залишаться постійними. Далі слід пристосувати до неї метод управління торговим обсягом і реалізувати «тривожну кнопку» для фіксування прибутку і виходу в кеш при появі поганих новин. Необхідно відобразити всі істотні параметри трейдингу в реальному часі, додати можливості для перенавчання системи і включити в неї метод порівняння реальних результатів з результатами бэктеста. Трейдер має переконатися, що зможе контролювати систему з будь-якої точки простору і часу. Це не означає, що її потрібно перевіряти кожні п'ять хвилин. Але мати можливість за обідом поглянути на результати торгівлі з допомогою мобільного телефону ніколи не зашкодить.

Як часто відбувається в реальності

Вище ми описали розробку ідеальної стратегії. Все це виглядає симпатично. Але як розробити реальну стратегію трейдингу? Зрозуміло, що між теорією і практикою лежить прірва — що, звичайно, неправильно.

Ось як часто виглядає послідовність кроків по створенню стратегії роботи на біржі, яку проробляють сотні і тисячі трейдерів:

Крок 1. Зайти на форум трейдерів і отримати підказку про новий крутому індикаторі, який приносить надзвичайну виручку.

Крок 2. Помучитися з кодом системи тестів, щоб переконатися, що індикатор працює. Результати бэктеста не вражають? Код закралася помилка. Потрібно зробити налагодження, намагатися ще краще.

Крок 3. Все ще немає результату, але трейдер вже усвідомлює, що освоїв і кілька корисних ходів. Можна ще додати трейлінг-стоп. Тепер все виглядає трохи краще. Пора запускати тижневий аналіз. Вівторок випадає з стратегії? Потрібно додати фільтр, який пропускає торгівлю по вівторках. Вписати ще кілька фільтрів, які блокують відкриття позицій між 10 і 12 ранку, у випадку, якщо котирування менше $14,5, і в період повного місяця. Слід почекати, поки моделювання завершиться. Відмінно, результати бэктеста тепер хороші!

Крок 4. Зрозуміло, ніхто не ведеться просто на результат вибірки. Після оптимізації всіх 23 параметрів, трейдер запускає форвардний аналіз. Чекає. Не подобається результат? Він пробує різні цикли цього аналізу, різні періоди. Ще чекає. Нарешті, потрібні значення з'являться.

Крок 5. Система запускається в ході реальних торгів.

Крок 6. Підсумок не виглядає вражаючим.

Крок 7. Після фіаско залишається тільки чекати, поки банківський рахунок прийде в себе. Деякі трейдери в такі періоди займаються написаннями книг з торгівлі на біржі.

У наступному матеріалі ми розглянемо підхід використання техніки data mining в поєднанні з машинним навчанням для виявлення патернів з допомогою різних алгоритмів і нейронних мереж.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.