|
|
МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ
Во всех нижеследующих тестах использован стандартный портфель. Количество
контрактов при покупке или продаже при входе на любом рынке
в любое время подбиралось так, чтобы приблизительно соответствовать
долларовой волатильности двух контрактов S&P 500 на конец 1998 г.
Использованы стандартные выходы. Все тесты проведены с использованием
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 = xlOmodOl.c
// parms — набор [1..MAXPRM] параметров
// dt — набор [l..nb] дат в формате ГГММДД
// орn — набор [l..nb] цен открытия
// hi — набор [1..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, fastmalen,slowmalen;
static int modeltype, ordertype, avgtype, signal;
static float mmstp, ptlim, stpprice, limprice, tmp;
static float exitatr[MAXBAR+1] ;
static float fastma[MAXBAR+1] , slowma[MAXBAR+1] ;
// копируем параметры в локальные переменные для более удобного обращения
fastmalen = parms[1]; // период для быстрой скользящей средней
slowmalen = parms[2]; // период для медленной скользящей средней
modeltype - parms[5]; // тип модели входа
avgtype = parms[6]; // тип скользящего среднего
ordertype = parms[7]; // тип входного приказа
maxhold = 10; // максимальный период удержания позиции
ptlim = 4; // целевая прибыль в единицах волатильности
mmstp = 1; // защитная остановка в единицах волатильности
// пропускать неверные комбинации параметров
if(fastmalen >= slowmalen) {
set_vector(eqcls, 1, nb, 0.0);
return;
}
// делаем вычисления по всему ряду данных, используя векторизацию
AvgTrueRangeS(exitatr, hi, lo, cls, 50, nb); // средний истинный
// диапазон для выхода
switch(avgtype) { // выбираем тип скользящей средней
case 1: // простые скользящие средние
Averages{fastma, cls, fastmalen, nb);
Averages(slowma, cls, slowmalen, nb);
break;
case 2: // экспоненциальные скользящие средние
XAverageS(fastma, cls, fastmalen, nb);
XAverageS(slowma, cls, slowmalen, nb);
break;
case 3: // треугольные скользящие средние с передним взвешиванием
FWTAverageS(fastma, cls, fastmalen, nb};
FWTAverageS(slowma, cls, slowmalen, nb);
break;
case 4: // VIDYA-адаптивные скользящие средние
VIAverageS(fastma, cls, fastmalen, 10, nb) ;
VIAverageS(slowma, cls, slowmalen, 10, nb) ;
break;
default: nrerror("Invalid moving average selected");
} ;
// проходим через дни, чтобы смоделировать реальную торговлю
for(cb =1; cb <= nb; cb++) {
//не входим в сделки до начала периода выборки
// ...так же, как установка MaxBarsBack в Trade Station
if (dt[cb] < IS_DATE} { eqcls [cb] = 0.0; continue;)
// выполняем все ожидающие приказы и подсчитываем капитал по закрытым
// сделкам
гс = ts.update (opn [cb] , hi [cb] , lo [cb], cls [cb] , cb) ;
if (rc = 0) nrerror("Trade buffer overflow");
eqcls[cb] = ts.currentequity(EQ_C1OSETOTAL);
// подсчитываем количество контрактов для сделки
// ... мы хотим торговать эквивалентом долларовой волатильности
// ... 2 новых контрактов S&P-500 от 12/31/98
ncontracts = RoundToInteger(5673.0 / dlrv[cb]);
if(ncontracts < 1) ncontracts = 1;
// избегаем установки приказов на день, когда остановлены торги
if (hi[cb+1] == lo [cb+1]) continue;
// генерировать входные сигналы, цены стоп- и лимитных приказов,
// используя модель входа определенной скользящей средней
#define CrossesAbove(a,b, с) {а[с]>=b[с] && a [c-1]#define CrossesBelow(a,b,c) {a[c]=b[c-1])
#define TurnsUp(a,c) {a [c]>=a[c-l] && a [c-1]#define TurnsDn(a,c) {a[c]=a[c-2] )
signal=0;
switch(modeltype) {
case 1: // классическая следующая за трендом модель, основанная на
// пересечении
if (CrossesAbove(fastma, slowma, cb)) signal = 1;
else if (CrossesBelow(fastma, slowma, cb)) signal = -1;
limprice = 0.5 * (hi [cb] + lo [cb]);
stpprice = cls [cb] +0.5 * signal * exitatr[cb] ;
break;
case 2: // следующая за трендом модель, основанная на наклоне
if (TurnsUp(fastma, cb)) signal = 1;
else if(TurnsDn{fastma, cb)) signal = -1;
limprice = 0.5 * (hi[cb] + lo [cb]};
stpprice = cls[cb] +0.5 * signal * exitatr[cb];
break;
case 3: // противотрендовая модель
if(CrossesAbove(fastma, slowma, cb)) signal = -1 ;
else if(CrossesBelow(fastma, slowma, cb)) signal = 1;
limprice = 0.5* (hi[cb] + lo[cb]);
stpprice = cls[cb] + 0.5 * signal * exitatr[cb];
break;
case 4: // противотрендовая модель, основанная на поддержке
// и сопротивлении
if(slowma[cb] > slowma[cb-1]
&& CrossesBelow(fastma, slowma, cb) ) signal = 1;
else if(slowma[cb] < slowma[cb-1]
&& CrossesAbove(fastma, slowma, cb)) signal = -1;
limprice = 0.5 * (hi[cb] + lo[cb]);
stpprice = cls[cb] +0.5 * signal * exitatr[cb];
break;
default: nrerror("Invalid model selected"};
}
#undef CrossesAbove
#undef CrossesBelow
#undef TurnsUp
#tundef TurnsDn
// входим в сделку, используя опеределенный тип приказа
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);
} // обрабатываем следующий день
}
В этом коде содержатся три сегмента. Первый сегмент рассчитывает
скользящие средние. Параметр avgtype выбирает вид среднего: 1 — простое,
2 — экспоненциальное, 3 — треугольное с передним взвешиванием,
4 — модифицированное VIDYA. Даже если в коде использовано всего одно
среднее, рассчитываются два одинаковых, чтобы сделать выбор вида
скользящего среднего независимым от модели. Также рассчитывается
средний истинный диапазон, значение которого требуется для установки
защитных остановок и целевых прибылей в стратегии стандартных выходов.
Два дополнительных параметра — fastmalen и slowmalen — указывают
период быстрой и медленной скользящих средних. Значения скользящих
средних сохраняются в векторах fastma и stowma.
Следующий блок использует выбранную модель для получения сигналов
выхода, цен для стоп-приказов и цен для лимитных приказов. Сначала определяются простые соотношения значений (CrossesAbove,
CrossesBelow, Turnsllp и TurnsDown). В зависимости от mode/type одна из
4 видов моделей скользящих средних генерирует сигнал. Переменная
modeltype принимает следующие значения: 1 — классическая, следующая
за трендом модель пересечения двух скользящих средних; 2 — следующая
за трендом модель, основанная на наклоне; 3 — противотрендовая
модель, основанная на пересечении и 4 — противотрендовая модель на
основе поддержки/сопротивления. В классической модели, основанной
на пересечении скользящих средних, трейдер открывает длинную позицию,
если быстрое среднее поднимается выше медленного, и короткую,
если быстрое среднее опускается ниже медленного. Эта модель также
может содержать сравнение скользящего среднего и цены в случае, когда
период быстрого среднего приравнен к единице. При использовании основанной
на наклоне модели, следующей за трендом, трейдер покупает,
когда скользящее среднее после снижения стало расти, и продает в обратной
ситуации. Эта модель требует только медленного скользящего
среднего. Противотрендовая модель представляет собой обратную версию следующей за трендом классической модели пересечения: трейдер
покупает, когда быстрое среднее (или собственно цена) опускается ниже
медленного, и продает, когда оно поднимется выше. Такая модель — мечта
для приверженцев теории противоположного мнения: она работает
строго противоположно системе следования за трендом. Последняя модель
— грубая система на основе поддержки/сопротивления, где ожидается,
что цены будут «отскакивать» от линии скользящего среднего, как
от уровней поддержки/сопротивления. Правила почти идентичны противотрендовой
системе пересечения за тем исключением, что медленное
среднее должно двигаться в направлении входа. Если медленное скользящее
среднее стремится вверх, а цены (или быстрое среднее) падают сверху
до его уровня или ниже, то дается сигнал на покупку; в противном случае
дается сигнал на продажу. Дополнительное правило тренда обеспечивает
защиту от немедленного разворота позиции после соприкосновения или
пересечения средних. Без этого ограничения быстрый пробой с последующим
разворотом вызвал бы два входа — желаемый вход против тренда
и второй при пересечении средней во время отката цен. Контроль тренда
позволяет входить только при движении в одном направлении: пересечение
и отскок при повышающемся тренде приводят к открытию длинной
позиции, а при понижающемся тренде — к открытию короткой.
В последней части кода параметр ordertype определяет вид приказа:
1 — рыночный приказ при открытии; 2 — лимитный приказ; 3 — стопприказ.
Генерация приказа на покупку или продажу либо отсутствие приказа
определяется тем, какой сигнал был сгенерирован предыдущим блоком
программы; эта информация содержится в переменной signal: 1 —
покупка; —1 — продажа (открытие короткой позиции); 0 — нет приказа.
Уровень цены лимитного приказа (limprice) рассчитывается как сумма максимума и минимума текущего дня, деленная на два. Поскольку многие
из моделей не имеют естественного уровня цены для установки входных
стоп-приказов, используется стандартный стоп. Его цена (stpprice)
получается таким образом: берется цена закрытия предыдущего дня и к
ней прибавляется (при сигнале для длинной позиции) или от нее отнимается
(при сигнале для короткой позиции) средний истинный интервал за
последние 50 дней, умноженный на 0,50; т.е. рынок должен сместиться
как минимум на половину среднего дневного движения в направлении
желаемого входа, чтобы этот вход имел место. Такой стоп-приказ как бы
добавляет методику пробоя к скользящим средним — рынок должен «пробить» некоторую границу, чтобы сработал вход. Поскольку тестов проводилось
множество, мы приводим только наиболее интересные результаты
статистического анализа.
Знаете ли Вы, что: через компанию «Just2Trade» Вы можете получить прямой доступ к мировому рынку облигаций (доступны US Treasuries, российские еврооблигации, облигации Газпрома и многие другие) с низкими комиссиями и минимальным депозитом – от $3 тыс.
|
|