Парний трейдинг. Фільтр спредів

Anonim

Всім привіт! У даній статті я спробую розповісти про те, як можна заощадити купу часу, нервів і зір, перебираючи тисячі спредів пар, в спробі впорядкувати непотрібні нам спреди. Але для початку давайте згадаємо про що писалося в минулих статтях:

1. Коінтеграція в парному трейдингу

2. Парний трейдинг. Спред

3. Парний трейдинг. Акції для пар

4. Парний трейдинг: пара акцій, кореляція, Коінтеграція спреда, інвестиційний портфель (Клевцов Антон)

Тим хто не читав, настійно рекомендую. У цих статтях описана сама концепція парного трейдингу, чому Коінтеграція а не кореляція, що таке спред і як його будувати.

Ну а тепер поговоримо про можливі фільтрах спредів, а точніше про фільтр "краси" спреда, свого часу ми його називали саме так)

Вимірювання ступеня коінтеграції

У першій статті я вже розповідав про Коінтеграція і про її важливість. Настав час познайомитися з ним з прикладної точки зору.

Для чого нам розраховувати Коінтеграція? Ми вже знаємо, що ладу спреди між акціями, ми хочемо побачити в них якийсь перевага і розуміння. Розрахунок коінтеграції допоможе нам відфільтрувати хаотичні спреди, які нічим не відрізняються від непередбачуваних графіків вартості акцій компаній.

Як же спростити пошук красивих спредів?

Для оцінки ступеня коінтеграції між тимчасовими рядами існує ряд математичних методів, одним з базових і найефективніших є Розширений тест Дікі Фуллера (ADF test). Вдаватися в математичну складову в рамках цієї статті не будемо, тому що для розуміння принципу необхідно знати більш прості моделі і поняття з економетрики. Але не варто забувати що живемо ми в еру інформаційних технологій і будь-яка математична модель може бути автоматизована в середовищі програмування. З останніх я виділяю MatLab і R project, але вважав за краще останній. Тому все шматки коду, які я буду викладати в цій та наступних статтях будуть відноситься саме до мови R.

Побудуємо спред пари BMR/OFC:

Бачимо дуже навіть непоганий спред. Даний спред пройшов АДФ тест з відзнакою, значення p. value на виході вийшло рівним 0.01, що може говорити про належність даного спреда до стаціонарного на 99%. Значення p.value це коефіцієнт, який показує ймовірність того, що спред не стаціонарний. У нашому випадку значення коефіцієнта дорівнює 1%, значить з імовірністю 99% стверджуємо що даний спред нам підходить. Стаціонарним прийнято вважати тимчасової ряд, якщо значення p.value менше або дорівнює 0.05, тобто 5%. Але зі свого досвіду можу сказати, що АДФ тест не ідеальний і частенько приписує хорошим спред високу p.value, а погані спреди відносить до стаціонарних.

Код для розрахунку p. value:

library (timeDate)

stock1 = get. hist.quote (instrument = "BMR", start = "2012-01-01", end = "2014-10-01", quote = "AdjClose", retclass = "zoo", quiet = TRUE, drop = FALSE)

stock2 = get. hist.quote (instrument = "OFC", start = "2012-01-01", end = "2014-10-01", quote = "AdjClose", retclass = "zoo", quiet = TRUE, drop = FALSE)

spred = stock1 stock2

p. value = adf.test (spred) $ p.value

Функція get. hist.quote качає ціни закриття дня, скориговані на дивіденди і сплити, дані бере з yahoo finance. Параметри start і end вказують період скачується дати. Параметр instrument встановлює назву тікера необхідної акції. Останні два рядки будують ratio spred і визначають значення p.value.

Що б вас переконати в працездатності АДФ тесту, побудуємо пару SPY/AAPL:

Погодьтеся, ловити тут нічого, що і показав нам тест: значення p. value = 0.9, тобто 90% що спред НЕ стационарен, думаю сперечатися ніхто не буде))

