Генетические оптимизаторы
Представьте себе нечто, способное решить все проблемы, связанные с созданием человека — нечто, представляющее собой вершину всех методов оптимизации и решения задач. Что это такое? Известный процесс эволюции. Генетические оптимизаторы пытаются использовать часть этой невероятной способности к решению задач при помощи грубой симуляции эволюционного процесса. По параметрам общей эффективности и размаха решаемых программ никакой многоцелевой оптимизатор не превосходит хорошо написанный генетический оптимизатор.
Генетические оптимизаторы являются стохастическими в том смысле, что они используют в работе случайные числа. Может показаться невероятным, что бросание кубиков помогает решать задачи, но при правильном подходе это так! Кроме случайности генетические оптимизаторы используют отбор и комбинирование. Продуманная интеграция случая, отбора и комбинации — причина успешной работы генетических оптимизаторов. Полное обсуждение генетических алгоритмов, служащих основой для генетических оптимизаторов, приведено во втором разделе книги.
Генетические оптимизаторы могут иметь множество ценных характеристик, например скорость (особенно при наличии риска комбинаторного взрыва). Генетический оптимизатор работает на несколько порядков быстрее, чем оптимизатор с лобовым подходом, особенно при наличии множества правил или значений параметров. Это происходит потому, что, как и при оптимизации под управлением пользователя, идет фокусировка на важных участках пространства решений, а тупики пропускаются. В противоположность оптимизации под управлением пользователя селективный поиск достигается без вмешательства человека.
Генетические оптимизаторы могут быстро решать сложные задачи и более устойчивы, чем другие подходы, к эффектам локальных максимумов или (минимумов) на поверхности значений функции пригодности (или затрат). Вычислительные методы плохи тем, что всегда ведут к ближайшей вершине или впадине, не обращая внимания на более высокие вершины или впадины, которые могут существовать в других местах. При этом хороший генетический оптимизатор часто находит лучшее глобальное решение — великолепный результат при сложной форме поверхности.
Еще одна характеристика генетической оптимизации — то, что она хорошо работает на поверхностях с разрывами, плоскими участками и другими сложными неупорядоченными формами. Генетический метод делит это преимущество с другими неаналитическими методами — лобовым подходом, управлением пользователем и пр. При помощи генетического оптимизатора можно найти решения, максимизирующие такие показатели, как чистая прибыль, доходность, отношение Шарпа и подобные, для которых поверхность функции пригодности имеет сложную форму, с трудом поддающуюся анализу. Это не означает, что такой оптимизатор не применяется для задач с простыми поверхностями — уступая в скорости вычислительным методам, генетический оптимизатор защищен от влияния ловушек локальных экстремумов.
В общем, генетические оптимизаторы — предпочтительные методики для систем с множеством правил или параметров; они особенно полезны, если необходимо найти глобальное решение или работать с весьма сложными (прерывистыми и недифференцируемыми) функциями пригодности или расходов. Хотя специализированные оптимизаторы могут обгонять генетические на избранных задачах, для многоцелевой оптимизации генетический метод — один из самых мощных доступных инструментов.
На что похож генетический оптимизатор в работе? Мы перевели на C++ код для системы с пересечением скользящих средних, упоминавшейся ранее, чтобы при помощи C- Trader toolkit решать задачу оптимизации двух параметров — LenA и LenB. LenA, период первой скользящей средней, исследовался при значениях от 2 до 50, так же как и LenB — период второй скользящей средней. Оптимизация велась по показателю общей прибыли, чтобы можно было напрямую сравнивать результаты с полученными ранее методом оптимизации с лобовым подходом. Ниже приведен код для системы пересечения скользящих средних, написанный на C++:
static void Model (float *parms, float *dt, float *opn, float *hi, float *lo, float *cls, float *vol, float *oi, int nb, TRDSIM &ts, float *eqcls) {
// Выполнение тестирования всех моделей скользящих средних,
// используя следующие аргументы:
// parms — набор [1..MAXPRM] параметров
// dt - набор [l..nb] дат в формате ГГММДД
// орn — набор [1..nb] цен открытия
// hi - набор [l..nb] максимальных цен
// 1о — набор [1..nb] минимальных цен
// cls - набор [1..nb] цен закрытия
// vol — набор [1..nb] значений объема
// oi — набор [1..nb] значений открытого интереса
// nb - количество дней в наборе данных
// ts — ссылка на класс торгового симулятора
// eqcls — набор [1..nb] уровней капитала по ценам закрытия
//объявляем локальные переменные и макрофункции
static int cb, LenA, LenB;
static float MavgA[MAXBAR+1] , MavgB[MAXBAR+1] ;
#define CrossesAbove(a,b) ( (a[cb]>=b[cb])&&{a[cb- l]<b[cb- l]))
#tdefine CrossesBelow(a,b) ((a[cb]<b[cb])&&(a[cb- l]>=b[cb- l]))
//очищаем счет и снимаем неисполненные приказы
ts.clear{);
//считаем скользящие средние, используя серии (наборы} функций
LenA = parms[1];
LenB = parms[2];
Averages(MavgA, cls, LenA, nb);//Первая скользящая средняя
Averages(MavgB, cls, LenB, nb);//Вторая скользящая средняя
//проходим через дни, чтобы моделировать реальную торговлю
for (cb = 1; cb <= nb; cb++) {
//не открываем позиций в прошлом периоде
if(dt[cb] < 910302) { eqcls[cb] = 0.0; continue; }
//выполняем ожидающие ордера и считаем кумулятивный капитал
ts.update(opn[cb], hi[cb], lo [cb], cls [cb], cb) ;
eqcls [cb] = ts.currentequity(EQ_CLOSETOTAL);
//правило торговой системы пересечения двух скользящих средних
if (CrossesAbove(MavgA, MavgB)) ts.buyopen('A', 1);
if (CrossesBelow(MavgA, MavgB)) ts.sellopen('B', 1);
Для поиска оптимальных параметров путем оптимизации с лобовым подходом потребовалось бы провести 2041 тест, т.е. около 56 минут работы TradeStation согласно опыту прошлого тестирования небольшой выборки. Генетический оптимизатор справился с заданием за минуту. Кроме того, генетический оптимизатор был остановлен после проведения всего лишь 133 тестов, что должно значительно ухудшить его результат.
Данные генетического оптимизатора приведены в табл. 3- 2, где Р1 — период первой скользящей средней, Р2 — период второй скользящей средней, ЧИСТ. — чистая прибыль, Д.ЧИСТ, — чистая прибыль для длинных позиций, К.ЧИСТ. — чистая прибыль для коротких позиций, Ф.ПРИБ — фактор прибыли, ДОХ % — доходность в процентах годовых, МаксПК — максимальное падение капитала, СДЕЛ — количество совершенных системой сделок, ПРИБ% — процент выгодных сделок, Сред.рез. — прибыль или убыток от средней сделки и ПРИГ. — пригодность решения (в данном случае — просто общая прибыль). Как и в случае с данными лобовой оптимизации в табл. 3- 1, генетические данные были рассортированы по эффективности (общей прибыли) и показаны только 25 лучших.
Сравнение результатов генетической оптимизации и оптимизации с лобовым подходом (табл. 3- 1 и 3- 2 соответственно) показывает, что генетический оптимизатор обнаружил решение, для которого общая прибыль была выше ($172,725 против $145,125). Это неудивительно, поскольку исследовалось большое поле вариантов и скорость оптимизации не была ограничена последовательными шагами. Удивительно скорее то, что решение было обнаружено так быстро, несмотря на прерванный преждевременно эволюционный процесс. Подобные результаты демонстрируют невероятную мощь генетической оптимизации.