МЕТОДОЛОГИЯ ТЕСТИРОВАНИЯ ЛУННЫХ МОДЕЛЕЙ
Все тесты проводились с использованием входов по сигналам лунной модели для торговли портфелем различных финансовых инструментов. Можно ли получить прибыль, используя лунную модель? Как результативность подобных моделей будет изменяться со временем? Как изменились их результаты за последние годы? Для того чтобы ответить на эти вопросы, и было проведено тестирование.
Применены стандартные выходы, правила входов будут рассмотрены при обсуждении отдельных тестов. Позиции закрываются при подаче сигнала на вход в противоположном направлении либо при срабатывании стандартного выхода. В приведенном ниже коде описана модель входа на основе лунных циклов.
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);
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) { // режим "складного ножа"
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
if(sdate > m) break;
hunt(dt, n, sdate, &k);
if(sdate > dt[k]) k++;
cnt++; sum +- v[k] ; ) a[i]
sum / (cnt + tiny);
; // находим индекс
// накапливаем среднюю
{ // двигаемся вперед
{dt[i], j); //к исходной дате
// избегаем данных oos
// находим индекс
// накапливаем среднюю
// //
заканчиваем среднюю следующий день
режим фиксированного периода для каждого текущего дня
анализа
// двигаемся назад выполняем достаточные условия , -j); // исходная дата
// идем к началу находим индекс
// накапливаем среднюю
// двигаемся вперед выполняем достаточные условия исходная дата
} else
if(mode == 2) { //
ford = 1; i <= n; i ++) { // sum =0.0; cnt = 0 ; for( j =2;j<1000;j++ ) {
if(cnt >= m) break; // sdate = LunarEquivDate(dt[i] 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) {
// parms // dt // ор // hi // 1о // cl // vol // oi // dlrv / / nb // ts // eqcls
Выполняем разнообразные file = xl3modOl.c
торговые модели на лунных циклах.
набор набор набор набор набор набор набор набор набор
[1..MAXPRM] [l..nb] [1..nb] [l..nb] [1..nb] [l..nb] [l..nb] [1..nb] [1..nb] количество дней ссылка на класс
параметров дат в формате ГГММДД цен открытия максимальных цен минимальных цен цен закрытия значений объема значений открытого интереса средних долларовых волатильностей в наборе данных торгового симулятора
набор [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] ;
static float mal[MAXBAR+1], ma2[MAXBAR+1], stoch[MAXBAR+1]; static float *exitatrtab[MAXMKT+1], *savgtab[MAXMKT+1] ;
и инверсией 2=по лимитному приказу,
//копируем avglen disp = thresh matype
modeltype
ordertype
maxhold = ptlim = 4; rrmstp = 1;
параметры в локальные переменные = parms[1]; // период скользящей средней parms[2]; // множитель смещения parms[3]; // порог для импульсных моделей parms[7]; // тип средней: // 1=простое скользящее среднее // 2=экспоненциальное
// 3=треугольное с
// 4=треугольное
// 5=простое центрованное
// 6=экспоненциальное центрованное
// 7=треугольное центрованное
parms[8]; // тип модели:
// 1=импульс
// 2=пересечение
// 3-пересечение с
// 4=пересечение с
parms[9]; // вход:
переднем взвешиванием
подтверждением
подтверждением
10;
1=на открытии, // 3 =по стоп-приказу // период максимального удержания позиции // целевая прибыль в единицах волатильности // защитная остановка в единицах волатильности
// диапазон
// вспомогательный
// изменение цены
[cb] ; // нормирование
2.0); // обрезание
// Выполняем вычисления по всему объему данных, которые не подвержены // воздействию каких-либо параметров. Выполняется один раз для каждого // рынка, результаты сохраняются в таблицах для повторного использования.
// Таким образом, значительно снижается
mktindx = ts.modelf) ;
if (exitatrtab[mktindx] == NOLL) {
exitatrtab[mktindx] = vector(1, nb);
savgtab[mktindx] = vector{1, nb);
AvgTrueRangeS(exitatrtab[mktindx], hi, lo, cls, 50, nb);
float *pchg = vector(1, nb) ; pchg[l] = 0.0;
for(cb =2; cb < = nb; cb++) { tmp = els [cb] - els [cb-1] ; tmp /= exitatrtab[mktindx] pchg [cb] = clipltmp, -2.0, } LunarAvg(savgtab[mktindx],
pchg, dt, 2, 60, nb); free_vector(pchg, 1, nb); printf {"Met: %d\n", mktindx);
}
время выполнения программы.
// индекс рынка
// размещен?
// таблица exitatr
// таблица savg
//50-дневный средний истинный
вектор
// лунная сезонность
// показывать прогресс
// выполняем вычисления для всех данных 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) // стохастический осц.
StochOsc(stoch,hi,lo,cls,l,9,nb) ; // 9-дневный Быстрый %К break; default: nrerrorl"TRAPSMOD: invalid modeltype"); }
// проходим через дни, чтобы смоделировать реальную торговлю for(cb = I; cb <= nb; cb++) {
// не открываем позиций до периода выборки
// ... то же самое, что установка MaxBarsBack в TradeStation
if(dt[cb] < IS_DATE) { egcls[cb] = 0.0; continue; }
// выполняем ожидающие приказы и считаем кумулятивный капитал re = ts.update(opn[cb] , hi[cb] , lo [cb] , cls[cb], cb) ; if (re = 0) nrerrorl "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.0 / dlrv[cb]};
if(ncontracts < 1) neontracts = 1;
// избегаем устанавливать приказы на дни с ограниченной торговлей if(hi[cb+l] == lo[cb+l]) continue;
// генерируем входные сигналы, цены стоп- и лимитных приказов // для всех моделей signal = 0 ; switch(modeltype) {
case 1: // основная модель входа на основе импульса с порогом k = cb + disp; tmp = thresh * mal[к] ; if(savg[k] > tmp && savg[k-l] <= tmp)
signal = 1; else if(savg[k] < -tmp && savg[k-l] >= -tmp)
signal = -1; break; case 2 : // основная модель пересечения к = cb + disp;
if (CrossesAbove (mal, ma2 , k) } signal = 1 ; else if (CrossesBelow{mal, ma2, k)} signal = -1; break; case 3: // пересечение с подтверждением к = 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 : // пересечение с подтверждением и инверсией к = 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;
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);
} // обрабатываем следующий день }
Назад