МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ Во вс
Энциклопедия торговых стратегий














МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ Во вс

МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ Во всех тестах циклических моделей входа используется стандартный портфель из 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) { // 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]; ordertype = parms[9]; maxhold = 10; ptlim 4; mmstp = 1; // модель: 1=торговать развороты циклов // вход: 1=на открытии, 2=по лимитному приказу, // 3=по стоп-приказу // период максимального удержания позиции // целевая прибыль в единицах волатильности // защитная остановка в единицах волатильности // Создаем искусственный набор цен закрытия в // форме синусоиды. Это "плазмода" для проведения тестов. // Модель должна хорошо торговать на данном наборе цен. // #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 =20; // число фильтров в группе ratio = exp ( l o g (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 ] [ c b ] = (inphase [ k ] [ c b ] * inphase [ k ] [cb] + inquad [k] [cb] * inquad [ k ] [cb] ) / filter[k-1].period(); } // сохраняем спектральный анализ выборки в файл // эта процедура проводится для отладки // #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] [ c b ] ; 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; ) // выполняем ожидающие приказы и сохраняем значение капитала re = ts.update (opn [cb] , hi [cb] , lo [cb] , els [cb] , cb) ; if(re != 0) nrerrorl"Trade buffer overflow"); eqcls[cb] = ts.currentequity(E^CLOSETOTAL) ; //не торгуем в последние 30 дней выборки // оставляем место в массивах для будущих данных if(cb > nb-30) continue; // считаем количество контрактов для позищии // ... мы хотим торговать эквивалентом долларовой волатильности // ... 2 новых контрактов на S&P-500 от 12/31/98 ncontracts = RoundToInteger(5673 .0 / dlrv[cb] ) ; if (ncontracts < 1) ncontracts = 1; // избегаем устанавливать приказы на дни с ограниченной торговлей if(hi[cb+l] == lo[cb+l]} 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; 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 } Назад

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
Hosted by uCoz