Amibroker: архитектура языка

Язык Амиброкера — векторный, именно с этого момента у многих начинается недопонимание. Именно отсюда заявления, что тестер глючит, или стратегия не так как надо считает.

Самое главное, что нужно понять, что все переменные Амиброкера — это массивы. Амиброкер использует числа float (single precision) в своих расчетах, поэтому результаты расчетов некоторых индикаторов могут отличаться от других программ.

Для примера возьмем встроенные переменные Амиброкера для работы с OHLC, ничего не нужно объявлять дополнительно, чтобы получить данные об инструменте. Список встроенных переменных данных: Open, High, Low, Close, Volume, OI, Aux1, Aux2. Или короткие эквиваленты: O, H, L, C, V. Aux1, Aux2 — это вспомогательные поля в которые можно загрузить разную доп информацию, например из текстовиков.

Простой пример выражения:
MidPx = (H + L) / 2;

Переменные H и L — это массив данные об High и Low текущего инструмента, который выбран на графике или по которому идет бэктест.
Длина всех массивов (переменных) равна числу баров и переменной BarCount.

Теперь разберемся в том, как работает выражение (H + L) / 2, допустим у нас 6 баров, с индексами от 0 до 5. В Амиброкере индексация массивов тоже начинается с 0, как в C/C++. Алгоритм проходит все бары, и на каждом баре проводит простейшую математическую операцию.

Простой пример в Excel:


Мы можем переписать ту же операцию только через циклы, и она будет работать в Амиброкере:

MidPx = 0; //Инициализируем массив, и забиваем его нулями
for( i = 0; i < BarCount; i++ )
{
   MidPx[i] = (H[i] + L[i]) / 2;
}

В точно таком же виде мы бы написали это на C#. Можно для интереса посчитать сколько символов заняло написание этого кода. Код C#-like занял у нас 67 символов, включая "{}[]();\tab\space", код на векторном диалекте AFL — 20 символов. Эффективность кода с т.з. написания в 3 раза выше (!), и это на простейшей операции, что уж говорить о более сложных. Когда нам нужно будет инициализировать несколько сот таких переменных, в сложном коде — это не редкость, нам придется напечатать несколько сот/тысяч лишних знаков!

Как вы поняли язык Амиброкера может работать в 2х режимах: в векторном и «цикловом». C т.з. циклов и ключевых слов синтаксис Амиброкера ничем не отличается от C-like языков. For, while, do-while, switch, if — все это есть.

Логические переменные и условия
В Амиброкере все просто 1 — true, 0 — false. Логические переменные — это такие же массивы 0 и 1, длиной BarCount, как и все массивы Ами.

Простой пример, логического выражения:
MidPxGt96 = MidPx > 96;


Посмотрим какой результат даст выражение из примера Excel выше и напишем эквивалентную функцию через Excel:


Аналогичный код в C-like style:

MidPx = 0; //Инициализируем массив, и забиваем его нулями
MidPxGt96 = 0;
for( i = 0; i < BarCount; i++ )
{
   MidPx[i] = (H[i] + L[i]) / 2;
   if(MidPx[i] > 96)
        MidPxGt96[i] = 1;
    else
        MidPxGt96[i] = 0;
}


Попробуем сделать простейшее условие. Допустим для какого индикатора нам нужно взять Low в случае MidPx <= 96, и High во всех остальных. В Амиброкере это делается с помощью функции IIF.

CondHL = IIF(MidPxGt96, H, L);


То же само через Excel:


Аналогичный код в C-like style:

MidPx = 0; //Инициализируем массив, и забиваем его нулями
MidPxGt96 = 0;
CondHL = 0;
for( i = 0; i < BarCount; i++ )
{
   MidPx[i] = (H[i] + L[i]) / 2;
   if(MidPx[i] > 96)
        MidPxGt96[i] = 1;
    else
        MidPxGt96[i] = 0;
    
    if(MidPxGt96[i])
        CondHL[i] = H[i];
    else
        CondHL[i] = L[i];
}


Самой распространенной ошибкой новичка является, то что он питается использовать if с массивами, вместо IIF. if — используется в циклах, или для сравнения строковых переменных, или в структурах кода вида if(Action() == actionExploration).


if(MidPxGt96[i]) - OK!
if(MidPxGt96) - FAIL! MidPxGt96 - это массив


Итоговый код
AFL: 3 строчки, 75 знаков

MidPx = (H + L) / 2;
MidPxGt96 = MidPx > 96;
CondHL = IIF(MidPxGt96, H, L);


C-like: 13 строк, 275 знаков

MidPx = 0;
MidPxGt96 = 0;
CondHL = 0;
for( i = 0; i < BarCount; i++ )
{
   MidPx[i] = (H[i] + L[i]) / 2;
   if(MidPx[i] > 96)
        MidPxGt96[i] = 1;
    else
        MidPxGt96[i] = 0;
    
    if(MidPxGt96[i])
        CondHL[i] = H[i];
    else
        CondHL[i] = L[i];
}


Если вам стало интересно и хотите попробовать Амиброкер. Обязательно прочтите и проработайтеUnderstanding how AFL works Проработайте с карандашиком, калькулятором и excel! Как только поймете суть векторных вычислений, все пойдет как по маслу.

3 комментария

avatar
Я правильно понимаю, что, допустим у нас есть свой кастумный индикатор, вычисляющийся в скользящем окне. Идеология такая, что мы этот индикатор вычисляем где-то вначале скрипта обычным циклом for (), формируем вектор значений myInd. А дальше уже обычными векторыми операциями начинаем это дело комбинировать с OHLCVI и, возможно, другими индюками-векторами?

Или есть какие-то хитрые методы как эффективно посчитать чисто векторными операциями, скажем, те же Moving Average, Highest High и подобные штуки в скользящем окне?
  • Sten
  • 0
avatar
Да, обычно считаешь индикатор, записываешь его значение в вектор и используешь дальше в коде.

Или есть какие-то хитрые методы как эффективно посчитать чисто векторными операциями, скажем, те же Moving Average, Highest High и подобные штуки в скользящем окне?
У Ами много встроенных функций. Напр, MA(Close, 10) — возвращает вектор который содержит Moving Average за 10 баров в скользящем окне, или HHV(H, 10) — это вектор Highest Hi за 10 баров.
avatar
Спасибо :)
Пока вроде простые вещи, жду продолжения и усложнения…
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.