d9e5a92d

Тестирование динамических защитных остановок

В этой группе тестов мы заменим фиксированную защитную остановку МССВ на динамическую, предположительно более эффективную. Целью является фиксация основной части потенциальной прибыли, избегая при этом превращения потенциально выгодных сделок в убыточные, как это может иметь место в случае слишком близко расположенной фиксированной остановки.
Существует много способов перемещать защитную остановку так, чтобы ее уровень следовал за рынком, фиксируя часть возникающей в течение сделки прибыли. Один из популярных методов состоит в размещении остановки на уровне минимального минимума за несколько предыдущих дней (для длинных позиций). Затем остановка может перемещаться вверх (но не вниз). Для коротких позиций защитная остановка размещается на уровне максимального максимума за несколько предыдущих дней и может двигаться только вниз, но не вверх. Этот простой метод испытывается в первом тесте.
Второй тест динамической защитной остановки похож на методику подгонки фиксированной защитной остановки в МССВ. Уровень смещается вверх (для длинных позиций) или вниз (для коротких позиций) от текущей цены на некоторое количество средних истинных диапазонов. В отличие от фиксированной защитной остановки, использованной в МССВ, в данном случае защитная остановка перемещается в зависимости от текущей рыночной цены. Смещение может происходить только в одну сторону — вверх для длинных позиций, вниз для коротких. Целью является поддержание одинакового статистического расстояния между наилучшей ценой, достигнутой во время удержания позиции, и защитной остановкой. Защитная остановка для длинных позиций рассчитывается следующим образом: (1) Из цены входа вычитается параметр mmstp, умноженный на средний истинный диапазон. Результат будет уровнем защитной остановки для следующего дня. (2) На следующей день из текущей цены вычитается другой параметр stpa, умноженный на средний истинный диапазон. (3) Если цена защитной остановки, полученная на шаге 2, выше ценового уровня текущей защитной остановки, то текущее значение защитной остановки заменяется вычисленным. (4) Стадии 2 и 3 повторяются для каждого последующего дня. При расчете защитной остановки для короткой позиции произведение среднего истинного диапазона на параметр (mmstp или stpa.} прибавляется к рыночной цене, и уровень защитной остановки опускается вниз.
В третьем тесте использован более сложный подход. Для длинных позиций, как обычно, защитная остановка задается на уровне некоторого количества средних истинных диапазонов ниже цены входа в рынок. Затем остановка смещается вверх на величину, зависящую от того, насколько текущая цена выше текущего уровня защитной остановки. Для коротких позиций уровень остановки задается выше цены входа и опускается в зависимости от того, насколько текущая цена ниже его. В принципе этот метод основывается на варианте смещенного экспоненциального скользящего среднего (ЭСС), за тем исключением, что величина скользящего среднего инициализируется отдельным условием при входе в сделку и может изменяться только в одном направлении (так как защитная остановка может двигаться только в направлении рыночной цены). Защитная остановка для длинных позиций рассчитывается нижеследующим образом: (I) Начальное значение в день входа в рынок задается вычитанием из цены входа произведения параметра mmstp и среднего истинного диапазона. (2) На следующий день от максимальной цены отнимается произведение параметра stpa и среднего истинного диапазона; затем вычитается текущее значение защитной остановки и результат умножается на параметр stpb. (3) Если результат шага 2 больше нуля, добавляем его к текущему значению защитной остановки, если нет, то уровень не изменяется.
(4) Повторяем шаги 2 и 3 для каждого последующего дня. При вычислении защитной остановки для коротких позиций произведения среднего истинного диапазона на параметры прибавляются к рыночной цене. К уровню защитной остановки прибавляются только отрицательные поправки.

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 = x20mod02.c
// parms — набор [1..MAXPRM] параметров
// dt - набор [l..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, signal, ranseed;
static float stpa, stpb, mmstp, ptlim, limprice, stpprice;
static int entryposted, entrybar, model type;
static float exitatr[MAXBAR+1] , rnum, entryprice, tmp, atr;
static long iseed;