Решта за кожним з вас) До цього коду треба написати цикл, який буде будувати всі можливі пари і визначати їх рівень коінтеграції. Можу сказати, що з кількох тисяч пар, навіть може з десятка тисяч, відфільтруєтся порядку 97-98%)) Хороших пар не так вже й багато.

Фільтр спредів N2

Є ще один варіант непоганого фільтра для спредів пар. Я його придумав не так давно, сильно його НЕ опкатал ще, але працює він дуже добре)

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

Розберемо малюнок:

Ми побудували два графіка акцій (BMR і OFC) приведені до відсоткам.

Далі побудуємо ковзаючі середні до кожного:

І бачимо, що тренди (ковзаючі середні) у даних акцій практично збігаються. Коли ми побудуємо спред між ними, ця трендова складова виключить сама себе і ми отримаємо спред між стаціонарними складовими, які розподілені навколо ковзають середніх.

Про те що спред між даними акціями стационарен ви можете переконається вище.

Тепер залишилося дану модель інтерпретувати в будь-якої показник. Я це зробив шляхом знаходження середнього арифметичного абсолютної різниці між легкими середніми: (Sum | SMA1-SMA2 |) / (Chart_period-sma_period). Отримали якийсь показник (назвемо його t.value), який вказує середню абсолютну різницю між легкими, відповідно чим вона менша, тим більше схожа середня складова у акцій і тим більше стационарен спред між ними. Провівши ряд випробувань, я виявив, що у непоганих спредів t.value не більше 10, у хороших не більше 5, у відмінних не більше 3-х. Період згладжування я використовував 50, з іншим значення t.value буде іншим і яким значенням буде відповідати хороший спред - невідомо. Але я багато з ним не практикував ще, тому діапазон значень може змінювати під власний смак. Наприклад t.value спреда BMR-OFC дорівнює 1.43, а у SPY-AAPL дорівнює 23.

Код, для розрахунку t. value для R:

filter = function (a, b, smooth_period, chart_period)

{

library (TTR)

a = a [1: chart_period]

b = b [1: chart_period]

a = a/a [1] * 100

b = b/b [1] * 100

ema. a = EMA (a, smooth_period)

ema. b = EMA (b, smooth_period)

t. value = sum (abs (ema.a [smooth_period: chart_period] -ema.b [smooth_period: chart_period])) / (chart_period-smooth_period + 1)

return (round (t. value, 2))

}

Де a - ціни першої акції, b - ціни другої акції, smooth_period - період ковзної (рекомендую 50), chart_period - довжина вашого графіка.

Код для thinkorswim:

def Data1 = close (GetSymbolPart (1));

def Data2 = close (GetSymbolPart (2));

def kf = close (GetSymbolPart (1)) [500];

def kff = close (GetSymbolPart (2)) [500];

def bn = BarNumber ();

def hbn = HighestAll (bn);

def bn_diff = hbn - bn;

def kf1 = GetValue (kf, -bn_diff);

def kf2 = GetValue (kff, -bn_diff);

def Data11 = (Data1 kf1-1) * 100;

def Data22 = (Data2 kf2-1) * 100;

def av1 = average (Data11, 50);

def av2 = average (Data22, 50);

def minus = sum (AbsValue (av1-av2), 450) / 450;

addLabel (yes, minus, color. cYAN);

З невідомих мені причин, у деяких користувачів не працює функція GetValue (), яка є невід'ємною частиною коду. Тому якщо у вас працює - відмінно, якщо ні - вам не пощастило (Сам код відображає у верхньому лівому кутку (див. Малюнок вище) значення t. value, при цьому в області для тікера акції повинна бути введена пара (ticker1-ticker2).

Ну ось власне і все, як фільтрувати пари математично, зберігаючи зір і нерви, я розповів, решта за вами:)

Коментарі, питання і критика вітаються. Чекаємо подальших випусків:)