Общие понятия Выбор брокера Анализ рынка Торговые стратегии Книги по Forex
Общие понятия
Биржа Форекс
Игра на бирже
Валютный трейдинг
Управление валютным портфелем
Как стать трейдером
Выбор брокера
Брокерское обслуживание
Как выбрать брокера Форекс
Лучшие дилинговые центры
Анализ рынка
Технический анализ
Японские свечи
Индикатор Ишимоку
Волны Вульфа
Полосы Боллинджера
Скользящие средние
Линия тренда
Фундаментальный анализ
Механические торговые системы
Оценка эффективности механических торговых систем
Торговые сигналы
Лучшие
дилинговые центры:
Дилинговый центр EXNESS
Дилинговый центр Forex4you
Дилинговый центр Alpari

Методология тестирования

Во всех тестах циклических моделей входа используется стандартный портфель из 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 - набор [1..nb] дат в формате ГГММДД
// орn — набор [1..nb] цен открытия
// hi — набор [1..nb] максимальных цен
// 1о - набор [1..nb] минимальных цен
// cls — набор [1..nb] цен закрытия
// vol — набор [1..nb] значений объема
// oi — набор [1..nb] значений открытого интереса
// dlrv - набор [1..nb] средних долларовой волатильности
// nb — количество точек в наборе данных
// ts - ссылка на класс торгового стимулятора
// eqcls - набор [1..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[1]; // ширина полосы пропускания фильтра (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 =20; // число фильтров в группе
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(1,fcount,1,MAXBAR);
if(inquad == NULL) inquad = matrix(1,fcount,1.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();
}
// сохраняем спектральный анализ выборки в файл
// эта процедура проводится для отладки
// #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; }
// выполняем ожидающие приказы и сохраняем значение капитала
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;
}
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. Входной сигнал представляет исходные цены закрытия. Поскольку фильтры математически оптимальны и рассчитаны на удаление трендов, предварительная обработка данных становится излишней в отличие от менее продвинутых методик анализа. Каждая строка в массиве представляет собой выход отдельного фильтра с данной частотой или периодом, каждая колонка представляет собой торговый день. Центральные частоты или периоды фильтров расположены на равных расстояниях на логарифмической шкале, т. е. соотношение между центральной частотой данного и следующего фильтра постоянно. Селективность полосы пропускания (width) — единственный настраиваемый параметр в расчете группы фильтров, и это значение может подбираться путем оптимизации.

Затем запускается обычный цикл перебора точек данных, и генерируются собственно торговые сигналы. Сначала проверяется наличие чистого, пригодного для торговли цикла. Для этого определяется мощность при периоде, имеющем максимальный резонанс с текущей активностью рынка (peakpower). Также оценивается период, на котором наблюдается максимальная мощность. Если период не попадает на одно из крайних значений рассматриваемого диапазона (диапазон составляет от 3 до 30 дней), то потенциально цикл может быть пригоден для торговли. Затем проверяется максимальная мощность на расстоянии не менее 2 полос пропускания фильтра от периода пика (peaknoise). Если отношение peakpower/peaknoise составляет 1,5 или более, то выполняется второе условие пригодности цикла. На основе пары выходов определяется фазовый угол цикла. Затем код проверяет фазовый угол на соответствие максимуму или минимуму цены. Кроме того, в эту оценку вводится небольшое значение смещения (disp). Оно работает подобно смещению в предыдущих моделях, хотя здесь относится к фазовому углу, а не к количеству точек данных. Между фазовым углом и количеством точек данных существует прямая зависимость: период цикла, умноженный на фазовый угол в градусах и разделенный затем на 360, дает количество точек данных, соответствующее фазовому углу. Если фаза после смещения такова, что через некоторое количество градусов до или после текущего дня можно ожидать минимума, отдается приказ на покупку. Если фаза такова, что можно ожидать максимума, отдается приказ на продажу. Затем, как обычно, рассчитываются цены для лимитного и стоп-приказов. При поступлении сигналов система исполняет требуемые приказы.

Другие блоки вышеприведенного кода здесь не обсуждаются, поскольку связаны с отладкой и тестированием программы. Их предназначение описано в комментариях к коду.

Далее

Вернуться к оглавлению

Торговые стратегии
Скальпинг
Стратегия "Середина"
Позиционная среднесрочная
Система ATCF
Стратегия по Moving Average, ADX и Фракталам
Стратегия разворотного периода
Стратегия "теней"
Стратегия "Серфинг"
Стратегия Trend Finder Daily
Стратегия на внутреннем баре
Скальпинг M1 GBPJPY
Стратегия "4 средних"
Торговая стратегия The Bat
Книги по Forex
А.Фарлей "Мастерство свинг-трейдинга"
B. Сафонов "Практическое использование волн Эллиотта в трейдинге"
Кац Дж.О., МакКормик Д.Л. "Энциклопедия торговых стратегий"
Лучшие
дилинговые центры:
Дилинговый центр EXNESS
Дилинговый центр Forex4you
Дилинговый центр Alpari
Торговые стратегии