Д.Катс.Д.Маккормик.Энциклопедия торговых стратегий. Донна л. Маккормик
Скачать 5.96 Mb.
|
ГЛАВА 10 Входы НА ОСНОВЕ циклов 239 В дополнение к данным, представленным на графиках, были проведе- ны другие тесты с использованием «плазмод». Плазмодой называют набор данных, подобранных так, чтобы содержать предполагаемые в реальных данных характеристики. Идея состоит в проверке того, насколько алго- ритм или модель может обнаружить и проанализировать эти характерис- тики. Хорошая торговая система на основе циклов должна проявлять вы- сокую эффективность на синтетической серии данных, состоящей из боль- шого количества шума и изредка встроенных циклов. Фильтры, описан- ные в следующих тестах, работали в такой ситуации очень хорошо. ПОЛУЧЕНИЕ ЦИКЛИЧЕСКИХ ТОРГОВЫХ СИГНАЛОВ ВХОДА С ИСПОЛЬЗОВАНИЕМ ГРУПП ФИЛЬТРОВ Одним из способов получения сигналов входа является использование серии фильтров, настроенных на различные частоты или периоды, кото- рые целиком перекрывают весь диапазон анализируемых частот. Если в одном из этих фильтров возникает сильный резонанс при отсутствии ак- тивности в других, можно предположить наличие на рынке сильного цик- ла. На основе поведения выходов фильтров определяются ожидаемые моменты возникновения ценовых минимумов (сигнал к покупке) и мак- симумов (сигнал к продаже). Поскольку наиболее сильно реагирующий фильтр не должен вызывать запаздывания и фазовых сдвигов, при его должной работе и реально существующих циклах на рынке можно полу- чать чрезвычайно своевременные сигналы. Один из традиционных спо- собов использования циклов на рынке — это попытка продавать по цик- лическим максимумам и покупать по циклическим минимумам. Получае- мая от групп фильтров или других источников информация может также дополнять другие системы или адаптировать индикаторы к текущему со- стоянию рынка. Пример того, как метод обнаружения периода домини- рующего цикла и соотношения сигнал/шум включается в другую торго- вую систему, можно найти у Ружжиеро (Ruggiero, 1997). ХАРАКТЕРИСТИКИ ЦИКЛИЧЕСКИХ ВХОДОВ Исследуемые ниже циклические входы (нацеленные на продажу по мак- симуму и покупку по минимуму) имеют ряд важных характеристик: вы- сокий процент прибыльных сделок, низкое проскальзывание, способность захватывать максимально возможную часть каждого движения рынка — одним словом, мечта трейдера. Это справедливо только при условии, что на рынке действительно существуют предсказуемые циклы, которые мож- но обнаружить и, что еще важнее, экстраполировать имеющимися мето- дами. Считается, что на рынках примерно 70% времени присутствует цик- 240 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК лическая активность. Даже если четкие циклы, ведущие к выгодным сдел- кам, возникают гораздо реже, использование близких защитных остано- вок позволяет сводить к минимуму потери от неудачных сделок. Главный недостаток циклических входов состоит в том, что ввиду широкого рас- пространения весьма мощных алгоритмов анализа циклов, например ме- тода максимальной энтропии, рынки изменили свою природу и стали «ме- нее уязвимыми» для подобных методов. Предсказуемые циклы обнару- живаются и нивелируются настолько быстро, что их исследования зачас- тую теряют смысл. Поскольку описываемые циклические входы по при- роде своей направлены против циклов, то при отсутствии продолжения циклов (т.е. при продолжении тренда) трейдер понесет потери, если не будут применены эффективные методы управления капиталом (защит- ные остановки). Пригодность к реальной работе сложных методик анали- за циклов и будет рассмотрена в наших тестах. МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ Во всех тестах циклических моделей входа используется стандартный портфель из 36 рынков. Количество контрактов для покупки или прода- жи на каждом рынке подбиралось для соответствия долларовой волатиль- ности двух контрактов S&P 500 на конец 1998 г. Использован стандарт- ный выход: защитная остановка закрывает любую позицию, убытки ко- торой превышают одну единицу волатильности. Кроме того, лимитный приказ закрывает позиции, прибыль которых превышает четыре едини- цы волатильности, а рыночный приказ по цене закрытия закрывает пози- ции, не закрытые предыдущими выходами в течение 10 дней. Правила входов рассмотрены в обсуждении модели и индивидуальных тестов. Все тесты проведены при помощи стандартного C-Trader toolkit. Ниже при- веден код модели, основанный на волновом фильтре со стандартной стра- тегией выходов: static void Model (float *parms, float *dt, float *opn, float *hi, float *lo, float *cls, float *vol, float *oi, float *dlrv, int nb, TRDSIM &ts, float *eqcls) { // Модели группы волновых фильтров // File = x14mod01.c // parms — набор [1..MAXPRM] параметров // dt - набор [l..nb] дат в формате ГГММДД // орn — набор [1..nb] цен открытия // hi — набор [1..nb] максимальных цен // 1о - набор [l..nb] минимальных цен // cls — набор [1..nb] цен закрытия // vol — набор [1..nb] значений объема // oi — набор [1..nb] значений открытого интереса // dlrv - набор [l..nb] средних долларовой волатильности / / nb — количество точек в наборе данных // ts - ссылка на класс торгового стимулятора ГЛАВА 10 Входы НА ОСНОВЕ циклов 241 // eqcls - набор [l..nb] уровней капитала по ценам закрытия // объявляем локальные переменные static int rc, cb, ncontracts, maxhold, ordertype, signal; static int disp, k, modeltype, fcount, goodcycle, domperndx; static float mmstp, ptlim, stpprice, limprice, tmp; static float width, oldwidth, lper, sper, per, ratio; static float exitatr[MAXBAR+1], **inphase, **inquad, **power; static float peakpower, phase, peaknoise, domperiod; static float buyphase, sellphase, phaseb, oldphase, oldphaseb; static WAVFILT filter[20]; // копируем параметры в локальные переменные для удобного обращения width = parms[l]; // ширина полосы пропускания фильтра (0.05 .. 0.20} disp= parms[2]; // временное смещение в градусах modeltype = parms[8]; // модель: 1=торговать развороты циклов ordertype = parms[9]; // вход: 1=на открытии, 2=по лимитному приказу, // 3=по стоп-приказу maxhold = 10; // период максимального удержания позиции ptlim = 4; // целевая прибыль в единицах волатильности mmstp = 1; // защитная остановка в единицах волатильности // Создаем искусственный набор цен закрытия в // форме синусоиды. Это «плазмода» для проведения тестов. // Модель должна хорошо торговать на данном наборе цен. // #define USESIMEWAVE #ifdef USESINEWAVE per = 3.0; ratio = exp (log (30.0/3.0) / (nb - 1)); sper=0.0; for (cb = 1; cb <= nb; cb++) ( sper += 2.0 * PI * (1.0 / per); cls[cb] = sin(sper); per *= ratio; } #endif // инициализируем группу равноотстоящих волновых фильтров // заново инициализируем, если параметр ширины полосы изменился if(width != oldwidth) { lper ==30.0; // фильтр длинных периодов sper = 3.О ; // фильтр коротких периодов fcount = 2 0 ; // число фильтров в группе ratio = exp (log (lper / sper) / (fcount - 1) ) ; per = sper; for(k = 1; k <= fcount; k++) ( filter[k-1].build_kernel(per, width); per *= ratio; } oldwidth = width; } // рассчитываем выходы фильтров и откорректированный спектр мощности // если матрицы (таблицы) пустые, то присваиваем им значения if(inphase == NULL) inphase = matrix(l,fcount,1,MAXBAR); if(inquad == NULL) inquad = matrix(1,fcount,l.MAXBAR); if(power == NULL) power = matrix(1,fcount,1.MAXBAR); for(k = 1 ; k <= fcount; k++) { filter[k-1] .apply (cls, inphase[k] , inquad[k], nb); for(cb = 1; cb <= nb; cb++) power [k] [cb] = (inphase [k] [cb] * inphase [k] [cb] + inquad [k] [cb] * inquad [k] [cb] ) / filter[k-1].period(); 242 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК } // сохраняем спектральный анализ выборки в файл // эта процедура проводится для отладки // #define WRITESAMPLE #ifdef WRITESAMPLE FILE *fil = fopen("test.dat", "wt"); for(cb = nb-1200; cb < nb; cb++) { domperndx = 0 ; peakpower = -1.0; for(k = 1; k <= fcount; k++) ( if(power[k][cb] > peakpower) { peakpower = power[k] [cb] ; domperndx = k; } ) phase = (180.0 / PI) * atan2 (inquad [domperndx] [cb] , inphase[domperndx] [cb]); for(k = 1; k <= fcount; k++) ( if (power [k] [cb] > 0.90 * peakpower) fprintf(fil, " **"); else if (power[k][cb] > 0.75 * peakpower) fprintf(fil, " ++"); else if (power[k][cb] > 0.5 * peakpower) fprintf(fil, " + "); else fprintf(fil, " "); ) fprintf(fil, "%4d %7d %7d %7d %8.1f\n", (int)filter[domperndx-1].period(), (int)(inphase[domperndx] [cb]), (int)(inquad[domperndx] [cb]), (int)phase, cls [cb]); } fclose(fil); exit(0); #endif // используется для отладки сигналов // #define SIGNALDEBUG #ifdef SIGNALDEBUG FILE *fil = fopen("testsig.dat" , "wt"); #endif // выполняем вычисления для всех данных AvgTrueRangeS(exitatr,hi,lo,cls,50,nb) ; // средний истинный диапазон для // выхода switch (modeltype) [ case 1: // Ничего не делайте! Место для будущего кода, break ; default: nrerror ("Invalid model type"); ) // проходим через дни, чтобы смоделировать реальную торговлю for(cb = 1; cb <= nb; cb++) { // не открываем позиций до начала периода выборки // ... то же самое, что установка MaxBarsBack в TradeStation if(dt[cb] < IS_DATE) 1 egcls[cb] = 0.0; continue; ) ГЛАВА 10 Входы НА ОСНОВЕ циклов 243 // выполняем ожидающие приказы и сохраняем значение капитала rc = ts.update (opn [cb] , hi [cb] , lo [cb] , cls [cb] , cb) ; if(rc != 0) nrerror{"Trade buffer overflow"); eqcls[cb] = ts.currentequity(EQ_CLOSETOTAL); / / н е торгуем в последние 30 дней выборки // оставляем место в массивах для будущих данных if(cb > nb-30) continue; // считаем количество контрактов для позиции // ... мы хотим торговать эквивалентом долларовой волатильности // ... 2 новых контрактов на S&P-500 от 12/31/98 ncontracts = RoundToInteger(5673 . О / dlrv[cb] ) ; if (ncontracts < 1) ncontracts = 1; // избегаем устанавливать приказы на дни с ограниченной торговлей if(hi[cb+1] == lo[cb+1]} continue; // генерировать входные сигналы, цены стоп- и лимитных приказов signal = 0; switch (modeltype) { case 1: // ищем хороший цикл для торговли domperndx = 0; peakpower = -1.0; for(k = 1; k <= fcount; k++) { if(power[k][cb] > peakpower) { peakpower = power[k][cb]; domperndx = k; } } goodcycle = FALSE; if(domperndx > 3 && domperndx < fcount-1) { peaknoise = 0.0; for(k = 1; k <= fcount; k++) { if (abs(k - domperndx) > 2) { if (power[k] [cb] > peaknoise) peaknoise - power[k] [cb] ; } } if(peakpower > 1.5 * peaknoise) goodcycle = TRUE; } // генерируем торговые сигналы if (goodcycle) { domperiod = filter [domperndx-1] .period() ; phase = (180.0 / PI) * atan2(inquad[domperndx] [cb], inphase[domperndx] [cb]); oldphase = (180.0 / PI) * atan2(inquad[domperndx] [cb-1], inphase[domperndx] [cb-1] ); phaseb - (phase<0.0) ? (360.0+phase) : phase; oldphaseb = (oldphase<0.0) ? (360.0+oldphase) : oldphase; sellphase = 0.0 - (disp + 180.0 / domperiod); buyphase = 180.0 + sellphase; if (phaseb > buyphase && oldphaseb <- buyphase) signal = 1; // сигнал на покупку if (phase > sellphase && oldphase <= sellphase) signal = -1; // сигнал на продажу } break; 244 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК } limprice = 0.5 * (hi [cb] + lo [cb] ) ; stpprice = cls[cb] + 0.5 * signal * exitatr[cb]; // печатаем отладочную информацию #ifdef SIGNALDEBUG fprintf(fil, "%8d %8.1f %8d %8d %8d %8d\n", cb, cls[cb], signal, (int)filter[domperndx-1].period(), (int)peakpower, {int)peaknoise); #endif // входим в сделку, используя определенный тип приказа if(ts.position() <= 0 && signal == 1) ( switch(ordertype) { // выбираем нужный вид приказа case 1: ts.buyopen('1', ncontracts); break; case 2: ts.buylimit ('2', limprice, ncontracts); break; case 3: ts.buystop('3', stpprice, ncontracts); break; default: nrerror("Invalid buy order selected"); } ) else if (ts.position() >= 0 && signal == -1) { switch(ordertype} { // выбираем нужный вид приказа case 1: ts.sellopen('4', ncontracts); break; case 2: ts.selllimit('5', limprice, ncontracts); break; case 3: ts.sellstop('6', stpprice, ncontracts); break; default: nrerror("Invalid sell order selected"); } } // симулятор использует стандартную стратегию выхода tmp = exitatr[cb]; ts.stdexitcls('X', ptlim*tmp, mmstp*tmp, maxhold); } // обрабатываем следующий день // закрываем, если в режиме отладки #ifdef SIGNALDEBUG fclose(fil); exit(0); #endif } Вышеприведенный код описывает тестируемую модель. Первый важ- ный блок кода, принципиальный для циклической модели, инициализи- рует индивидуальные фильтры, составляющие группу фильтров. Этот код работает только при первом проходе или при изменении параметра, вли- яющего на инициализацию группы фильтров, например параметра width. Если важные параметры остаются без изменений, не имеет смысла пере- запускать фильтры при каждом вызове функции Model. Следующий блок применяет к входящему сигналу каждый из фильт- ров в составе группы. В этом блоке отведены два массива для хранения выходного сигнала группы фильтров. Первый массив хранит выход с со- впадающей фазой inphase, а второй — ортогональный выход inquad. Вход- ной сигнал представляет исходные цены закрытия. Поскольку фильтры математически оптимальны и рассчитаны на удаление трендов, предва- ГЛАВА 10 Входы НА ОСНОВЕ циклов 245 рительная обработка данных становится излишней в отличие от менее продвинутых методик анализа. Каждая строка в массиве представляет собой выход отдельного фильтра с данной частотой или периодом, каж- дая колонка представляет собой торговый день. Центральные частоты или периоды фильтров расположены на равных расстояниях на логарифми- ческой шкале, т.е. соотношение между центральной частотой данного и следующего фильтра постоянно. Селективность полосы пропускания (width) — единственный настраиваемый параметр в расчете группы филь- тров, и это значение может подбираться путем оптимизации. Затем запускается обычный цикл перебора точек данных, и генери- руются собственно торговые сигналы. Сначала проверяется наличие чи- стого, пригодного для торговли цикла. Для этого определяется мощность при периоде, имеющем максимальный резонанс с текущей активностью рынка (peakpower). Также оценивается период, на котором наблюдается максимальная мощность. Если период не попадает на одно из крайних зна- чений рассматриваемого диапазона (диапазон составляет от 3 до 30 дней), то потенциально цикл может быть пригоден для торговли. Затем проверя- ется максимальная мощность на расстоянии не менее 2 полос пропуска- ния фильтра от периода пика (peaknoise). Если отношение peakpower/ peaknoise составляет 1,5 или более, то выполняется второе условие при- годности цикла. На основе пары выходов определяется фазовый угол цик- ла. Затем код проверяет фазовый угол на соответствие максимуму или минимуму цены. Кроме того, в эту оценку вводится небольшое значение смещения (disp). Оно работает подобно смещению в предыдущих моде- лях, хотя здесь относится к фазовому углу, а не к количеству точек дан- ных. Между фазовым углом и количеством точек данных существует пря- мая зависимость: период цикла, умноженный на фазовый угол в градусах и разделенный затем на 360, дает количество точек данных, соответству- ющее фазовому углу. Если фаза после смещения такова, что через неко- торое количество градусов до или после текущего дня можно ожидать минимума, отдается приказ на покупку. Если фаза такова, что можно ожи- дать максимума, отдается приказ на продажу. Затем, как обычно, рассчи- тываются цены для лимитного и стоп-приказов. При поступлении сигна- лов система исполняет требуемые приказы. Другие блоки вышеприведенного кода здесь не обсуждаются, посколь- ку связаны с отладкой и тестированием программы. Их предназначение описано в комментариях к коду. РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ Тестировалась только одна модель с входами по цене открытия (тест 1), по лимитному приказу (тест 2) и стоп-приказу (тест 3). Правила были про- стыми: покупать на предсказанных минимумах и продавать на предска- 246 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК занных максимумах. Выходы производились при поступлении сигнала к открытию противоположной позиции или при срабатывании стандарт- ного выхода. Эта простая торговая система сначала испытывалась на ис- кусственных ценовых данных, созданных путем добавления шума к иде- альной синусоиде с периодом от 4 до 20 дней. На этих данных были полу- чены сигналы покупки и продажи, идеально совпадающие с максимума- ми и минимумами. Такое совпадение показывает, что при наличии реаль- ных циклов система способна обнаруживать их с высокой точностью и использовать в торговле. В табл. 10-1 приведены лучшие показатели, полученные для данных, находящихся в пределах выборки, а также эффективность портфеля на данных в пределах и вне пределов выборки. В таблице: ВЫБ. — вид вы- борки данных (В — в пределах, ВНЕ — вне пределов выборки); ДОХ% — доходность в процентах годовых; Р/ПРИБ — соотношение риска/прибы- ли в годовом исчислении; ВЕР — ассоциированная вероятность статисти- ческой достоверности; СДЕЛ — число сделок на всех рынках в составе портфеля; ПРИБ% — процент прибыльных сделок; $СДЕЛ — средняя при- быль/убыток со сделки; ДНИ — средняя длительность сделки в днях; ПРИБДЛ — общая прибыль от длинных позиций в тысячах долларов; ПРИБКР — общая прибыль от коротких позиций в тысячах долларов. Оп- тимизировались два параметра. Первый (Р1) определяет ширину полосы пропускания для каждого фильтра в составе группы. Второй (Р2) отобра- жает фазовое смещение в градусах. Во всех случаях параметры прогоня- лись в пределах выборки для ширины полосы пропускания от 0,05 до 0,2 с шагом 0,05 и для фазового сдвига от —20 до +20° с шагом 10°. Показаны только оптимальные решения. Интересно отметить, что в общем циклическая модель имела доста- точно низкую эффективность. По показателю прибыли со сделки эта мо- дель превосходила многие рассмотренные ранее, но сильно уступала луч- шим из них. В пределах выборки убыток со сделки оставил $ 1329 при вхо- де по цене открытия, $1037 при входе по лимитному приказу и $1245 при входе по стоп-приказу. Вход по лимитному приказу обеспечил максималь- ный процент прибыльных сделок и минимальный средний убыток. Длин- ные позиции были слабо прибыльными при входе по цене открытия, бо- лее прибыльны при входе по лимитному приказу и убыточны при входе по стоп-приказу. Вне пределов выборки входы по лимитному приказу и цене открытия работали хуже, чем в пределах выборки. Средний убыток в сделке составил $3741 при входе по цене открытия и $3551 при входе по лимитному приказу. Доля прибыльных сделок также снизилась до 34%. Эффективность циклической модели вне пределов выборки была одной из худших среди всех моделей, что нельзя отнести на счет избыточной оптимизации: при других параметрах убытки были еще больше. При ис- пользовании входа по стоп-приказу эффективность вне пределов выбор- ки не ухудшалась, средний убыток ($944) в сделке был близок к убытку в |