Д.Катс.Д.Маккормик.Энциклопедия торговых стратегий. Донна л. Маккормик
Скачать 5.96 Mb.
|
ГЛАВА 9 ЛУННЫЕ и СОЛНЕЧНЫЕ РИТМЫ 209 при этом должен быть ниже 25%, т.е. рынок должен находиться в состоя- нии, близком к минимуму за последнее время. Соответственно, если сис- тема дает сигнал на продажу, то Медленный %К должен быть выше 75%, чтобы считать поведение рынка соответствующим лунной модели. Мо- дель с подтверждением и инверсией также вводит правило инверсии при- каза: если подается сигнал на покупку в то время как рынок близок к мак- симуму (Медленный %К выше 75%), то считается, что произошла инвер- сия лунной модели, и отдается сигнал на продажу. Если сигнал на прода- жу подается в момент, когда рынок близок к минимуму, то система отдает приказ на покупку. Характеристики входов, используемых в моделях на лунном цикле, подобны входам сезонных моделей: входы в рынок делаются на основе прогнозирования и, следовательно, пригодны для торговли против трен- да. Как и любые прогностические входы, они могут не совпадать с пове- дением рынка. Как и в случае с сезонными явлениями, могут происхо- дить инверсии ритма или цикла. МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ ЛУННЫХ МОДЕЛЕЙ Все тесты проводились с использованием входов по сигналам лунной мо- дели для торговли портфелем различных финансовых инструментов. Можно ли получить прибыль, используя лунную модель? Как результа- тивность подобных моделей будет изменяться со временем? Как измени- лись их результаты за последние годы? Для того чтобы ответить на эти вопросы, и было проведено тестирование. Применены стандартные выходы, правила входов будут рассмотрены при обсуждении отдельных тестов. Позиции закрываются при подаче сигнала на вход в противоположном направлении либо при срабатыва- нии стандартного выхода. В приведенном ниже коде описана модель вхо- да на основе лунных циклов. int LunarEventDates (int n) { // подсчитывает дату лунной фазы, начиная // с января 1900. // n - ввод: номер фазы луны // 0,4,8... новолуния // 1,5,9... луна в первом квартале // 2,6,10... полнолуние / / 3,7,11... луна во втором квартале //возвращает - вывод: дата события по юлианскому календарю static long ndate; static float timzon = -5.0 / 24.0; // восточное стандартное время static float fгас; flmoon {n >> 2, n & 3, &ndate, &frac); frac = 24.0 * {frac + timzon); 210 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК if(fгас < 0.0) { // корректировка времени ndate—; frac += 24.0; ) if(frac > 12.0) ( ndate++; frac -= 12.0; ) else frac += 12.0; return ndate; // юлианская дата события } int LunarEquivDate (int date, int n) ( // рассчитываем дату предыдущего n-го (n < 0) или // будущего (n > 0) случая фазы луны, равной // сегодняшней фазе // date - ввод: текущая дата в формате ГГГММДД // n - ввод: лунные циклы назад{-) или вперед (+) // return - вывод: дату предыдущего или будущего цикла в формате ГГГММДД static long nstar, ndatel, ndate2, curdate, ntarg, nans; static int mm, dd, yyyy; curdate = julday((date/100)%100, date%10O, 1900+date/lOOOO); while(curdate >= ndate2) { ndatel = LunarEventDates(++nstar); ndate2 = LunarEventDates(nstar + 1) ; } while(curdate < ndatel) { ndatel - LunarEventDates{—nstar); ndate2 = LunarEventDates(nstar + 1); } if(curdate < ndatel || curdate >= ndate2 || abs(ndate2 - ndatel - 7) > 2) nrerror("LunarEquivDate: calculation error"); nans = LunarEventDates(nstar +4 * n); nans += (curdate - ndatel); caldatfnans, &mm, &dd, &yyyy) ; return 10000*(yyyy-1900) + 100*mm + dd; } void LunarAvg (float *a, float *v, float *dt, int mode, int m, int n) { // Подсчитываем лунное (в зависимости от даты и фазы) скользящее среднее // для каждого дня, основанное на предыдущих днях и (в некоторых случаях) // на последующих днях с эквивалентной лунной фазой. // Работаем на всех имеющихся данных. / / а - вывод: значения [1..n] лунного среднего / / v - ввод: исходный ценовой ряд данных [1..n] // dt - ввод: соответствующие [1..n] данные // mode - ввод: метод анализа: // 1 = «складной нож» IS, все прошлые циклы 008 // 2 - фиксированный период в лунных циклах //m - ввод: дата (для режима - 1) или период анализа (для режима = 2) // n - ввод: количество дней во всех рядах static int i, j, cnt; static unsigned long k; static float sum, sdate, tiny=l.OE-20; if(mode == 1) { // режим «складного ножа» ГЛАВА 9 ЛУННЫЕ и СОЛНЕЧНЫЕ РИТМЫ 211 for(i = 1; i <= n; i++} { // для каждого текущего дня sum = 0.0; cnt = 0; for(j = 2; j < 1000; j++) { // двигаемся назад sdate - LunarEquivDate {dt[i] , -j ) ; / / к исходной дате if(sdate < dt[3]) break; // переход к началу hunt(dt, n, sdate, &k) ; // находим индекс if (sdate > dt[k]) k++; cnt++; sum += v[k] ; // накапливаем среднюю } for(j = 2; j < 1000; j ++) { // двигаемся вперед sdate = LunarEquivDate {dt[i], j); / / к исходной дате if(sdate > m) break; // избегаем данных oos hunt(dt, n, sdate, &k); // находим индекс if(sdate > dt[k]) k++; cnt++; sum +- v[k]; // накапливаем среднюю } a[i] = sum / (cnt + tiny); // заканчиваем среднюю ) // следующий день } else if(mode == 2) { // режим фиксированного периода анализа for(i = 1; i <= n; i ++) { // для каждого текущего дня sum =0.0; cnt = 0; for(j = 2 ; j < 1 0 0 0 ; j + + ) { // двигаемся назад if(cnt >= m) break; // выполняем достаточные условия sdate = LunarEquivDate(dt[i] , -j); // исходная дата if (sdate < dt[3]) break; // идем к началу hunt(dt, n, sdate, &k); // находим индекс if{sdate > dt[k]} k++; cnt++; sum +- v[k]; // накапливаем среднюю } for(j = 2; -j < 1000; j++) { // двигаемся вперед if (cnt >= m) break; // выполняем достаточные условия sdate = LunarEquivDate(dt[i] , j ) // исходная дата hunt(dt, n, sdate, &k) ; // находим индекс if (sdate > dt[k]} k++; cnt++; sum += v[k]; // накапливаем среднюю } a[i] = sum / (cnt + tiny) // заканчиваем среднюю } // следующий день } } 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 = xl3modOl.c // parms — набор [1..MAXPRM] параметров // dt — набор [l..nb] дат в формате ГГММДД // орn — набор [1..nb] цен открытия // hi - набор [l..nb] максимальных цен // 1о — набор [1..nb] минимальных цен // cls — набор [l..nb] цен закрытия // vol - набор [l..nb] значений объема // oi — набор [1..nb] значений открытого интереса // dlrv — набор [1..nb] средних долларовых волатильностей / / nb — количество дней в наборе данных // ts — ссылка на класс торгового симулятора // eqcls — набор [1..nb] уровней капитала по ценам закрытия // объявляем локальные переменные static int rc, cb, ncontracts, maxhold, ordertype, signal; static int avglen, disp, k, modeltype, matype, mktindx; static float mmstp, ptlim, stpprice, limprice, tmp, thresh; static float exitatr[MAXBAR+1] , savg[MAXBAR+1] ; 212 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК static float mal[MAXBAR+1], ma2[MAXBAR+1], stoch[MAXBAR+1]; static float *exitatrtab[MAXMKT+1], *savgtab[MAXMKT+1] ; //копируем параметры в локальные переменные avglen = parms[1]; // период скользящей средней disp = parms[2]; // множитель смещения thresh = parms[3]; // порог для импульсных моделей matype = parms[7]; // тип средней: // 1=простое скользящее среднее // 2=экспоненциальное // 3=треугольное с переднем взвешиванием // 4=треугольное // 5=простое центрованное // 6=экспоненциальное центрованное // 7=треугольное центрованное modeltype = parms[8]; // тип модели: // 1=импульс // 2=пересечение // 3-пересечение с подтверждением // 4=пересечение с подтверждением и инверсией ordertype = parms[9]; // вход: 1=на открытии, 2=по лимитному приказу, // 3 =по стоп-приказу maxhold = 10; // период максимального удержания позиции ptlim = 4; // целевая прибыль в единицах волатильности mmstp = 1; // защитная остановка в единицах волатильности // Выполняем вычисления по всему объему данных, которые не подвержены // воздействию каких-либо параметров. Выполняется один раз для каждого // рынка, результаты сохраняются в таблицах для повторного использования. // Таким образом, значительно снижается время выполнения программы. mktindx = ts.modelf) ; // индекс рынка if (exitatrtab[mktindx] == NOLL) { // размещен? exitatrtab[mktindx] = vector(1, nb); // таблица exitatr savgtab[mktindx] = vector{1, nb); // таблица savg AvgTrueRangeS(exitatrtab[mktindx], hi, lo, cls, 50, nb); //50-дневный средний истинный // диапазон float *pchg = vector(1, nb); // вспомогательный вектор pchg[l] = 0.0; for(cb =2; cb < = nb; cb++) { tmp = cls [cb] - els [cb-1]; // изменение цены tmp /= exitatrtab[mktindx] [cb]; // нормирование pchg [cb] = clip(tmp, -2.0, 2.0); // обрезание } LunarAvg(savgtab[mktindx], pchg, dt, 2, 60, nb); // лунная сезонность free_vector(pchg, 1, nb); printf {"Mkt: %d\n", mktindx}; // показывать прогресс } // выполняем вычисления для всех данных memcpy(exitatr, exitatrtab[mktindx] , sizeof (float)*nb); memcpy(savg, savgtab[mktindx], sizeof(float)*nb); switch(modeltype) { case 1: // данные для импульсной модели MovAvg{savg,savg,matype,avglen,nb) ; // сглаживающее среднее for(cb = 1; cb <= nb; cb++) ma2 [cb] = fabs(savg[cb]} ; MovAvg (mal, ma2, 1, 100, nb) ; // среднее отклонение break; case 2: case 3: case 4: // данные для моделей пересечения for(cb = 2; cb <= nb; cb++) savg[cb] += savg [cb-1]; // интеграция MovAvg(mal,savg,matype,avglen,nb); // сглаж. средн. MovAvg(ma2,mal,matype,avglen,nb}; // пересеч. средн. if (modeltype == 3 | | modeltype == 4) // стохастический осц. ГЛАВА 9 ЛУННЫЕ и СОЛНЕЧНЫЕ РИТМЫ 213 StochOsc(stoch,hi,lo,cls,1,9,nb); // 9-дневный Быстрый %К break; default: nrerror("TRAPSMOD: invalid modeltype"); } // проходим через дни, чтобы смоделировать реальную торговлю for(cb = I; cb <= nb; cb++) { // не открываем позиций до периода выборки // ... то же самое, что установка MaxBarsBack в TradeStation if(dt[cb] < IS_DATE) { egcls[cb] = 0.0; continue; } // выполняем ожидающие приказы и считаем кумулятивный капитал 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); / / не проводим сделок в последние 3 0 дней выборки. // для того, чтобы оставить место в массивах для будущих сезонностей if(cb > nb-30) continue; // считаем количество контрактов для позиции // ... мы хотим торговать эквивалентом долларовой волатильности // ... 2 новых контрактов на S&P-500 от 12/31/98 neontracts = RoundToInteger(5673.О / dlrv[cb]}; if(ncontracts < 1) ncontracts = 1; // избегаем устанавливать приказы на дни с ограниченной торговлей if(hi[cb+1] == lo[cb+1]) continue; // генерируем входные сигналы, цены стоп- и лимитных приказов // для всех моделей signal = 0 ; switch(modeltype) { case 1: // основная модель входа на основе импульса с порогом k = cb + disp; tmp = thresh * mal[k] ; if(savg[k] > tmp && savg[k-l] <= tmp) signal = 1; else if(savg[k] < -tmp && savg[k-l] >= -tmp) signal = -1; break; case 2 : // основная модель пересечения k = cb + disp; if (CrossesAbove (mal, ma2 , k) } signal = 1 ; else if (CrossesBelow{mal, ma2, k)} signal = -1; break; case 3: // пересечение с подтверждением k = cb + disp; if(CrossesAbove{mal, ma2, k)) { if(stoch[cb] < 25.0) signal = 1; } else if {CrossesBelow(mal, ma2, k)) { if(stoch[cb] > 75.0} signal = -1; } break; case 4 : // пересечение с подтверждением и инверсией k = cb + disp; if{CrossesAbove(mal, ma2, k)) { if (stoch[cb] < 25.0) signal = 1; else if{stoch[cb] > 75.0} signal = -1; } else if (CrossesBelow (rnal, ma2 , k) } { if (stoch[cb] > 75.0) signal = -1; else if (stoch[cb] < 25.0} signal = 1; } break; 214 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК Собственно коду предшествует ряд функций, необходимых для рас- чета лунных циклов на любом рынке с адаптивным подходом. Функция Model следует стандартным принципам: после объявления параметры копируются в местные переменные для простоты обращения. Коммен- тарии указывают, что контролируют параметры. В следующем блоке рас- считывается средний истинный интервал за 50 дней (exitatrtab), исполь- зуемый в выходах и при нормализации, а также лунные сезонные пос- ледовательности (savgtab) — прогнозируемые изменения цены для каж- дого дня. Эти ряды рассчитываются один раз для каждого рынка и зано- сятся в таблицы; это допустимо, поскольку при повторных вызовах Model в последующих тестах никакие важные параметры не изменяются. Вто- рой блок рассчитывает специфические для моделей временные после- довательности, необходимые для получения сигналов входа. Если modeltype = 1, используется простая импульсная модель; если modeltype = 2, то модель на основе пересечения; если modeltype = 3, то модель на основе пересечения с подтверждением, и если modeltype = 4, то модель на основе пересечения с подтверждением и инверсией. Среди возмож- ных серий есть такие варианты, как сглаженная последовательность лун- ных импульсов, интегрированные импульсы (ценоподобный ряд), сколь- зящие средние для моделей на пересечении и Медленный %К для под- тверждений и инверсий. В зависимости от modeltype могут приобретать значение некоторые другие параметры. Один из них, avglen, управляет периодом всех скользящих средних: в модели на основе импульса он ) limprice = 0.5 * (hi [cb] + lo [cb] ) ; stpprice = cls[cb] + 0.5 * signal * exitatr[cb] ; // входим в сделку, используя определенный тип приказа if (ts.position{) <= 0 && signal == 1) { switch(ordertype) { // select desired order type 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); } // обрабатываем следующий день } ГЛАВА 9 ЛУННЫЕ и СОЛНЕЧНЫЕ РИТМЫ 215 управляет длиной центрированного треугольного скользящего средне- го, а в моделях на пересечении — длиной необходимых там средних. Другой параметр, disp, выставляет смещение, т.е. степень сдвига вперед для компенсации запаздывания скользящих средних. Параметр thresh означает величину порога, используемого в импульсной модели для длин- ных и коротких позиций (короткие используют отрицательное значе- ние thresh). Переменная matype управляет видом скользящего среднего: 1 — простое, 2 — экспоненциальное, 6 — центрированное экспоненци- альное, 7 — центрированное треугольное; существуют и другие виды средних, не использованные в анализе. После расчета всех рядов дан- ных запускается цикл, который перебирает рыночные цены день за днем для моделирования торговли. Этот цикл содержит код для обновления симулятора, определения количества контрактов, избежания дней с ог- раниченной торговлей и т.п. В следующем блоке, расположенном внут- ри блока перебора текущих дней, происходит генерация сигналов вхо- да. Правила определяются параметром modeltype. Последний блок уп- равляет отдачей соответствующих приказов согласно параметру ordertype: 1 — вход по цене открытия, 2 — по лимитному приказу, 3 — по стоп-приказу. Результаты тестирования лунных моделей Проводилось тестирование четырех моделей: на основе пересечения, импульса, пересечения с подтверждением и пересечения с подтвержде- Таблица 9—1. Эффективность лунных моделей, распределенная по модели, виду приказа и выборке Модель Лунное пересечение Лунный импульс Пересечение с подтвержд. Пересечение с подтвержд. и инверсией Среднее В пределах выборки Открытие Лимитный Стоп- приказ приказ -9,3 -6,0 -5,6 -1287 -406 -686 -10,1 -9,9 -8,1 -2410 -1560 -1288 -8,1 -6,6 1,8 -1251 -655 234 -9,4 -10,0 -7,8 -1546 -1078 -998 -9,3 -8,1 -4,9 -1624 -925 -685 Вне пределов выборки Открытие Лимитный Стоп- приказ приказ -14,3 -10,2 -10,4 -894 -643 -702 -14,8 -19,7 -8,3 -1316 -1942 -372 -20,5 -21,3 -18,6 -3465 -3896 -2449 -20,6 -20,9 -20,1 -2937 -3203 -2995 -17,6 -18,0 -14,4 -2153 -2421 -1630 Среднее В пределах -7.0 -793 -9,4 -1753 -4,3 -557 -9,1 -1207 -7,4 -1078 Среднее Вне пределов -11,6 -746 -14,2 -1210 -20,1 -3270 -20.5 -3405 -16,6 -2068 216 ЧАСТЬ II ИССЛЕДОВАНИЕ входов в РЫНОК Таблица 9—2. Эффективность в пределах выборки по тестам и рынкам нием и инверсией. Каждая модель тестировалась с входами по цене от- крытия, по лимитному приказу и по стоп-приказу. В табл. 9-1 приведены все результаты, распределенные по виду выборки, приказу и модели. Для каждой модели даны ряд значений, содержащий годовую доходность пор- тфеля, и ряд значений средней прибыли или убытка в сделке. В двух пра- вых столбцах — средние по всем видам приказов в пределах и вне преде- |