Код подобен представленному в предыдущих главах. Изменился лишь порядок генерации сигналов для входа. Входные сигналы теперь создаются с помощью генератора псевдослучайных чисел (ГПСЧ). Перед входом в цикл, который проходит через дни для моделирования процесса торговли, ГПСЧ инициализируется с уникальным начальным значением.
Начальное значение инициализации определено номером рынка и параметром (ranseed). При изменении данного параметра генерируется абсолютно другая последовательность случайных входов. Точные значения инициализации не важны, так как для каждой инициализации создается уникальный ряд из- за чрезвычайно большого периода ГПСЧ. Используемый ГПСЧ описан как гап2 в вышеупомянутой работе Numerical Recipes in С (1992). Период для ГПСЧ больше, чем 2Х1018. Этот ГПСЧ намного лучше стандартных генераторов, включенных в языки программирования. Внутри цикла, там, где фактически имеет место торговля, сигналы генерируются, основываясь на случайных числах. Шаги очень просты. На каждом дне от ГПСЧ получается равномерно распределенное случайное число между 0 и 1. Если случайное число меньше 0,025, то генерируется сигнал для входа в короткую позицию. Вероятность получения короткого сигнала в любой день равна 0,025, т.е. короткий сигнал должен генерироваться в среднем каждые 40 дней. Если случайное число превышает 0,975, то подается сигнал для открытия длинной позиции; частота этих сигналов такая же — один сигнал каждые 40 дней. Другими словами, в среднем торговые сигналы генерируются каждые 20 дней. Цены лимитного приказа и стоп- приказа рассчитываются обычным способом. Обычным способом размещаются приказы и определяются выходы.
Для проведения трех испытаний используются следующие шаги: на данных внутри выборки для каждого типа входного приказа генерируются и участвуют в торговле 10 различных серий случайных входов. Лучшие из этих последовательностей затем проверяются на данных вне выборки.
Процесс подобен оптимизации параметра в реальной системе. Изменяясь от 1 до 10, параметр выбирает различные ряды случайных входов для каждого значения.


// копируем параметры в локальные переменные для удобного обращения
mmstp = parms[1]; // используется для начальный защитной остановки
stpa - parms[2]; // дополнительный параметр защитной остановки
stpb = parms[3]; // дополнительный параметр защитной остановки
ptlim = parms[6]; // целевая прибыль в единицах среднего истинного
// диапазона
modeltype = parms[7]; // тип используемой динамической защитной
// остановки
maxhold = parms[8]; // период максимального удержания позиции
ranseed = parms[9]; // используется для инициализации случайной
// последовательности
// выполняем вычисления по всему объему данных
AvgTrueRangeS{exitatr,hi,lo,cls,50,nb); // средний истинный диапазон
// для выхода
// очищаем генератор случайных чисел
// ... используем различные случайные последовательности для каждого рынка
// ... ts.model() возвращает индекс рынка (SP=1, YX- 2, ...)
iseed = - {ranseed + 10 * ts.model());
rnum = ran2(&iseed);
// проходим через дни, чтобы смоделировать реальную торговлю
for(cb = 1; cb <= nb; cb++) {
// не открываем позиций до начала периода выборки
// ... то же самое, что установка MaxBarsBack в TradeStation
if(dt[cb] < IS_DATE) { eqcls[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);
// считаем количество контрактов для позиции
// ... мы хотим торговать эквивалентом долларовой волатильности
// ... 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;
rnum = ran2(&iseed);
if(rnum < 0,025) signal = - 1 // случайный короткий вход
else if(rnum > 0.975) signal = 1 // случайный длинный вход
// входим в сделки по цене открытия
entryposted = 0;
if (ts.position() < = 0 && signal == 1) {
ts.buyopen{'1' , ncontracts) ;
entryposted - 1;
entryprice = opn[cb+1];
entrybar = cb + 1;
}
else if(ts.position{} >= 0 && signal == - 1) {
ts.sellopen{'2', ncontracts};
entryposted = - 1;
entryprice = opn[cb+1];
entrybar = cb + 1;
}


// выходим из сделок, используя стандартный выход с улучшенными
// защитными остановками
atr = exitatr[cb];
if (entryposted > 0) {
// инициализация и выходы для длинных позиций в день входа
switch(modeltype) {
case 1:
limprice = entryprice + ptlim * atr;
stpprice = min (Lowest (lo, 2, cb),
entryprice - mmstp * atr);
break;
case 2:
case 3:
limprice = entryprice + ptlim * atr;
stpprice = entryprice - mmstp * atr;
break;
default: nrerror("Invalid modeltype");
}
ts.exitlonglimit('A' , limprice} ;
ts.exitlongstop('B' , stpprice) ;
}
else if (entryposted < 0) {
// инициализация и выходы для коротких позиций в день входа
switch(model type) {
case 1:
limprice = entryprice - ptlim * atr;
stpprice = max (Highest(hi, 2, cb),
entryprice + mmstp * atr);
break;
case 2:
case 3:
limprice = entryprice - ptlim * atr;
stpprice - entryprice + mmstp * atr;
break;
default: nrerror{"Invalid modeltype" ) ;
}
ts.exitshortlimit('C' , limprice) ;
ts.exitshortstop('D' , stpprice);
}
else {


// выходы после дня входа
if(ts.position() > 0) { // длинные позиции
switch{modeltype) {
case 1:
stpprice - max(stpprice, Lowest(lo,2,cb));
break;
case 2:
stpprice = max(stpprice, cls [cb]- stpa*atr);
break;
case 3:
tmp = (hi [cb] - stpa * atr) - stpprice;
if{tmp > 0.0) stpprice += stpb * tmp;
break;
}
ts.exitlonglimit('F' , limprice);
ts.exitlongstop('G' , stpprice);
if (cb- entrybar >= maxhold) ts.exitlongclose('E' } ;
}
else if (ts.position(} < 0) { // короткиепозиции
switch(modeltype) {
case 1:
stpprice = min(stpprice, Highest(hi,2,cb}) ;
break;
case 2:
stpprice = min (stpprice, cls [cb]+stpa*atr);
break;
сазеЗ:
tmp = {lo[cb] + stpa * atr) - stpprice;
if(tmp < 0.0) stpprice += stpb * tmp;
break;
}
ts.exitshortlimit('I' , limprice) ;
ts.exitshortstop('J' , stpprice);
if(cb- entrybar >= maxhold) ts.exitshortclose('H') ;
}
}
} // обрабатываем следующий день
}

Вышеприведенный код реализует МССВ с заменой фиксированной защитной остановки на одну из трех динамических методик. Вид защитной остановки выбирается параметром modeltype, и в зависимости от вида выбранной остановки программа оптимизирует значения еще трех дополнительных параметров. Для остановки на основе максимального максимума/минимального минимума за два последних дня (ММ/ММ) параметр mmstp — это количество средних истинных диапазонов (не обязательно целое число), прибавляемых или отнимаемых от цены входа для получения защитной остановки для входного дня. Защитная остановка входного дня устанавливается на уровне цены входа или минимального минимума за два последних дня плюс или минус указанное количество средних истинных диапазонов (выбирается уровень, более удаленный от текущей рыночной цены). Для двух других остановок (на основе среднего истинного диапазона и ЭСС) уровень защитной остановки входного дня инициализируется стандартным образом, т.е. цена входа минус (для длинной позиции) или плюс (для короткой позиции) произведение mmstp на средний истинный диапазон.
Затем в каждом торговом дне производится коррекция уровня защитной остановки. Вид коррекции зависит от выбранного параметром modeltype типа. Для остановки на основе ММ/ММ рассчитывается максимальный максимум или минимальный минимум в зависимости от вида открытой позиции (короткая или длинная). Если результат ближе к рыночной цене, чем текущий уровень защитной остановки, то он используется в качестве новой защитной остановки. В другой модели средний истинный диапазон умножается на второй параметр stpa. Результат вычитается (для длинной позиции) или прибавляется (для короткой) к текущей цене закрытия. Если результат ближе к текущей цене, чем текущий уровень защитной остановки, то он заменяет уровень защитной остановки, приближая его, таким образом, к текущей рыночной цене. Для третьего типа остановки (на основе ЭСС) средний истинный диапазон умножается на второй параметр stpa. Результат вычитается (для длинной позиции) или прибавляется (для короткой) к текущей цене закрытия для получения сдвига. Эта разность заносится в переменную tmp. Уровень защитной остановки обновляется в последующие дни путем прибавления imp, умноженной на другой параметр (коэффициент коррекции stpb) к текущей защитной остановке. Это, впрочем, производится только в том случае, если коррекция сместит уровень защитной остановки ближе к текущей цене. Расчеты подобны методике получения экспоненциального скользящего среднего (ЭСС) — с той разницей, что при расчете собственно ЭСС было бы возможно смещение уровня защитной остановки в обе стороны и не использовался бы предварительный сдвиг. В этой модели stpb определяет эффективный период экспоненциального скользящего среднего, которое может изменяться только в одном направлении — к текущей рыночной цене.


Содержание раздела