Выбор индикатора Технического анализа (далее ТА) для последующего употребления будет более аргументирован, если известна эффективность индикаторов, из числа которых выбор осуществляется.
Для оценки эффективности индикатора ТА или группы одновременно употребляемых индикаторов необходимо иметь графики цены актива, например акции, стратегию применения индикатора и знать формулу или алгоритм вычисления значений индикатора.
Так, Осциллятор Ускорение/Замедление (Acceleration/Deceleration Oscillator, AC) можно оценить, применяя следующую стратегию:
График цены актива можно выгрузить, например, с finam.ru или иного источника.
Формула (алгоритм) вычисления значений индикатора берется из приводимых ниже источников. Из них же заимствуются и описания подаваемых индикатором сигналов.
Таким образом, остается выбрать подходящую стратегию употребления индикатора, применить ее на некотором временном интервале и подсчитать полученный доход или понесенный убыток.
Чтобы реализовать эту схему, создается приложение, обеспечивающее
При создании приложения употреблена СУБД Microsoft Visual FoxPro. Примеры программирования на Microsoft Visual FoxPro можно найти в [4].
Трейдеры (Traders) – биржевые спекулянты (игроки), рассчитывающие наварить на постоянной купле-продаже ФИ. В качестве трейдеров могут выступать как физические, так и юридические лица, например, банки или инвестиционные компании. Физические лица, как правило, относятся к разряду мелких игроков, а банки – к разряду крупных. Доли мелких, средних и крупных игроков в общем объеме биржевых торгов неизвестны.
Быки (Bulls) – трейдеры, играющие на повышение рынка.
Медведи (Bears) – трейдеры, играющие на понижение рынка.
Сила быков и медведей измеряется, в частности, индикатором EFI.
Приведенные понятия относятся к разряду образных, поскольку трейдер в общем случае придерживается не одной стратегии (бычьей, медвежьей или иной), а тех, которые сулят наибольшую выручку.
Биржевые инвесторы – физические или юридические лица, на длительный срок покупающие ценные бумаги. С экономической точки зрения инвестиции в ценные бумаги оправданы, если получаемые дивиденды или процентные выплаты (за вычетом налогов) превышают инфляцию.
Долгосрочное инвестирование в подавляющее большинство продаваемых на биржах ценных бумаг является практически бессмысленным мероприятием, поскольку биржевые спекулянты (трейдеры) делают рынок непредсказуемым.
Эмитент – любой орган или организация (государственный банк, финансово-кредитное учреждение, предприятие, компания), выпускающие в обращение деньги и ценные бумаги, производящие эмиссию. Например, Сбербанк, помимо прочих активов, поставляет на биржу обычные и привилегированные акции.
Эмиссия ценных бумаг – выпуск в обращение акций, сертификатов, облигаций и других ценных бумаг любыми эмитентами, включая государство, кредитные учреждения, акционерные компании.
Рыночная капитализация компании – это величина, равная количеству акций компании (общему количеству выпущенных ценных бумаг), умноженная на текущую рыночную стоимость одной акции. Если компания выпустила несколько видов ценных бумаг, то все они учитываются при расчете капитализации по вышеприведенной схеме.
Акции ранжируются по эшелонам.
Акции первого эшелона – это так называемые голубые фишки (в покере голубые фишки, или blue chips считаются самыми дорогими). Эмитенты голубых фишек – это крупные компании, имеющие большую капитализацию.
Российские компаний с голубыми фишками (в скобках указан код акции):
Голубые фишки нередко показывают хорошую динамику роста. Но она может уступать некоторым акциям второго эшелона.
Голубые фишки обладают высокой степенью ликвидности.
Ликвидность ценной бумаги оценивают по количеству совершаемых сделок (объему торгов) и величине спреда – разницы между максимальными ценами заявок на покупку и минимальными ценами заявок на продажу. Чем больше сделок и меньше разница, тем больше ликвидность.
Второй эшелон – это акции, эмитенты которых вне списка компаний с наиболее ликвидными ценными бумагами, то есть не являются представителями голубых фишек на фондовом рынке. Акции второго эшелона уступают голубым фишкам в отношении ликвидности и капитализации.
Классическим представителем второго эшелона может выступать компания, имеющая средние годовые объемы продаж около 150-400 миллионов долларов и рыночную капитализацию 25-500 миллионов долларов.
Второй эшелон может оказаться более привлекательным, чем голубые фишки: его акции могут подорожать из-за их рыночной переоценки. Сравнительно небольшая компания с большей вероятностью прибавит в росте на 50 и более процентов, нежели известные лидеры.
Третий эшелон включает акции компаний-новичков, которые только начали свое обращение на рынке и не имеют собственной истории торгов. Уровень ликвидности третьего эшелона наиболее низок. Акции третьего эшелона подвержены наибольшим рискам. Однако, как известно, чем выше риск, тем выше может быть и доходность.
IPO (Initial Public Offering) – первичное размещение эмитентом ценных бумаг (акций). Цель IPO – получение дополнительных средств для развития бизнеса.
Макроэкономические индикаторы (МА) и индексы деловой активности (ИДА)– числовые показатели, отражающие экономическое состояние отраслей промышленности, сферы услуг, стран и регионов.
Примеры МА:
Примеры ИДА:
Технический анализ – совокупность методов прогнозирования динамики цены актива на основе прошлых цен. При прогнозировании широко употребляются индикаторы ТА.
Фундаментальный анализ (Fundamental analysis) – совокупность методов прогнозирования рыночной (биржевой) стоимости компаний, основанных на анализе финансовых и производственных показателей её деятельности. Фундаментальный анализ исходит из предпосылки, что мировая экономика, макроэкономические тенденции влияют на котировки акций конкретных компаний, а также на иные инструменты рынка ценных бумаг. Оценка экономики и макроэкономических тенденций опирается на макроэкономические индикаторы и индексы деловой активности.
Бар (Bar) – вертикальная полоса (столбец) на графике цены актива, выводимая в каждом интервале графика от минимального значения цены интервала к максимальному значению цены интервала.
Бычье расхождение (дивергенция) – цена достигает нового максимума, а индикатор не поднимается выше предыдущих максимумов.
Бычье схождение (конвергенция) – цена не достигла нового максимума, а индикатор показал новый максимум.
Медвежье расхождение (дивергенция) – цена не достигла нового минимума, а индикатор показал новый минимум.
Медвежье схождение (конвергенция) – цена достигает нового минимума, а индикатор не опускается ниже предыдущих минимумов.
Сигналы расхождения и схождения предупреждают о возможном изменении направления движения цены.
Волатильность ФИ (Volatility) – это разница, вычисляемая на заданном временном промежутке, между максимальной и минимальной ценами ФИ. Используется, в частности, индикатором ChV.
Длинная позиция (Long position) – покупка акций с целью их последующей реализации после роста цены (бычья тактика).
Короткая позиция (Short position) – продажа акций, взятых взаймы у брокера, в ожидании снижения их цены. После снижения цены трейдер покупает акции и возвращает их брокеру (медвежья тактика).
Коррекция (откат рынка – это движение цены в противоположную сторону по отношению к действующему в данный момент тренду. Различают восходящую, нисходящую и боковую коррекции. Последняя также называется консолидацией рынка. Консолидация рынка возникает, когда спрос и предложение на ФИ примерно равны. Продолжительную коррекцию можно рассматривать как тренд.
Кредитное плечо – это доля средств трейдера в общей сумме сделки. Например, кредитное плечо 1:20 при сумме сделки 5000 руб. означает, что 250 руб. этой суммы взято со счета трейдера, а оставшиеся 4750 руб. добавлены инвестиционной компанией (предоставлены в кредит).
Отскок от трендовой линии – кратковременное движение цены вблизи линии тренда, в направлении, противоположном тренду.
Пипс (Pips) – минимальная единица изменения цены актива. Например, если акция котируется с точностью до третьего десятичного знака, то 1 пипс = 0.001 руб.
Спрэд (Spread) – разница между ценами покупки и продажи актива.
Стоп-приказ на покупку (Order Buy Stop) – приказ на покупку ценной бумаги в случае, когда рыночная цена достигает или преодолевает заданную цену (стоп-цену).
Стоп-приказ на продажу (Order Sell Stop) – приказ на продажу ценной бумаги, когда рыночная цена достигает или оказывается ниже стоп-цены.
Стоп-приказ исполняется по наилучшей доступной цене.
Финансовые инструменты (ФИ) – продаваемые на бирже активы, например, акции, валюта, сырьевые ресурсы и др.
Флэт (Flat) – временной промежуток, в котором цена актива практически не изменяется.
Индикатор ТА – это показатель, вычисляемый в каждой точке заданного временного диапазона, количественно характеризующий динамику биржевого актива.
Описание индикаторов ТА широко представлено в Интернете (см. например список источников). По этой причине индикаторы ТА рассматриваются бегло, в объеме, необходимом для построения приложения.
Список используемых приложением индикаторов ТА приведен в алфавитном порядке:
В разных источниках индикаторы делят на три или пять категорий.
В первом случае выделяют следующие категории:
Список из пяти категорий разбиения следующий:
В ряде источников выделяется еще одна категория – психологические индикаторы, определяющие настроения участников рынка.
Приложение реализуется поэтапно:
Приводится сокращенная версия модели данных, отражающей ход биржевых торгов. В модели имеются следующие таблицы:
Первые две таблицы имеют следующие поля:
Таблица Активы имеет следующие поля (тип всех полей Integer):
Таблица Биржевые Торги имеет следующие поля:
Данные в таблицу Биржевые Торги загружаются из файла, выгружаемого с finam.ru или иного источника.
Файл с данными выгружается без заголовка и несет следующие сведения: Date, Time, Open, High, Low, Close и Volume.
Разделителем полей является запятая.
Интервал предоставления данных 5 минут.
Для загрузки выбирается актив и файл с выгруженными данными. Форма, обеспечивающая загрузку, приведена на рис. 1.
Рис. 1. Форма загрузки актива
Кнопка Загрузить D зарезервирована для загрузки данных с интервалом в 1 день.
Загрузку и вывод сведений о результатах загрузки обеспечивает следующий код:
LOCAL fn, IDSVl
WITH thisForm
IDSVl = .IDSlct
nmVl = .TxtNm.Value
ENDWITH
fn = GETFILE('TXT', RTRIM(nmVl), 'Get data', 0, 'Stock prices')
IF NOT EMPTY(fn)
IF RIGHT(GETWORDNUM(fn, 1, '.'), 1) # 'F'
MESSAGEBOX("5 minutes file should be selected")
RETURN
ENDIF
ali = 'stcksTrdngTmp'
closeAli(ali)
tbl = _tmpPth + ali
* DATE, TIME, OPEN, HIGH, LOW, CLOSE, VOL
CREATE TABLE (tbl) FREE (dtD D, tm C(6), pn N(7, 2), hgh N(7, 2), lw N(7, 2), cls N(7, 2), vlm N(9, 0))
APPEND FROM (fn) DELIMITED WITH ,
rCVl = RECCOUNT( )
IF rCVl = 0
MESSAGEBOX('File is empty')
ELSE
ALTER TABLE (tbl) ADD dt T ADD IDS I
REPLACE dt WITH DATETIME(YEAR(dtD), MONTH(dtD), DAY(dtD), VAL(LEFT(tm, 2)), VAL(SUBSTR(tm, 3, 2)), 0);
IDS WITH IDSVl ALL
DELETE stcksTrdngTmp FROM stcksTrdngF;
WHERE stcksTrdngTmp.IDS = stcksTrdngF.IDS AND stcksTrdngTmp.Dt = stcksTrdngF.Dt
SELECT stcksTrdngTmp
PACK
ali2 = 'stcksTrdngF'
rc = RECCOUNT(ali2)
IF RECCOUNT(ali) > 0
INSERT INTO (ali2) (ids, dt, pn, hgh, lw, cls, vlm);
SELECT ids, dt, pn, hgh, lw, cls, vlm FROM (ali)
nDdVl = _TALLY
ELSE
nDdVl = 0
ENDIF
fn2 = _tmpPth + 'rslts.txt'
SET SAFETY OFF
SET ALTERNATE TO (fn2)
SET ALTERNATE ON
SET CONSOLE OFF
? 'File ' + fn
? nmVl + '. Added records: ' + TRANSFORM(nDdVl)
IF rCVl - nDdVl # 0
? nmVl + '. Missed records: ' + TRANSFORM(rCVl - nDdVl)
ENDIF
? ''
SET ALTERNATE TO
MODIFY FILE (fn2)
ENDIF
ENDIF
Загруженные данные используются, в частности, для вычисления значений индикаторов ТА.
Выгрузка данных об активе для последующего построения графика цены, линии тренда, скользящих средних, объемов продаж и индикаторов ТА обеспечивается формой, показанной на рис. 2.
Рис. 2. Форма выгрузки актива
Визуализация биржевых данных используется только на этапе отладки системы. Сама же система вырабатывает рекомендации по табличным данным.
Изменение цены актива, 0.5 * (high + low) или close, во времени отображается на графике (рис. 3).
Рис. 3. ОАО Газпром АО. Черный четверг 22.09.2011
График строится по данным, выгружаемым посредством формы, приведенной на рис. 2. Выгружается один биржевой день. Реальное значение цены актива получается путем прибавления к цене значения base, указанного в заголовке графика.
Одновременно с графиком цены, если установлен флажок Тренд, рассчитываются и выгружаются начальные и конечные координаты линии тренда. Поиск линии тренда выполняется в указанном временном диапазоне.
Линия тренда – это прямая линия, которая соединяет на графике цены два характерных пика ценовых максимумов (минимумов). Все промежуточные точки лежат ниже (выше) линии тренда.
Линия нисходящего тренда показана на рис. 3, а восходящего – на рис. 4.
Рис. 4. ОАО Газпром АО. Линия восходящего тренда
В пределах основного тренда могут наблюдаться вторичные (малые) тренды.
Выбор временного диапазона при определении линий тренда имеет принципиальное значение.
Тренд, характеризуемый пологой линией (цена практически не меняется), называется боковым (Sideways Trend).
Крутая линия, соединяющая ценовые максимумы, образует нисходящий тренд (Down Trend). При таком тренде тон задают медведи. Такую линию можно рассматривать как нисходящий уровень сопротивления.
Линия, соединяющая ценовые минимумы, образует восходящий тренд (Up Trend). При таком тренде тон задают быки. Такую линию можно рассматривать как восходящий уровень поддержки.
При нисходящем или восходящем тренде можно говорить о существовании на рынке доминирующей группы. Сила этой группы зависит от следующих факторов:
Чем выше значения этих факторов, тем больше сила доминирующей группы.
Продолжительность ярко выраженные трендовых изменений обычно не превышает 15-30 % общей продолжительности биржевых торгов.
При вычислении многих индикаторов ТА употребляются сглаженные данные, называемые скользящими средними (Moving Average, MA). Преимущественно используются три следующих типа MA:
Использованы следующие обозначения:
j – номер временного интервала, в котором рассчитывается значение MA;
Pi – значение цены в i-м интервале;
Vi – значение объема продаж в i-м интервале;
n – число интервалов (период) сглаживания (по умолчанию n = 7).
В общем случае при вычислении MA или индикатора ТА в качестве цены актива может быть взято одно из следующих значений:
Выгрузка MA выполняется, если в форме (см. рис. 2) установлен соответствующий флажок.
Вычисление SMA и VMA обеспечивает функция clcSMA, а EMA – функция clcEMA.
*
* Returns SMA or VMA value in record rNd
FUNCTION clcSMA(vl, rStrt, rNd)
LOCAL aVl, k2
aVl = 0.0
FOR k2 = rStrt TO rNd
GO k2
aVl = aVl + &vl
NEXT
RETURN aVl / (rNd - rStrt + 1)
ENDFUNC
*
* Returns EMA value in record rCrrnt
FUNCTION clcEMA(vl, aVl, rCrrnt, n)
GO rCrrnt
RETURN (aVl * (n - 1) + 2 * &vl) / (n + 1)
ENDFUNC
На рис. 5 график SMA отображен красным, EMA – зеленым, а VMA – синим цветом.
Рис. 5. Скользящие средние (график цены показан черным цветом)
Индикатор RSI использует скользящие средние повышения и понижения цены. Их расчет обеспечивает функция clcUDMA.
*
* Returns UMA or DMA value in record rNd
FUNCTION clcUDMA(vl, rStrt, rNd, sUVl)
LOCAL mVVl, aVl, k2, n2
aVl = 0.0
n2 = 0
FOR k2 = rStrt TO rNd
GO k2 - 1
mVVl = &vl
GO k2
IF sUVl
IF &vl > mVVl
n2 = n2 + 1
aVl = aVl + (&vl - mVVl)
ENDIF
ELSE
IF &vl < mVVl
n2 = n2 + 1
aVl = aVl + (mVVl - &vl)
ENDIF
ENDIF
NEXT
RETURN IIF(n2 = 0, 0, aVl / n2)
ENDFUNC
Ряд индикаторов, например BB, использует стандартное отклонение цены SD:
SDj = SQRT(sum(Pi – MAi(P, n))^2) / n), где i = j – n + 1, j
Значение SDj в интервалеj возвращается функцией clcSD. Перед вызовом функции выполняется расчет MA (SMA, EMA или VMA).
*
* Returns Standard deviation (SD) value in record rNd
FUNCTION clcSD(p, vl, rStrt, rNd)
LOCAL sdVl, k2, dVl
sdVl = 0.0
FOR k2 = rStrt TO rNd
GO k2
dVl = &p - &vl
sdVl = sdVl + dVl * dVl
NEXT
RETURN SQRT(sdVl) / (rNd - rStrt + 1)
ENDFUNC
Индикатор IKH рассчитывает в указанном временном промежутке из n интервалов средину цены:
PM = (max(H, n) + min(L, n)) / 2
Значение PM в позиции rCrrnt для временного промежутка из mntVl интервалов возвращает функция clcPrcMddl.
*
* Returns price middle value for a record rCrrnt
FUNCTION clcPrcMddl(rCrrnt, mntVl)
LOCAL rStrtVl, pXVl, pMVl, rNdVl, k2
rStrtVl = rCrrnt - mntVl + 1
GO rStrtVl
pXVl = hgh
pMVl = lw
rStrtVl = rStrtVl + 1
FOR k2 = rStrtVl TO rCrrnt
GO k2
pXVl = MAX(pXVl, hgh)
pMVl = MIN(pMVl, lw)
NEXT
RETURN 0.5 * (pXVl + pMVl)
ENDFUNC
Индикатор MnFI использует значения положительного и отрицательного денежных потоков, возвращаемых функцией clcMF.
*
* Returns sum for positive or negative money flow for a record rCrrnt
FUNCTION clcMF(rCrrnt, mntVl, fPVl)
LOCAL rStrtVl, mFVl, k2, mVVl, mVVl2
rStrtVl = rCrrnt - mntVl + 1
mFVl = 0.0
FOR k2 = rStrtVl TO rCrrnt
GO k2 - 1
mVVl = (hgh + lw + cls) / 3.0 * vlm
SKIP
mVVl2 = (hgh + lw + cls) / 3.0 * vlm
IF fPVL
IF mVVl2 > mVVl
mFVl = mFVl + mVVl2
ENDIF
ELSE
IF mVVl2 < mVVl
mFVl = mFVl + mVVl2
ENDIF
ENDIF
NEXT
RETURN mFVl
ENDFUNC
В индикаторах SO, %R и VHF берутся минимальное и максимальное значения цены в заданном временном промежутке. Эти значения возвращаются функциями clcMinP и clcMaxP.
*
* Возвращает минимум цены за mntVl интервалов
FUNCTION clcMinP(rCrrnt, mntVl)
LOCAL rStrtVl, mnPVl, k2
rStrtVl = rCrrnt - mntVl + 1
GO rStrtVl
mnPVl = lw
FOR k2 = rStrtVl + 1 TO rCrrnt
GO k2
mnPVl = MIN(mnPVl, lw)
NEXT
RETURN mnPVl
ENDFUNC
*
* Возвращает максимум цены за mntVl интервалов
FUNCTION clcMaxP(rCrrnt, mntVl)
LOCAL rStrtVl, mxPVl, k2
rStrtVl = rCrrnt - mntVl + 1
GO rStrtVl
mxPVl = hgh
FOR k2 = rStrtVl + 1 TO rCrrnt
GO k2
mxPVl = MAX(mxPVl, hgh)
NEXT
RETURN mxPVl
ENDFUNC
Индикатору VHF нужна сумма изменений цены в заданном промежутке. Эту сумму возвращает функция clcSPCH.
*
* Возвращает сумму абсолютных значений изменений цены за mntVl интервалов
FUNCTION clcSPCH(mV, rCrrnt, mntVl)
LOCAL rStrtVl, mVVl, sPCHVl, k2
rStrtVl = rCrrnt - mntVl + 1
sPCHVl = 0
GO rStrtVl
mVVl = &mV
FOR k2 = rStrtVl + 1 TO rCrrnt
GO k2
sPCHVl = sPCHVl + ABS(&mV - mVVl)
mVVl = &mV
NEXT
RETURN sPCHVl
ENDFUNC
Объемы продаж отображаются в виде столбчатой диаграммы. Перед выводом график объема масштабируются так, чтобы его можно было показать одновременно с графиком цены (рис. 6).
Рис. 6. Объемы продаж
Выгрузку данных обеспечивает следующий код (функции выгрузки SMA, VMA и EMA см. выше):
* Выгрузка графиков цены, линии тренда, скользящей средней и объема
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
* See someprocs.prg
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
WITH thisForm
chTrnd = .CheckTrnd.Value
chMA = .CheckMA.Value
chVlms = .CheckVlms.Value
prdVl = .SpinnerPrd.Value
ENDWITH
nFldsVl = 6
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'mV'
arrFlds[2] = 'trnd'
arrFlds[3] = 'sma'
arrFlds[4] = 'ema'
arrFlds[5] = 'vma'
arrFlds[6] = 'vlms'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrGTps[2] = IIF(chTrnd, 'T', 'N') + ' 1.0 0.0 1.0 0.0'
arrGTps[3] = IIF(chMA, 'L', 'N') + ' 1.0 0.0 0.0 0.0'
arrGTps[4] = IIF(chMA, 'L', 'N') + ' 0.0 1.0 0.0 0.0'
arrGTps[5] = IIF(chMA, 'L', 'N') + ' 0.0 0.0 1.0 0.0'
arrGTps[6] = IIF(chVlms, 'C', 'N') + ' 0.0 1.0 1.0 0.0'
prcKndVl = LEFT(prcKndVl, RAT('_', prcKndVl) - 1)
prcKndVl = prcKndVl + IIF(chTrnd, '_Trend', '')
prcKndVl = prcKndVl + IIF(chMA, '_MA(' + TRANSFORM(prdVl) +')', '')
prcKndVl = prcKndVl + IIF(chVlms, '_Volume', '')
* Kind of files
mVDtVl = arrFlds[1]
flNmVl = _prjPth + mVDtVl + '.txt'
kFFlsWrdVl = mVDtVl + _NEXTLINE + arrGTps[1]
mvBsVl = nldMv(ali, IDSVl, pDtVl, 'ttl.txt', 'Prices', prcKndVl, mVDtVl, .T., 0, flNmVl, .F.)
FOR k = 2 TO nFldsVl
kFFlsWrdVl = kFFlsWrdVl + _NEXTLINE + arrFlds[k] + _NEXTLINE + arrGTps[k]
* Trend
IF chTrnd
chTrnd = nldTrnd(thisForm, slctVl, mvBsVl)
ENDIF
IF chMA
chMA = nldMFls(ali, DAY(pDtVl), prdVl, mvBsVl)
ENDIF
IF chVlms
chVlms = nldVlms(ali, DAY(pDtVl), mvBsVl)
ENDIF
NEXT
* Create file kFFls.txt with types of unloaded files
STRTOFILE(kfFlsWrdVl, _prjPth + 'kFFls.txt')
oVl = chTrnd OR chMA OR chVlms
msgVl = 'File' + IIF(oVl, 's ', '');
+ ' prices' + IIF(chTrnd, ', trend', '') +;
IIF(chMA, ', moving average', '') +;
IIF(chVlms, ', volumes', '') +;
IIF(oVl, ' are', ' is') + ' created'
MESSAGEBOX(msgVl)
*
* Определяет начальные и конечные координаты тренда указанного вида
* (нисходящего или восходящего)
FUNCTION trnd(tk, dtVl, mvMVl, dtVl2, mvMVl2)
sgn = IIF(tk = 'd', '<', '>')
sgn2 = IIF(tk = 'd', '>=', '<=')
sgn3 = IIF(tk = 'd', '>', '<')
FOR k = 2 TO rCnt - 1
GO k - 1
mvPVl = mv
SKIP
mvCVl = mv
SKIP
IF mvCVl &sgn2 mvPVl AND mvCVl &sgn3 mv
SKIP -1
REPLACE tpnts WITH 'm'
SKIP
ENDIF
NEXT
IF tk = 'd'
CALCULATE MAX(mv) FOR tpnts = 'm' TO mvMVl
ELSE
CALCULATE MIN(mv) FOR tpnts = 'm' TO mvMVl
ENDIF
LOCATE FOR mv = mvMVl
REPLACE tpnts WITH 't'
dtVl = tmx
REPLACE tpnts WITH '' FOR tmx < dtVl
STORE 0 TO dtVl2, mvMVl2
tgVl = IIF(tk = 'd', -1, 1) * 10000.0
k = 0
SCAN FOR tpnts = 'm'
tgVl2 = (mv - mvMVl) / (tmx - dtVl)
IF tgVl2 &sgn3 tgVl
k = k + 1
mvMVl2 = mv
dtVl2 = tmx
tgVl = tgVl2
ENDIF
ENDSCAN
RETURN IIF(k = 0, 0, dtVl2 - dtVl)
ENDFUNC && trnd
*
* Масштабирование по временной оси
FUNCTION fndTmxVl(tmxVl)
r2Vl = RIGHT(tmxVl, 2)
DO CASE
CASE r2Vl = '05'
r2Vl = '08'
CASE r2Vl = '10'
r2Vl = '17'
CASE r2Vl = '15'
r2Vl = '25'
CASE r2Vl = '20'
r2Vl = '34'
CASE r2Vl = '25'
r2Vl = '42'
CASE r2Vl = '30'
r2Vl = '51'
CASE r2Vl = '35'
r2Vl = '59'
CASE r2Vl = '40'
r2Vl = '67'
CASE r2Vl = '45'
r2Vl = '75'
CASE r2Vl = '50'
r2Vl = '84'
CASE r2Vl = '55'
r2Vl = '92'
ENDCASE
RETURN LEFT(tmxVl, 2) + r2Vl
ENDFUNC && fndTmxVl
*
* Выгружает в файл fn график цены или индикатора ТА (поле mV) из таблицы ali
FUNCTION nldMv(ali, IDSVl, pDtVl, ttlFnVl, ttlVl, prcKndVl, mV, sBsVl, mVBs, fn, llVl)
LOCAL f, dVl
dVl = DAY(pDtVl)
IF sBsVl
CALCULATE MIN(&mV) TO mVNVl FOR dy = dVl AND (&mV > 0 OR llVl)
mVBs = INT(mVNVl / 10) * 10
ENDIF
IF NOT EMPTY(ttlFnVl)
ALTER table (ali) ADD tmx C(4)
REPLACE tmx WITH CHRTRAN(tm, ':', '') ALL
SEEK IDSVl IN stcks ORDER IDN
SEEK stcks.IDC IN cmpns ORDER IDN
SEEK stcks.IDK IN stcksKnds ORDER IDN
pDtVl = CHRTRAN(TRANSFORM(PDtVl), '.', '')
stckVl = TRIM(cmpns.NmShrt) + '_' + TRIM(stcksKnds.NmShrt2)
SELECT (ali)
GO TOP
tmxNVl = tmx
GO BOTTOM
tmxXVl = tmx
* Title-file
ttlWrd = stckVl + '_' + pDtVl + '_' + ttlVl + '_' + prcKndVl +;
_NEXTLINE + TRANSFORM(mvBs) + _NEXTLINE + tmxNVl + _NEXTLINE + tmxXVl
STRTOFILE(ttlWrd, _prjPth + ttlFnVl)
ENDIF
f = FCREATE(fn)
SCAN FOR dy = dVl AND (&mV > 0 OR llVl)
FPUTS(f, fndTmxVl(tmx) + ' ' + TRANSFORM(&mV - mVBs))
ENDSCAN
FCLOSE(f)
RETURN mVBs
ENDFUNC && nldMv
*
* Находит и выгружает начальные и конечные координаты линии тренда
FUNCTION nldTrnd(thsFrm, slctVl, mvBs)
LOCAL fn, f, ali0, ali, tbl
fn = _prjPth + 'trnd.txt'
WITH thsFrm
IDSVl = .IDSlct
sDtVl2 = .SDt2.Value
nDtVl2 = .NDt2.Value
ENDWITH
nDtVl2 = IIF(EMPTY(nDtVl2), DATETIME( ) + 19 * 3600, nDtVl2)
ali0 = 'stcksTrdngF'
ali = 'stcksTL'
tbl = _tmpPth + ali
SELECT &slctVl AS mV,;
TRANSFORM(HOUR(dt)) + ":" + IIF(MINUTE(dt) > 5, TRANSFORM(MINUTE(dt)),;
'0' + TRANSFORM(MINUTE(dt))) AS tm;
FROM (ali0);
WHERE IDS = IDSVl;
AND dt BETWEEN sDtVl2 AND nDtVl2;
ORDER BY dt;
INTO TABLE (tbl)
rCnt = RECCOUNT()
IF rCnt < 3
MESSAGEBOX("Trend: three or less records are selected")
RETURN .F.
ENDIF
ALTER table (ali) ADD tmx I ADD tpnts C(2)
REPLACE tmx WITH VAL(CHRTRAN(tm, ':', '')) ALL
* Try to understand a kind of trend (D, U or S)
* Try D trend first
STORE 0 TO dtVlD, mvMVlD, dtVlD2, mvMVlD2, dtVlU, mvMVlU, dtVlU2, mvMVlU2
tLD = trnd('d', @dtVlD, @mvMVlD, @dtVlD2, @mvMVlD2)
* Try U trend next
REPLACE tpnts WITH '' ALL
tLU = trnd('u', @dtVlU, @mvMVlU, @dtVlU2, @mvMVlU2)
IF tLU > tLD
*!* tk = 'U'
dtVlT = dtVlU
mvMVlT = mvMVlU
dtVlT2 = dtVlU2
mvMVlT2 = mvMVlU2
ELSE
*!* tk = 'D'
dtVlT = dtVlD
mvMVlT = mvMVlD
dtVlT2 = dtVlD2
mvMVlT2 = mvMVlD2
ENDIF
f = FCREATE(fn)
FPUTS(f, fndTmxVl(TRANSFORM(dtVlT)))
FPUTS(f, TRANSFORM(mvMVlT - mvBs))
FPUTS(f, fndTmxVl(TRANSFORM(dtVlT2)))
FPUTS(f, TRANSFORM(mvMVlT2 - mvBs))
FCLOSE(f)
RETURN .T.
ENDFUNC && nldTrnd
*
* Выгрузка скользящих средних
FUNCTION nldMFls(ali, dVl, n, mvBs)
LOCAL ali2, tbl2, k2
ali2 = 'nldMF'
tbl2 = _tmpPth + ali2
SELECT mV, vlm, tmx;
FROM (ali);
WHERE dy = dVl AND mV > 0;
INTO TABLE (tbl2)
rCnt = _TALLY
IF rCnt < n + 1
RETURN .F.
ENDIF
fn3 = _prjPth + 'sma.txt'
fn4 = _prjPth + 'ema.txt'
fn5 = _prjPth + 'vma.txt'
f3 = FCREATE(fn3)
f4 = FCREATE(fn4)
f5 = FCREATE(fn5)
emaVl = mV
FOR k = 1 TO n - 1
GO k
tmxVl = fndTmxVl(tmx)
FPUTS(f3, tmxVl + ' ' + TRANSFORM(mv - mvBs))
FPUTS(f4, tmxVl + ' ' + TRANSFORM(mv - mvBs))
FPUTS(f5, tmxVl + ' ' + TRANSFORM(mv - mvBs))
NEXT
FOR k = n TO rCnt
k2 = k - n + 1
smaVl = clcSMA('mV', k2, k)
emaVl = clcEMA('mV', emaVl, k, n)
vmaVl = clcSMA('mV * vlm', k2, k) / clcSMA('vlm', k2, k)
GO k
tmxVl = fndTmxVl(tmx)
FPUTS(f3, tmxVl + ' ' + TRANSFORM(smaVl - mvBs))
FPUTS(f4, tmxVl + ' ' + TRANSFORM(emaVl - mvBs))
FPUTS(f5, tmxVl + ' ' + TRANSFORM(vmaVl - mvBs))
NEXT
FCLOSE(f3)
FCLOSE(f4)
FCLOSE(f5)
RETURN .T.
ENDFUNC && nldMFls
*
* Выгрузка объемом продаж
FUNCTION nldVlms(ali, dVl, mVBs)
LOCAL fn, f
SELECT (ali)
CALCULATE MAX(vlm) TO vlmXVl FOR dy = dVl AND mV > 0
CALCULATE MAX(mV - mVBs) TO mVXVl FOR dy = dVl AND mV > 0
dvdVl = vlmXVl / mVXVl
fn = _prjPth + 'vlms.txt'
f = FCREATE(fn)
SCAN FOR dy = dVl AND mV > 0
FPUTS(f, fndTmxVl(tmx) + ' ' + TRANSFORM(vlm / dvdVl))
ENDSCAN
FCLOSE(f)
RETURN .T.
ENDFUNC && nldVlms
Файл ttl.txt может иметь следующее наполнение:
gasp_O_23092011_Prices_0.5*(high+low)_ma(7)
140
1000
1840
6.44
12.85
Начальную часть файла prcs.txt с ценами актива иллюстрирует следующий пример:
1000 10.710
1005 10.330
1010 9.825
Линия тренда восстанавливается по файлу trnd.txt, содержащему описатель вида тренда (буква U, D или S соответственно для восходящего, нисходящего или бокового тренда) и начальные и конечные координаты линии.
U
1505
1.95
1725
2.880
Графический вывод обеспечивается средствами OpenGL и языка программирования Fortran.
!
! Модуль, задающий цифры, точку, знаки + и - и буквы x, y, z и e
module figures
use opengl
integer(4), parameter :: mli = 19, nli = 8
! mli - число символов (битовых образов) в массиве rasterfont
! nli - размер знакоместа
integer(1), dimension(nli) :: letter ! Массив для одного символа
integer(1) :: pointplace = 12 ! Позиция точки в массиве
! Точка выводится более компактно. Для ее поиска применяется pointplace
! rasterfont - массив символов с ASCII-кодами цифр и букв x, y, z и e
integer(1), dimension(mli, nli) :: rasterfont = reshape((/ &
#3c, #66, #c3, #c3, #c3, #c3, #66, #3c, & ! 0 (48)
#7e, #18, #18, #18, #18, #78, #38, #18, & ! 1 (49)
#ff, #60, #30, #18, #0c, #06, #e7, #7e, & ! 2 ...
#7e, #e7, #03, #03, #3e, #03, #e7, #7e, & ! 3
#0c, #0c, #0c, #ff, #cc, #6c, #3c, #1c, & ! 4
#7e, #c3, #03, #03, #fe, #c0, #c0, #ff, & ! 5
#7e, #c3, #c3, #c3, #fe, #c0, #c3, #7e, & ! 6
#30, #30, #30, #18, #0c, #06, #03, #ff, & ! 7
#7e, #c3, #c3, #c3, #3c, #c3, #c3, #7e, & ! 8
#7e, #e7, #03, #03, #7f, #c3, #c3, #7e, & ! 9 (57)
#00, #00, #00, #3f, #3f, #00, #00, #00, & ! - (45)
#00, #38, #38, #00, #00, #00, #00, #00, & ! . (46)
#7c, #c2, #c0, #fc, #c6, #c6, #7c, #00, & ! e (101 = 69 + 32)
#00, #18, #18, #ff, #ff, #18, #18, #00, & ! + (43)
#c6, #6c, #38, #38, #6c, #c6, #00, #00, & ! x (120)
#60, #30, #18, #1c, #36, #63, #c3, #00, & ! y (121)
#fe, #60, #30, #18, #0c, #fe, #00, #00, & ! z (122)
#00, #00, #00, #00, #00, #00, #00, #00, & ! ' ' (32)
#00, #38, #38, #00, #00, #38, #38, #00 & ! : (58)
/), shape = (/ mli, nli /), order = (/ 2, 1 /))
real(4) :: spx = 8.0, spy = 8.0 ! x и y-размеры знакоместа
contains
! Модуль figures включает процедуры:
! makeFigures - формирует списки команд вывода текста
! printString - выводит строку текста
! Создаем списки команд, используемые затем при выводе наборов символов
! Выводимый набор символов задается в виде строки,
! например: '0123456789xyz+-.e'
subroutine makeFigures()
integer(4) :: i, sg
! Начало координат битового образа
real(4) :: xorigx, yorigx, xorigy, yorigy
! Выравнивание по одному байту
call fglPixelStorei(gl_unpack_alignment, 1)
! Генерируем 3*m списков команд - по 3 списка на каждый заданный массивом
! rasterfont символ. Первый список для x-координат, второй - для y-координат
xorigx = 14.0; yorigx = 15.0
xorigy = 14.0; yorigy = 1.0
sg = 1
do i = 1, mli
letter = rasterfont(i, :)
call details(i, sg, xorigx, yorigx)
call details(i + mli, -sg, xorigy, yorigy)
end do
contains
! Внутренняя процедура подпрограммы makeFigures
! Детализирует различия в способах вывода x- и y-координат
subroutine details(k, sg, xorig, yorig)
integer(4) :: k, sg ! k - номер списка; sg = +1 или -1
real(4) :: xorig, yorig ! Начало координат битового образа
call fglNewList(k, gl_compile)
if(i == pointplace) then
! Способ вывода точки
call fglBitmap(spx, spy, xorig + sg, yorig, sg * (spx - 1.0), 0.0, loc(letter))
else
! Способ вывода x-координат, если sg = +1, и y-координат, если sg = -1
call fglBitmap(spx, spy, xorig, yorig, sg * (spx + 1.0), 0.0, loc(letter))
end if
call fglEndList( )
end subroutine details
end subroutine makeFigures
subroutine printString(s, gt) ! Вывод строки текста
character(*) s
character(1) gt ! gt = 'x', 'y'
integer(2), dimension(len_trim(s)) :: ars
integer(2) :: lens, i, k
lens = len_trim(s)
if(gt == 'x') then
if(s(1:1) > '1') then
s = s(1:1) // ':' // s(2:3)
else
s = s(1:2) // ':' // s(3:4)
endif
endif
do i = 1, lens ! Формируем массив номеров команд, которые
k = int2(ichar(s(i:i))) ! нужно выполнить для вывода строки с текстом
if(k > 47 .and. k < 58) then ! Цифры 0, 1, ..., 9
ars(i) = k - 47
else if(k == 45 .or. k == 46) then
ars(i) = k - 34 ! Знаки - и .
else if(k == 58) then
ars(i) = 19 ! Двоеточие
else if(k == 69) then ! Буква e
ars(i) = 13
else if(k == 43) then
ars(i) = 14 ! Знак +
else if(k > 119 .and. k < 123) then ! Буквы x, y и z
ars(i) = k - 105
else
ars(i) = 18 ! Пробел
end if
end do
if(gt == 'y') ars = ars + mli
call fglPushAttrib(gl_list_bit) ! Сохраняем атрибуты изображения
! Номер выполняемой команды будет равен ars(i)
call fglCallLists(lens, gl_short, loc(ars))
call fglPopAttrib( ) ! Восстанавливаем атрибуты изображения
end subroutine printString
end module figures
!
! Модуль points содержит процедуры:
! initGL - выполняет инициализацию окна OpenGL
! setVars - вычисляет протяженность осей координат и шаги координатной сетки
! fgrid - находит шаг координатной сетки и область ее отображения по оси x или y
! gridt - подпрограмма, выводящая линии координатной сетки и их координаты
module points
use figures ! Содержит ссылку на модуль opengl.mod
! Число выводимых графиков
integer(4) :: kF
character(1), allocatable, dimension(:) :: ifun
! Число используемых для вывода графика точек
integer(4) :: npox
! gridval = .TRUE., если сетка отображается
! coordval = .TRUE., если выводятся координаты
logical(4) :: gridval, coordval
! Шаги координатной сетки по осям x и y
real(4) :: gridx, gridy
! Число шагов координатной сетки по осям x и y
integer(4), parameter :: ngx = 5, ngy = ngx
! px, py - массивы, задающие выводимые кривые
real(4), allocatable, dimension(:, :) :: px, py
real(4) :: xl, xr, yb, yt ! Протяженность осей координат
! Массив цветов для графиков функций
real(4), allocatable, dimension(:, :) :: cols
real(4) :: xmi1, xma1, ymi1, yma1
logical(4) :: fzer = .true. ! fzer = .false., когда 0.0 не выводится по оси y
! Образец для вывода координатной сетки (пунктир)
integer(2) :: pattern = 2#0011001100110011
contains
subroutine initGL(cmpn) ! Инициализация окна OpenGL
character(*) :: cmpn
! w, h - начальные размеры окна вывода
integer(4) :: result = 0, w = 629, h = 191
character(100) :: ttl
ttl = trim(cmpn) // char(0)
call fauxInitDisplayMode(aux_single .or. aux_rgb)
call fauxInitPosition(100, 50, w, h)
result = fauxInitWindow(ttl)
end subroutine initGL
subroutine setVars(xmi, xma, ymi, yma)
real(4) :: xmi, xma, ymi, yma
real(4) :: addx, addy, rk
! Вычисляем gridx и gridy - шаги координатной сетки по осям x и y
xmi1 = xmi; xma1 = xma; ymi1 = ymi; yma1 = yma
gridx = fgrid(xmi1, xma1, ngx) ! gridx - шаг координатной сетки по оси x
! xmi1, xma1 - область отображения координатной сетки по оси x
gridy = fgrid(ymi1, yma1, ngy)
! Координаты xmi1, xma1, ymi1, yma1 задают границы координатной сетки
! Координаты xl, xr, yb, yt используем для задания области вывода
rk = 0.1
addx = rk * (xma1 - xmi1) ! Увеличиваем протяженность осей координат
addy = rk * (yma1 - ymi1) ! x и y соответственно на 2 * addx и 2 * addy
xl = xmi1 - 1.4 * addx; xr = xma1 + 0.6 * addx
yb = ymi1 - 1.2 * addy; yt = yma1 + 0.8 * addy
end subroutine setVars
! fgrid - функция модуля points; содержит функцию tita, возвращающую
! границу области отображения координатной сетки
! Находит шаг координатной сетки и область ее отображения по оси x или y
function fgrid(ti, ta, ng)
real(4) :: fgrid, ti, ta
integer(4) ng, k
fgrid = (ta - ti) / float(ng)
k = 0
if(fgrid < 1.0) then
do while(fgrid <= 1.0)
k = k + 1
fgrid = fgrid * 10.0
end do
fgrid = aint(fgrid) / float(10 ** k)
else if(fgrid > 10.0) then
do while(fgrid > 10.0)
k = k + 1
fgrid = fgrid / 10.0
end do
fgrid = aint(fgrid) * float(10 ** k)
else
fgrid = aint(fgrid)
end if
! ti, ta - границы области отображения координатной сетки
ti = tita(ti, 1)
ta = tita(ta, 2)
contains ! tita - процедура функции fgrid
function tita(t, k) ! ti и ta должны быть кратны fgrid
real(4) :: tita, t ! t - граница области отображения сетки
integer(4) :: k ! k = 1, если рассматривается ti, k = 2, если - ta
tita = 0.0
if(t < 0.0) then
do while(tita > t)
tita = tita - fgrid
end do
if(k == 2) tita = tita + fgrid
else
do while(tita < t)
tita = tita + fgrid
end do
if(k == 1) tita = tita - fgrid
end if
end function tita
end function fgrid
! Подпрограмма, выводящая линии координатной сетки и их координаты
! Содержит процедуры:
! fgs - находит шаг координатной сетки в оконных координатах
! outString - формирует строку strin,
! которая содержит координаты выводимой линии
! makeStrin - формирует строку, которая используется для вывода координат сетки
subroutine gridt(ti1, ta1, ti2, ta2, ti3, ta3, gt, grid)
real(4) :: ti1, ta1, ti2, ta2, ti3, ta3 ! Протяженность осей координат
character(1) :: gt ! Вид линий: 'x' или 'y'
! strin - строка, содержащая координату линии координатной сетки
character(10) :: strin
! grid - шаг координатной сетки
real(4) :: t, pt1(3), pt2(3), pt3(3), grid
logical(4) :: fl
integer(4) :: gs ! Шаг сетки в оконных координатах
integer(4) :: tcur, tlast ! tlast - координата последнего вывода текста
! Применяется для предотвращения наложения строк,
! содержащих координаты сетки. Перекрытие строк может возникнуть при
! незначительной ширине (высоте) окна вывода
gs = fgs( )
tlast = 0
tcur = 0 ! Текущая позиция вывода текста
! Находим положение первой выводимой линии координатной сетки
t = ti1 - grid
do while(t < ta1) ! Вывод линий координатной сетки
fl = .true. ! Истина, если линии выводятся
t = t + grid ! Если gt = 'x', то выводятся x-линии
!!if(abs(t) < 0.9 * grid) fl = .false.
if(gt == 'x') then
pt1 = (/ t, ti2, ti3 /)
pt2 = (/ t, ta2, ti3 /)
else if(gt == 'y') then
pt1 = (/ ti2, t, ti3 /)
pt2 = (/ ta2, t, ti3 /)
end if
if(coordval) call outString( ) ! Вывод координат или имени оси координат
if(fl) then
call fglBegin(gl_lines) ! Вывод очередной линии координатной сетки
call fglVertex3fv(loc(pt1))
call fglVertex3fv(loc(pt2))
call fglEnd( )
end if
end do
contains
! fgs, outString и makeStrin - внутренние процедуры подпрограммы gridt
! fgs - находит шаг координатной сетки в оконных координатах
function fgs( )
integer(4) :: fgs, k ! k - номер измерения
real(8), dimension(4, 4) :: modelMatrix, projMatrix
integer(4), dimension(4) :: viewport
real(8) :: win1(2), win2(2), pt(4), ptn(4)
call fglGetDoublev(gl_modelview_matrix, loc(modelMatrix))
call fglGetDoublev(gl_projection_matrix, loc(projMatrix))
call fglGetIntegerv(gl_viewport, loc(viewport))
select case(gt)
case('x'); k = 1; pt = (/ ti1, ti2, ti3, 1.0 /)
case('y'); k = 2; pt = (/ ti2, ti1, ti3, 1.0 /)
end select
ptn = matmul(matmul(projMatrix, modelMatrix), pt)
win1 = (ptn(1:2) + 1.0_8) * dfloat((viewport(3:4) - viewport(1:2)) / 2)
pt(k) = pt(k) + real(grid, 8)
ptn = matmul(matmul(projMatrix, modelMatrix), pt)
win2 = (ptn(1:2) + 1.0_8) * dfloat((viewport(3:4) - viewport(1:2)) / 2)
win1 = win2 - win1
fgs = int(sqrt(sum(win1 * win1)))
end function fgs
! outString - внутренняя процедура подпрограммы gridt
subroutine outString( ) ! Формирует и выводит строку с текстом
integer(4) :: slen ! Длина строки с выводимым текстом
! Формируем строку strin, которая содержит координаты выводимой линии
if(abs(t) > 0.1 * grid) then
call makeStrin(strin, t, gt)
else ! Выводится координата 0.0
strin = '0.0'
end if
tcur = tcur + gs ! Текущая позиция вывода текста
! Если не нужен вывод 0.0 по оси y
if(.not. fzer .and. gt == 'y' .and. strin == '0.0') return
if(tlast > 0) then ! Если выводится не первая координата
slen = len_trim(strin)
! Проверим, можно ли разместить новый текст без перекрытий с предшествующим
if(gt == 'x') then
if(tcur - 2 * slen * spx < tlast) return
else ! gt = 'y'
if(tcur - 3 * spy < tlast) return
end if
end if
tlast = tcur ! Текст можно разместить без перекрытий
! Вывод сформированной строки strin
! Растровая позиция первой цифры строки strin
call fglRasterPos2fv(loc(pt1))
! Вывод координат
call printString(trim(strin), gt)
end subroutine outString
! makeStrin - внутренняя процедура подпрограммы gridt
! Формирует строку, которая используется для вывода координат сетки
subroutine makeStrin(strin, t, gt)
character(*) strin, gt
real(4) :: t
! Максимальное число позиций для координат - 5; минимальное - 3
real(4) :: ctpmin = 0.0099, ctmmax = -0.099
! Если 0.0010 <= t <= 9999., то используется формат F
! Если -999. <= t <= -0.010, то также используется формат F
! Если 9999. < t <= .9e+9), используется формат E5.1e1
! Если t = 0, то возвращается '0.0'
! Во всех остальных случаях возвращается пробел
integer(4), parameter :: np = 7, nm = 5
integer(4) :: k, i, j ! Номер выбранного в массиве fmt формата
character(1) :: ch
character(10), dimension(np) :: &
fmtp = (/ '(F5.4)', '(F4.3)', '(F3.2)', '(F3.1)', '(F3.0)', '(F4.0)', '(F5.0)' /)
character(10), dimension(nm) :: fmtm = (/ '(F5.3)', '(F4.2)', '(F4.1)', '(F4.0)', '(F5.0)' /)
character(10) :: fmt
fmt = ' '
if(t >= 0.00095 .and. t < 10000. .or. t >= -999. .and. t <= -0.0095) then
k = 1
if(t > 0) then
! (Минимальное положительное значение) * 10 для формата F
ct = ctpmin
do while(ct <= t .and. k < np)
k = k + 1
ct = ct * 10
end do
else
! (Максимальное отрицательное значение) / 10 для формата F
ct = ctmmax
do while(ct > t .and. k < nm)
k = k + 1
ct = ct * 10
end do
end if
! if(t >= 0.0010 .and. t < 0.0100) fmt = '(F5.4)'
! if(t >= 0.010 .and. t < 0.100) fmt = '(F4.3)'
! if(t >= 0.10 .and. t < 1.00) fmt = '(F3.2)'
! if(t >= 1.0 .and. t < 10.0) fmt = '(F3.1)'
! if(t >= 10.0 .and. t < 100.0) fmt = '(F3.0)'
! if(t >= 100.0 .and. t < 1000.0) fmt = '(F4.0)'
! if(t >= 1000.0 .and. t < 10000.0) fmt = '(F5.0)'
!
! if(t <= -0.010 .and. t > -0.100) fmt = '(F5.3)'
! if(t <= -0.10 .and. t > -1.00) fmt = '(F5.2)'
! if(t <= -1.0 .and. t > -10.0) fmt = '(F4.1)'
! if(t <= -10. .and. t > -100.) fmt = '(F4.0)'
! if(t <= -100. .and. t > -1000.) fmt = '(F5.0)'
if(t > 0) then
fmt = fmtp(k)
else
fmt = fmtm(k)
end if
else if(t > 0.0 .and. t <= .9e+9) then
fmt = '(e5.1e1)'
else if(abs(t) < tiny(t)) then
strin = '0.0'
return
else
strin = ' '
return
end if
write(strin, fmt) t ! Преобразование число - строка
! Меняем порядок следования символов в строке
if(gt == 'y') then
k = len_trim(strin)
do i = 1, k / 2
ch = strin(i:i)
j = k - i + 1
strin(i:i) = strin(j:j)
strin(j:j) = ch
end do
end if
end subroutine makeStrin
end subroutine gridt
end module points
!
! Содержит интерфейсы подпрограмм myReshape1 и display1
! Подпрограммы myReshape1 и display1 должны обладать атрибутом EXTENAL
module GLface2
interface
subroutine myReshape1(w, h)
!ms$ attributes stdcall, alias : '_myReshape1@8' :: myReshape1
integer(4) :: w, h
end subroutine myReshape1
subroutine display1( )
!ms$ attributes stdcall, alias : '_display1@0' :: display1
end subroutine display1
end interface
end module GLface2
!
! Вывод графика цены и линии тренда или индикатора ТА
program curve
use points
implicit none
character(100) :: pth = 'c:\FoxMicex\'
character(250) :: fnKF = 'kFFls.txt', fnTtl = 'ttl.txt', fn
character(100) cmpn, bs
character(10), allocatable, dimension(:) :: kFFls
character(1) :: st
integer :: k, n
real :: vlxN, vlxX, vlyN = huge(1.0), vlyX = -huge(1.0)
fnKF = trim(pth) // trim(fnKF)
fnTtl = trim(pth) // trim(fnTtl)
! Title file
open(1, file = fnTtl)
read(1, *) cmpn
read(1, *) bs
read(1, *) vlxN
read(1, *) vlxX
close(1)
! Types of unloaded files
open(1, file = fnKF)
kF = 0
do while(.NOT. eof(1))
kF = kF + 1
read(1, *) st
read(1, *) st
end do
allocate(kFFls(kF), ifun(kF), cols(4, kF))
rewind 1
kF = 0
do while(.NOT. eof(1))
kF = kF + 1
read(1, *) kFFls(kF)
read(1, *) ifun(kF), cols(:, kF)
end do
close(1)
fn = trim(pth) // trim(kFFls(1)) // '.txt'
open(1, file = fn)
! npox - число точек, используемых при выводе графика
npox = 0
do while(.NOT. eof(1))
npox = npox + 1
read(1, *) st
end do
close(1)
allocate(px(npox, kF), py(npox, kF))
do k = 1, kF
if(ifun(kF) /= 'N') call fllNVl( )
end do
! Вывод выполняется на белом фоне; оси координат выводятся черным цветом
cmpn = trim(cmpn) // '; base = ' // trim(bs)
call drawCurve(cmpn, vlxN, vlxX, vlyN, vlyX, .true., .true.)
contains
subroutine fllNVl( )
real y
integer m
fn = trim(pth) // trim(kFFls(k)) // '.txt'
open(1, file = fn)
m = 0
do while(.NOT. eof(1))
m = m + 1
read(1, *) px(m, k), y
py(m, k) = y
if(ifun(k) == 'F' .and. y == 0.0) cycle
vlyN = min(vlyN, y)
vlyX = max(vlyX, y)
end do
close(1)
end subroutine fllNVl
end program curve
!
! Подпрограмма вывода графиков функций одной переменной
subroutine drawCurve(cmpn, xmi, xma, ymi, yma, grid, coords)
use msfwin
use points
use GLface2 ! Содержит интерфейсы myReshape1 и display1
character(*) :: cmpn
real(4) :: xmi, xma, ymi, yma ! Диапазоны изменения координат
logical(4) :: grid, coords ! grid = .TRUE., когда отображается сетка
real(4) :: x, y, dx ! coords = .TRUE., когда выводятся координаты
integer(4) :: i, j
gridval = grid
coordval = coords ! coordval = .TRUE., если выводятся координаты
! Вычисляем протяженность осей координат и шаги координатной сетки (см. points.f90)
call setVars(xmi, xma, ymi, yma)
! Смотрим, нужно ли выводить 0.0 по оси y (не нужно, если нижний левый угол
! графика - это начало координат)
if(abs(xmi1) < tiny(xmi1) .and. abs(ymi1) < tiny(ymi1)) fzer = .false.
call initGL(cmpn) ! Выводятся графики вида y = f(x) (см. points.f90)
! Формирование списков команд, пригодных для вывода текста (см. figures.f90)
call makeFigures()
! При изменении размеров окна вызывается подпрограмма myReshape1
call fauxReshapeFunc(loc(myReshape1))
! Подпрограмма display1 выполняет роль оконной процедуры
! Вызывается каждый раз при перемещении и изменении размеров окна вывода
! и выводит оси координат, координатную сетку и графики функций
call fauxMainLoop(loc(display1))
deallocate(px, py)
end subroutine drawCurve
!
subroutine myReshape1(w, h)
!ms$ attributes stdcall, alias : '_myReshape1@8' :: myReshape1
use points ! Подпрограмма, формирующая матрицу проецирования
integer(4) :: w, h
call fglViewport(0, 0, w, h) ! Задание видового порта
call fglMatrixMode(gl_projection); call fglLoadIdentity( )
call fgluOrtho2D(xl, xr, yb, yt)
end subroutine myReshape1
!
! Выводит оси координат, координатную сетку и графики функций
subroutine display1( ) ! Вывод изображения
!ms$ attributes stdcall, alias : '_display1@0' :: display1
use points
integer(4) :: i, j
real(4) :: cc(3), x, y, y2
logical chClr
call fglClearColor(1.0, 1.0, 1.0, 1.0) ! Цвет фона - белый
call fglClear(gl_color_buffer_bit) ! Очистка буфера цвета
call fglColor3f(0.0, 0.0, 0.0) ! Текущий цвет - черный
call fglLineWidth(1.0)
if(gridval) then ! Вывод координатной сетки по образцу
call fglLineStipple(2, pattern) ! Повторяем каждый бит образца 2 раза
! Теперь вывод линии будет выполняться с применением образца
call fglEnable(gl_line_stipple)
call gridt(xmi1, xma1, ymi1, yma1, 0.0, 0.0, 'x', gridx)
call gridt(ymi1, yma1, xmi1, xma1, 0.0, 0.0, 'y', gridy)
call fglDisable(gl_line_stipple)
end if
if(1 == 0) then
call fglBegin(gl_lines) ! Вывод осей координат (отключен)
call fglVertex2f(xmi1, 0.0)
call fglVertex2f(xma1, 0.0)
call fglVertex2f(0.0, ymi1)
call fglVertex2f(0.0, yma1)
call fglEnd( )
call fglRasterPos2f(xma1, 0.0) ! Вывод имени оси x
letter = rasterfont(15, :)
call fglBitmap(spx, spy, 10.0, -4.0, 0.0, 0.0, loc(letter))
call fglRasterPos2f(0.0, yma1) ! Вывод имени оси y
letter = rasterfont(16, :)
call fglBitmap(spx, spy, -4.0, 10.0, 0.0, 0.0, loc(letter))
end if
! Вывод на экран осей координат и сетки
call fglFlush( )
! Вывод графиков функций
do j = 1, kF
if(ifun(j) == 'S' .or. ifun(j) == 'N') cycle
! cc - текущий цвет
cc = cols(1:3, j)
call fglColor3fv(loc(cc))
select case(ifun(j))
case('T')
call fglLineWidth(1.0)
call fglBegin(gl_lines)
call fglVertex2f(px(1, j), py(1, j))
call fglVertex2f(px(2, j), py(2, j))
call fglEnd( )
! Отображение графика на экране
call fglFlush( )
case('L')
call fglLineWidth(1.0)
call fglBegin(gl_line_strip)
do i = 1, npox
call fglVertex2f(px(i, j), py(i, j))
end do
call fglEnd( )
call fglFlush( )
case('D')
call fglLineStipple(2, pattern)
call fglEnable(gl_line_stipple)
call fglLineWidth(1.0)
call fglBegin(gl_line_strip)
do i = 1, npox
call fglVertex2f(px(i, j), py(i, j))
end do
call fglEnd( )
call fglFlush( )
call fglDisable(gl_line_stipple)
case('P')
call fglPointSize(2.0)
call fglBegin(gl_points)
do i = 1, npox
call fglVertex2f(px(i, j), py(i, j))
end do
call fglEnd( )
call fglFlush( )
case('C') ! Columns from y = 0
chClr = cols(4, j) == 1.0
call fglLineWidth(2.0)
do i = 1, npox
x = px(i, j)
y = py(i, j)
call fglBegin(gl_lines)
call fglVertex2f(x, 0.0)
call fglVertex2f(x, y)
call fglEnd( )
if(chClr) call stCrrntClr(i)
end do
call fglFlush( )
case('V') ! Verticle lines
call fglLineWidth(2.0)
do i = 1, npox
x = px(i, j)
call fglBegin(gl_lines)
call fglVertex2f(x, py(i, j))
call fglVertex2f(x, py(i, j + 1))
call fglEnd( )
end do
call fglFlush( )
case('F') ! Fractals
call fglPointSize(5.0)
call fglBegin(gl_points)
do i = 1, npox
if(py(i, j) == 0.0) cycle
call fglVertex2f(px(i, j), py(i, j))
end do
call fglEnd( )
call fglFlush( )
end select
end do
contains
subroutine stCrrntClr(k)
integer k
if(k < npox) then
y = py(k, j)
y2 = py(k + 1, j)
if(y < y2) then
cc = (/ 0.0, 1.0, 0.0 /)
elseif(y > y2) then
cc = (/ 1.0, 0.0, 0.0 /)
else
cc = (/ 0.0, 0.0, 1.0 /)
end if
call fglColor3fv(loc(cc))
end if
end subroutine stCrrntClr
end subroutine display1
Используется платформа Compaq Visual Fortran 6.6a. В меню Tools – Options – Directories – Include files указана директория C:\Program Files\Microsoft Visual Studio\DF98\Include. В том же меню для Library files указана директория C:\Program Files\Microsoft Visual Studio\DF98\Lib.
С деталями и примерами программирования на Фортране с использованием OpenGL можно познакомиться в [5-7].
Линия Поддержки (ЛП, Support Line) на заданном временном промежутке проходит через точку с минимальной ценой (рис. 7) и, наоборот, Линия Сопротивления (ЛС, Resistance Line) на том же временном промежутке проходит через точку с максимальной ценой.
Рис. 7. Линии поддержки и сопротивления
Эти линии образуют коридор поддержки (КП), в пределах которого изменяется цена актива. При незначительной волатильности можно надеяться, что границы продолженного в будущее коридора не будут нарушены. Тогда при приближении цены к ЛП трейдер вправе ожидать последующего роста цены актива и, наоборот, при подходе к ЛС цена актива, скорее всего, начнет в скором будущем снижаться.
Если же цена варьируется вблизи границы КП, а затем выходит за его пределы (пробивает ЛП или ЛС), то можно предположить, что наблюдаемый тренд обладает значительной силой. Поэтому в случае пробития ЛП (нисходящий тренд) трейдер получает сигнал к продаже актива, а в случае восходящего тренда (пробита ЛС) – сигнал на покупку актива.
КП может быть использован трейдером для задания защитных стоп-приказов.
Положение ЛП и ЛС постоянно меняется под действием разных факторов:
Если после пробоя ЛП некоторое время сохраняется нисходящий тренд, постепенно переходящий в боковой, то ЛП превращается в ЛС, а новое положение ЛП определяется по ценам актива, наблюдаемым после пробоя ЛП. То же справедливо и для ЛС, которая будучи пробитой может далее рассматриваться как ЛП.
Пробой КП может носить временный характер, и цены вновь окажутся в пределах коридора. Возврат цен в КП может быть, в частности, обусловлен сомнениями трейдеров в обоснованности пробоя КП. Так, возврат в КП можно наблюдать, если при его пробое объем торгов был незначителен. В период осмысления, наступающий через некоторое время после пробоя КП, объем торгов ненадолго может вырасти. Однако если сомнения в обоснованности новой цены возобладают, то цена вернется в КП. При этом, если была пробита ЛП, то прервется нисходящий тренд, и в минусе окажутся медведи, а если – ЛС, то прервется восходящий тренд, и проиграют быки.
Если же пробой произошел на больших объемах, то тренд окажется, скорее всего, устойчивым, и возврата в прежний КП не будет.
Отладка процедур расчета индикаторов ТА поддерживается приведенной на рис. 8 формой.
Рис. 8. Форма отладки процедур вычисления индикаторов ТА
После нажатия на кнопку с именем индикатора ТА, выполняется расчет индикатора выбранного актива в пределах указанной даты и если установлен флажок Выгружать, то формируется необходимое число файлов с рассчитанными значениями. Выгруженные данные употребляются для построения графика индикатора.
Вычисление индикатора предваряет обращение к функции prpsT, извлекающей необходимые расчетные данные.
Результаты расчета переносятся процедурой svMVDtFls в mVDt-файлы для последующей визуализации.
*
* Подготовка к расчету индикатора ТА
FUNCTION prpsT(oForm, pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt, n)
WITH oForm
PDtVl = .PDt.Value
IDSVl = .IDSlct
opgACVl = .OpgAC.Value
opgACVl2 = .OpgAC2.Value
chckNldVl = .ChckNld.Value
DO CASE
CASE opgACVl2 = 2
slctVl = 'hgh'
prcKndVl = 'High_'
CASE opgACVl2 = 3
slctVl = 'lw'
prcKndVl = 'Low_'
CASE opgACVl2 = 4
slctVl = 'cls'
prcKndVl = 'Close_'
CASE opgACVl2 = 5 OR opgACVl2 < 2
slctVl = '0.5 * (hgh + lw)'
prcKndVl = 'Median_'
CASE opgACVl2 = 6
slctVl = '(hgh + lw + cls) / 3.0'
prcKndVl = 'Typical_'
ENDCASE
ENDWITH
DIMENSION rrMV[3]
rrMV[1] = 'S'
rrMV[2] = 'E'
rrMV[3] = 'V'
prcKndVl = prcKndVl + rrMV[opgACVl] + 'MA'
pDtVl2 = pDtVl - IIF(DOW(pDtVl) = 2, 3, 1)
ali0 = 'stcksTrdngF'
ali = 'crStcksTrdng'
tbl = _tmpPth + ali
SELECT &slctVl AS mV, pn, cls, hgh, lw, vlm, DAY(dt) AS dy,;
TRANSFORM(HOUR(dt)) + ":" + IIF(MINUTE(dt) > 5, TRANSFORM(MINUTE(dt)),;
'0' + TRANSFORM(MINUTE(dt))) AS tm;
FROM (ali0);
WHERE IDS = IDSVl;
AND TTOD(dt) BETWEEN pDtVl2 AND pDtVl;
ORDER BY dt;
INTO TABLE (tbl)
rCnt = _TALLY
IF rCnt < n
MESSAGEBOX("Number of selected records < n = " + TRANSFORM(n))
RETURN .F.
ENDIF
RETURN .T.
ENDFUNC && prpsT
*
* Выгрузка индикатора ТА в mVDt-файлы (режим отладки)
PROCEDURE svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, gTp, n, arrFlds, sBsVl, llVl)
LOCAL k, kFFlsWrdVl, mvBsVl, mVDtVl, flNmVl
IF chckNldVl
* Kind of files
kFFlsWrdVl = 'mVDt' + _NEXTLINE + gTp
mvBsVl = nldMv(ali, IDSVl, pDtVl, 'ttl2.txt', ttlVl, prcKndVl, arrFlds[1], sBsVl, 0, _prjPth + 'mVDt.txt', llVl)
FOR k = 2 TO n
mVDtVl = 'mVDt' + TRANSFORM(k)
kFFlsWrdVl = kFFlsWrdVl + _NEXTLINE + mVDtVl + _NEXTLINE + gTp
flNmVl = _prjPth + mVDtVl + '.txt'
nldMv(ali, IDSVl, pDtVl, '', '', '', arrFlds[k], .F., mVBsVl, flNmVl, llVl)
NEXT
* Create file kFFls2.txt with types of unloaded files
STRTOFILE(kfFlsWrdVl, _prjPth + 'kFFls2.txt')
MESSAGEBOX('mvDt-file' + IIF(n = 1, ' is', 's are') + ' created')
ENDIF
GO TOP
BROWSE LAST
ENDPROC && svMVDtFls
Описание берется из указанных в конце работы источников и приводится при необходимости к следующей схеме:
Далее приводятся программа, обеспечивающая расчет графика индикатора и его выгрузку в текстовый файл (в некоторых случаях формируются несколько файлов). Предваряется заголовком Программа.
Часть программ оформлены в виде процедур, имеющих параметр hwVl (принимает значения 1 или 2). Вызов с hwVl = 1 выполняется из формы отладки кода расчета индикатора, вызов с hwVl = 2 выполняется из формы оценки эффективности индикатора.
При описании индикатора ТА употребляются ранее введенные обозначения.
В формулах вычисления индикаторов ТА нередко используются скользящее среднее значение. В таких формулах на месте скользящего среднего употребляется имя МА, означающее либо SMA, либо EMA, либо VMA.
Прочие обозначения поясняются по месту описания индикатора.
Аллигатор (Alligator) Б. Вильямса (B. Williams) – это комбинация трех линий баланса Челюсть, Зубы и Губы Аллигатора (Alligators jaw, teeth и lips, рис. 9).
Рис. 9. Аллигатор (график цены показан черным цветом)
По умолчанию челюсти Аллигатора отображаются синей, зубы – красной, а губы – зеленой линиями. Для первой линии по умолчанию используется 13-интервальная MA, смещенная на 8 баров в будущее, для второй – 8-интервальная MA, смещенная на 5 баров в будущее, а для третьей – 5-интервальная MA, смещенная на 2 бара в будущее. По умолчанию для всех трех линий берется медианная цена. График цены показан на рисунке черной линией.
Расчет:
ALLIGATORS_JAW = MA(M, B1, C1)
ALLIGATORS_TEETH = MA(M, B2, C2)
ALLIGATORS LIPS = MA(M, B3, C3),
где Bi – период сглаживания, Ci – сдвиг в будущее.
Использование:
С помощью Аллигатора можно определить направление тренда или его отсутствие.
Также Аллигатор помогает в определении разметки волн Эллиотта: если цена находится за пределами пасти Аллигатора, то возможно формирование импульсной волны, если – внутри пасти, то есть предпосылки для формирования корректирующей волны.
Программа (с заданными по умолчанию параметрами):
При вызове программы в результате нажатия на кнопку Fractals наряду с Аллигатором выводятся и Фракталы. Если же нажата кнопка Gator, то будет выведен Гатор осциллятор
* Click-обработчик кнопки Alligator
clcltLlgtr(thisForm, .F., .F., 1)
* Расчет и оценка индикатора Alligator
PROCEDURE clcltLlgtr(oFrm, frctlsVl, gtrVl, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
a1 = 13
c1 = 8
a2 = 8
c2 = 5
a3 = 5
c3 = 3
IF hwVl = 1
LOCAL chckNldVl
* See someprocs.prg
prpsVl = prpsT(oFrm, @PDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, a1 + c1 + 1)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD ajw N(8, 2) ADD ath N(8, 2) ADD alp N(8, 2)
IF opgACVl = 2
GO c1
aJwVl = mV
GO c2
aThVl = mV
GO c3
aLpVl = mV
ENDIF
FOR k = a1 + c1 TO rCnt
rStrt1 = k - a1 - c1 + 1
rStrt2 = k - a2 - c2 + 1
rStrt3 = k - a3 - c3 + 1
rNd1 = rStrt1 + a1 - 1
rNd2 = rStrt2 + a2 - 1
rNd3 = rStrt3 + a3 - 1
DO CASE
CASE opgACVl = 1
aJwVl = clcSMA('mV', rStrt1, rNd1)
aThVl = clcSMA('mV', rStrt2, rNd2)
aLpVl = clcSMA('mV', rStrt3, rNd3)
CASE opgACVl = 2
aJwVl = clcEMA('mV', aJwVl, rStrt1, a1)
aThVl = clcEMA('mV', aThVl, rStrt2, a2)
aLpVl = clcEMA('mV', aLpVl, rStrt3, a3)
CASE opgACVl = 3
aJwVl = clcSMA('mV * vlm', rStrt1, rNd1) / clcSMA('vlm', rStrt1, rNd1)
aThVl = clcSMA('mV * vlm', rStrt2, rNd2) / clcSMA('vlm', rStrt2, rNd2)
aLpVl = clcSMA('mV * vlm', rStrt3, rNd3) / clcSMA('vlm', rStrt3, rNd3)
ENDCASE
GO k
REPLACE ajw WITH aJwVl ath WITH aThVl alp WITH aLpVl
NEXT
IF hwVl < 3
nFldsVl = IIF(frctlsVl, 7, IIF(gtrVl, 2, 4))
ELSE
nFldsVl = 11
ENDIF
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
ttlVl = TRANSFORM(a1) + '_' + TRANSFORM(a2) + '_' + TRANSFORM(a3) + ')'
IF NOT gtrVl
arrFlds[1] = 'ajw'
arrFlds[2] = 'ath'
arrFlds[3] = 'alp'
arrGTps[1] = 'L 0.0 0.0 1.0 0.0'
arrGTps[2] = 'L 1.0 0.0 0.0 0.0'
arrGTps[3] = 'L 0.0 1.0 0.0 0.0'
ttlVl = 'Alligator(' + ttlVl
ENDIF
DO CASE
CASE frctlsVl
ALTER TABLE (ali) ADD fp N(8, 2) ADD fm N(8, 2)
DIMENSION arrHVl[5], arrLVl[5]
FOR k = 1 TO 5
GO k
arrHVl[k] = hgh
arrLVl[k] = lw
NEXT
kFltVl = 0.0
FOR k = 6 TO rCnt
IF arrHVl[3] > arrHVl[1] AND arrHVl[3] > arrHVl[2] AND arrHVl[3] > arrHVl[4] AND arrHVl[3] > arrHVl[5]
GO k - 3
REPLACE fp WITH (1.0 + kFltVl) * hgh
ENDIF
IF arrLVl[3] < arrLVl[1] AND arrLVl[3] < arrLVl[2] AND arrLVl[3] < arrLVl[4] AND arrLVl[3] < arrLVl[5]
GO k - 3
REPLACE fm WITH (1.0 - kFltVl) * lw
ENDIF
FOR k2 = 1 TO 4
arrHVl[k2] = arrHVl[k2 + 1]
arrLVl[k2] = arrLVl[k2 + 1]
NEXT
GO k
arrHVl[5] = hgh
arrLVl[5] = lw
NEXT
arrFlds[4] = 'fp'
arrFlds[5] = 'fm'
arrFlds[6] = 'hgh'
arrFlds[7] = 'lw'
arrGTps[4] = 'F 1.0 0.0 0.0 0.0'
arrGTps[5] = 'F 0.0 0.0 1.0 0.0'
arrGTps[6] = 'V 0.0 0.0 0.0 0.0'
arrGTps[7] = 'S 0.0 0.0 0.0 0.0'
IF hwVl = 3
arrFlds[8] = 'bsg'
arrGTps[8] = 'V 1.0 0.0 0.0 0.0'
arrFlds[9] = 'bsg2'
arrGTps[9] = 'S 1.0 0.0 0.0 0.0'
arrFlds[10] = 'ssg'
arrGTps[10] = 'V 0.0 0.0 1.0 0.0'
arrFlds[11] = 'ssg2'
arrGTps[11] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Fractals_' + ttlVl
CASE gtrVl
arrFlds[1] = 'ajw - ath'
arrFlds[2] = 'alp - ath'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
arrGTps[2] = 'C 1.0 0.0 0.0 1.0'
ttlVl = 'Gator(' + ttlVl
OTHERWISE
arrFlds[4] = 'mV'
arrGTps[4] = 'L 0.0 0.0 0.0 0.0'
ENDCASE
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., gtrVl)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
fndNxtFrctl('fp', 'fm')
IF NOT EOF() AND mntBsVl = mntSllsVl AND mV < ath
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
fndNxtFrctl('fm', 'fp')
IF NOT EOF() AND mntSllsVl = mntBsVl - 1 AND mV > ath
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltLlgtr
PROCEDURE fndNxtFrctl(fldVl, fldVl2)
LOCAL sFnd
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND &fldVl = 0
SKIP
ENDDO
sFnd = .T.
kSkpVl = 0
DO WHILE NOT EOF() AND kSkpVl < 3
kSkpVl = kSkpVl + 1
SKIP
IF &fldVl > 0 OR &fldVl2 > 0
sFnd = .F.
EXIT
ENDIF
ENDDO
IF sFnd
RETURN
ENDIF
ENDDO
ENDPROC && fndNxtFrctl
Чудесный осциллятор (Awesome Oscillator, АО) Б. Вильямса (B. Williams) помогает определить текущее поведение движущей силы рынка (рис. 10).
Рис. 10. AO: сигналы на покупку
Индикатор аналогичен индикатору MACD: АО, как и MACD, колеблется вокруг нулевой отметки, но в отличие от MACD не имеет сигнальной линии. Индикатор OSC – это АО, взятый с обратным знаком.
Расчет:
AO = MA(P, Shrt) – MA(P, Lng), где
Shrt – протяженность короткого временного промежутка, по умолчанию равна 5;
Lng – протяженность длинного временного промежутка, по умолчанию равна 34.
По умолчанию P – это M.
Использование:
AO показывает отношение движущей силы (изменения рыночного равновесия) рынка краткосрочного временного промежутка Shrt по сравнению с долгосрочным Lng.
Как и MACD, АО подает сигналы разворота текущего движения.
Сигнал АО на покупку образуется:
Сигналы на продажу зеркальны. Сигнал АО на продажу образуется:
Сигналы АО можно использовать совместно с сигналами индикатора АС. В этом случае можно употребить следующую тактику:
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки AO
clcltAO(thisForm, 1, 5, 34)
* Расчет и оценка индикаторов AO и OSC
PROCEDURE clcltAO(oFrm, hwVl, sVl, lVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
csVl = 2
IF hwVl < 3
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, lVl)
ELSE && Режим оценки AO
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD ao N(8, 2)
IF opgACVl = 2
GO sVl
aSVl = mV
GO lVl
aLVl = mV
ENDIF
FOR k = lVl TO rCnt
rStrt1 = k - sVl + 1
rStrt2 = k - lVl + 1
DO CASE
CASE opgACVl = 1
aSVl = clcSMA('mV', rStrt1, k)
aLVl = clcSMA('mV', rStrt2, k)
CASE opgACVl = 2
aSVl = clcEMA('mV', aSVl, rStrt1, sVl)
aLVl = clcEMA('mV', aLVl, rStrt2, lVl)
CASE opgACVl = 3
aSVl = clcSMA('mV * vlm', rStrt1, k) / clcSMA('vlm', rStrt1, k)
aLVl = clcSMA('mV * vlm', rStrt2, k) / clcSMA('vlm', rStrt2, k)
ENDCASE
GO k
REPLACE ao WITH IIF(hwVl = 2, aLVl - aSVl, aSVl - aLVl)
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'ao'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
ttlVl = IIF(hwVl = 2, '', 'Awesome_') + 'Oscillator(' + TRANSFORM(sVl) + '-' + TRANSFORM(lVl) + ')'
IF hwVl < 3
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
*
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
CALCULATE MAX(mV) TO mVSllVl
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
GO TOP
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT fndScndMnOrXCrssng('ao') && Buy signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT fndScndMnOrXCrssng('-ao') && Sell signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
ENDIF
ENDPROC && clcltAO
*
* Retuns .T. if buy / sell signal is found
FUNCTION fndScndMnOrXCrssng(fld)
DO WHILE NOT EOF() AND &fld >= 0
SKIP
ENDDO
IF NOT EOF()
fldVl = &fld
SKIP
DO WHILE NOT EOF() AND &fld <= fldVl
fldVl = &fld
SKIP
ENDDO
IF NOT EOF() AND &fld < 0
fldVl2 = fldVl
DO WHILE NOT EOF() AND &fld < 0 AND &fld >= fldVl
fldVl = &fld
SKIP
IF NOT EOF()
IF &fld < 0
DO WHILE NOT EOF() AND &fld <= fldVl
fldVl = &fld
SKIP
ENDDO
IF NOT EOF()
IF &fld < 0
RETURN fldVl > fldVl2
*!* ELSE
*!* RETURN .T.
ENDIF
ENDIF
*!* ELSE
*!* RETURN .T.
ENDIF
ENDIF
ENDDO
ENDIF
ENDIF
RETURN .F.
ENDFUNC && fndScndMnOrXCrssng
Осциллятор Б. Вильямса (B. Williams) Ускорение/Замедление (Acceleration/Deceleration Oscillator, AC, рис. 11) измеряет ускорение/замедление движущей силы рынка (ДСР).
Рис. 11. AC-сигналы на покупку и на продажу "выше нулевой линии"
С помощью AO можно определить ДСР. AC информирует о динамике ДСР: AC положителен, если ДСР нарастает (ускорение), и отрицателен – в противном случае.
Расчет:
AC = AO – MA(AO, n)
Использование:
АС следует игнорировать, пока не появится первый фрактал на покупку (продажу) за пределами пасти Аллигатора.
Не следует покупать при замедлении и продавать при ускорении.
AC подает следующие сигналы:
Сигнал на покупку "выше нулевой линии" поступает, если появились два последовательных бара с более высокими значениями, чем последний наименьший бар (правое увеличение на рис. 11). Ордер Buy Stop размещается на 1 пипс выше максимума сигнального бара с.
Сигнал на продажу "выше нулевой линии" поступает, когда появились три последовательных бара с более низкими значениями, чем последний наибольший бар (см. левое увеличение на рис. 11). Ордер Sell Stop размещается на 1 пипс ниже минимума сигнального бара d.
Сигнал на покупку "ниже нулевой линии" подается, когда появились три последовательных бара с более высокими значениями, чем последний наименьший бар. Ордер Buy Stop размещается на 1 пипс выше максимума сигнального бара.
Сигнал на продажу "ниже нулевой линии" поступает, если появились два последовательных бара с более низкими значениями, чем последний наибольший бар. Ордер Sell Stop размещается на 1 пипс ниже минимума сигнального бара.
Если бар b или c лежит ниже нулевой линии, то c становится сигнальным.
Сигнал АС отменяется, если перед исполнением отложенного ордера гистограмма изменила цвет.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
Обработчик нажатия на кнопку AC вызывает процедуру clcltAC:
* Click-обработчик кнопки AC
clcltAC(thisForm, 1)
* Расчет и оценка индикатора AC
PROCEDURE clcltAC(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
sVl = 5
lVl = 34
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, lVl)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD ao N(8, 2) ADD ac N(8, 2)
lVl2 = lVl - sVl
IF opgACVl = 2
GO lVl2 + 1
aSVl = mV
GO 1
aLVl = mV
ENDIF
FOR k = lVl TO rCnt
DO CASE
CASE opgACVl = 1
aSVl = clcSMA('mv', k - sVl + 1, k)
aLVl = clcSMA('mv', k - lVl + 1, k)
CASE opgACVl = 2
aLVl = clcEMA('mv', aLVl, k, lVl)
aSVl = clcEMA('mv', aSVl, k, sVl)
CASE opgACVl = 3
aSVl = clcSMA('mv * vlm', k - sVl + 1, k) / clcSMA('vlm', k - sVl + 1, k)
aLVl = clcSMA('mv * vlm', k - lVl + 1, k) / clcSMA('vlm', k - lVl + 1, k)
ENDCASE
GO k
REPLACE ao WITH aSVl - aLVl
NEXT
IF opgACVl = 2
GO lVl + 1
aSVl = ao
ENDIF
FOR k = lVl + sVl TO rCnt
DO CASE
CASE opgACVl = 1
aSVl = clcSMA('ao', k - sVl + 1, k)
CASE opgACVl = 2
aSVl = clcEMA('ao', aSVl, k, sVl)
CASE opgACVl = 3
aSVl = clcSMA('ao * vlm', k - sVl + 1, k) / clcSMA('vlm', k - sVl + 1, k)
ENDCASE
GO k
REPLACE ac WITH ao - aSVl
NEXT
nFldsVl = IIF(hwVl < 3, 1, 5)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
IF hwVl < 3
arrFlds[1] = 'ac'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
ELSE
arrFlds[1] = 'mV'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'bsg'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'bsg2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
arrFlds[4] = 'ssg'
arrGTps[4] = 'V 0.0 0.0 1.0 0.0'
arrFlds[5] = 'ssg2'
arrGTps[5] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Accelerator_Decelerator_Oscillator(' + TRANSFORM(sVl) + '-' + TRANSFORM(lVl) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllSgnlSFnd('ac')
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllSgnlSFnd('-ac')
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltAC
*
* Retuns .T. if buy / sell signal is found
FUNCTION bSllSgnlSFnd(fld)
DO WHILE NOT EOF()
fldVl0 = &fld
SKIP
IF NOT EOF()
fldVl = &fld
SKIP
IF NOT EOF()
fldVl2 = &fld
IF fldVl < fldVl0 AND fldVl < fldVl2
SKIP
IF NOT EOF()
fldVl3 = &fld
IF fldVl3 > fldVl2
IF fldVl > 0
RETURN .T.
ELSE
SKIP
RETURN NOT EOF() AND &fld > fldVl3
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDDO
RETURN .F.
ENDFUNC && bSllSgnlSFnd
Индекс направления движения усредненной цены (Average Directional Movement Index, ADX, рис. 12) помогает определить направление движения среднего значения цены на основе индикаторов направленности +DI (индикатор позитивного направления движения цены, Positive Directional Index) и –DI (индикатор негативного направления движения цены, Negative Directional Index), построенных по 14 интервалам.
Рис. 12. ADX, +DI и –DI
На рис. 12 ADX показан красным, +DI – зеленым, а –DI – синим цветом.
Расчет:
В источниках имеются по крайней мере два способа расчета индикатора:
Один поддерживается следующей схемой:
Второй способ имеет некоторые отличия:
Использование (см. также +/–DM):
Если рынок консолидируется, то +DM и –DM будут равны нулю, сообщая об отсутствии движения. Чем больше разница между +DM и –DM, тем сильнее тренд. Тесное переплетение +DM и –DM говорит о незначительных колебаниях цены (о флэте).
Значения ADX находятся в диапазоне 0 – 100. Значение ниже 20 сигнализирует о слабом тренде, значение выше 40 – о сильном тренде (восходящем или нисходящем).
Сигналы ADX:
Сигнал на вход, поданный пересечением –DI и +DI, нередко (актив находится в торговом диапазоне) бывает ложным.
ADX показывает наличие или отсутствие тренда, а для определения точек и направления входа следует использовать +/–DM или иные индикаторы.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа (рассчитываются и выгружаются ADX, +DI и –DI):
* Click-обработчик кнопки ADX
clcltADX(thisForm, 1, 14)
* Расчет и оценка индикаторов ADX и +/-DM
PROCEDURE clcltADX(oFrm, hwVl, n, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
csVl = 2
IF hwVl < 3
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 2 * n)
ELSE && Режим оценки ADX
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD tr N(8, 2) ADD dmp N(8, 2) ADD dmm N(8, 2) ADD sdp2 N(8, 2)ADD sdm2 N(8, 2)
GO 1
clsVl = cls
hghVl = hgh
lwVl = lw
REPLACE tr WITH hgh - lw
FOR k = 2 TO rCnt
GO k
trVl = MAX(hgh - lw, ABS(hgh - clsVl), ABS(lw - clsVl))
dmHVl = MAX(hgh - hghVl, 0)
dmLVl = MAX(lwVl - lw, 0)
IF csVl = 2
DO CASE
CASE dmHVl > dmLVl
dmLVl = 0
CASE dmLVl > dmHVl
dmHVl = 0
CASE dmLVl = dmHVl
STORE 0 TO dmLVl, dmHVl
ENDCASE
ENDIF
REPLACE tr WITH trVl dmp WITH dmHVl dmm WITH dmLVl;
sdp2 WITH IIF(trVl = 0, 0, dmHVl / trVl) sdm2 WITH IIF(trVl = 0, 0, dmLVl / trVl)
clsVl = cls
hghVl = hgh
lwVl = lw
NEXT
STORE 0.0 TO trNVl, dmpNVl, dmmNVl
FOR k = 1 TO n
GO k
trNVl = trNVl + tr
dmpNVl = dmpNVl + dmp
dmmNVl = dmmNVl + dmm
NEXT
ALTER TABLE (ali) ADD dipN N(8, 2) ADD dimN N(8, 2) ADD dx N(8, 2)ADD adx N(8, 2);
ADD dipN2 N(8, 2) ADD dimN2 N(8, 2) ADD dx2 N(8, 2)ADD adx2 N(8, 2)
* Case 2
IF opgACVl = 2
STORE 0.0 TO dipNVl2, dimNVl2
FOR k = 1 TO n
GO k
dipNVl2 = dipNVl2 + sdp2
dimNVl2 = dimNVl2 + sdm2
NEXT
dipNVl2 = dipNVl2 / n
dimNVl2 = dimNVl2 / n
ENDIF
* Case 1 & 2
FOR k = n + 1 TO rCnt
* Case 1
GO k
trN2Vl = trNVl - trNVl / n + tr
dmpN2Vl = dmpNVl - dmpNVl / n + dmp
dmmN2Vl = dmmNVl - dmmNVl / n + dmm
dipNVl = 100 * dmpN2Vl / trN2Vl
dimNVl = 100 * dmmN2Vl / trN2Vl
dxVl = 100 * ABS(dipNVl - dimNVl) / (dipNVl + dimNVl)
REPLACE dipN WITH dipNVl dimN WITH dimNVl dx WITH dxVl
trNVl = trN2Vl
dmpNVl = dmpN2Vl
dmmNVl = dmmN2Vl
* Case 2
DO CASE
CASE opgACVl = 1
dipNVL2 = clcSMA('sdp2', k - n, k)
dimNVL2 = clcSMA('sdm2', k - n, k)
CASE opgACVl = 2
dipNVL2 = clcEMA('sdp2', dipNVL2, k, n)
dimNVL2 = clcEMA('sdm2', dimNVL2, k, n)
CASE opgACVl = 3
dipNVL2 = clcSMA('sdp2 * vlm', k - n, k) / clcSMA('vlm', k - n, k)
dimNVL2 = clcSMA('sdm2 * vlm', k - n, k) / clcSMA('vlm', k - n, k)
ENDCASE
dxVl2 = ABS(100 * (dipNVL2 - dimNVL2) / (dipNVL2 + dimNVL2))
REPLACE dipN2 WITH 100 * dipNVl2 dimN2 WITH 100 * dimNVl2 dx2 WITH dxVl2
NEXT
* Case 1
adxVl = 0
FOR k = n + 1 TO 2 * n
GO k
adxVl = adxVl + dx
NEXT
adxVl = adxVl / n
FOR k = 2 * n + 1 TO rCnt
GO k
adxVl = (adxVl * (n - 1) + dx) / n
REPLACE adx WITH adxVl
NEXT
* Case 2
n2 = 2 * n
IF opgACVl = 2
adxVl2 = 0
FOR k = n + 1 TO n2
GO k
adxVl2 = adxVl2 + dx2
NEXT
adxVl2 = adxVl2 / n
REPLACE adx2 WITH adxVl2
ENDIF
FOR k = n2 + 1 TO rCnt
kS = k - n + 1
DO CASE
CASE opgACVl = 1
adxVl2 = clcSMA('dx2', kS, k)
CASE opgACVl = 2
adxVl2 = clcEMA('dx2', adxVl2, k, n)
CASE opgACVl = 3
adxVl2 = clcSMA('dx2 * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE adx2 WITH adxVl2
NEXT
nFldsVl = IIF(MOD(hwVl, 2) = 1, 3, 2)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
dpNVl = 'dipN' + TRANSFORM(csVl)
dmNVl = 'dimN' + TRANSFORM(csVl)
arrFlds[1] = dpNVl
arrFlds[2] = dmNVl
arrGTps[1] = 'L 0.0 1.0 0.0 0.0'
arrGTps[2] = 'L 0.0 0.0 1.0 0.0'
IF nFldsVl = 3 && ADX
arrFlds[3] = 'adx' + TRANSFORM(csVl)
arrGTps[3] = 'L 1.0 0.0 0.0 0.0'
ttlVl = 'Average_Directional_Movement + TRANSFORM(csVl) + (' + TRANSFORM(n) + ')'
ELSE && DM
ttlVl = 'Directional_Movement(' + TRANSFORM(n) + ')'
ENDIF
IF hwVl < 3
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
ELSE
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
*
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
CALCULATE MAX(mV) TO mVSllVl
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
bWhnCrssBT(dpNVl, dmNVl, kVl, @smVl2, smVl, fpVl, @mntBsVl, @mntSllsVl, @stcsMntVl, @smLftVl2, @fVl, @mVSllVl, pDtVl)
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
ENDIF
ENDPROC && clcltADX
Индикатор Накопление/Распределение (Accumulation/Distribution, A/D) определяется изменением цены и объема (A/D является менее распространенным вариантом Индикатора Балансового Объема). Объем выступает в роли весового коэффициента при изменении цены: чем больше объем, тем значительнее вклад изменения цены в значение индикатора.
Рис. 13. A/D
Расчет:
A/Di = (2 * Ci – Li – Hi) * Vi / (Hi – Li) + A/Di–1, где i – номер интервала.
Использование:
Рост индикатора означает накопление (покупку) ценной бумаги, поскольку подавляющая доля объема торгов связана с восходящим движением цен. Падение индикатора означает распределение (продажу) ценной бумаги, поскольку подавляющая доля объема торгов связана с нисходящим движением цен.
Несоответствие A/D с ценой предупреждает о надвигающемся изменении цены. Обычно в таких случаях ценовая тенденция изменяет свое движение в сторону движения индикатора. Например, если индикатор падает, а цена актива растет, то вскоре возможен ее разворот вниз.
Программа:
* Click-обработчик кнопки A/D
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD cumad N(15, 2)
GO TOP
dhlVl = hgh - lw
cumadVl = IIF(dhlVl = 0, 0, (2.0 * cls - lw - hgh) * vlm / dhlVl)
FOR k = 2 TO rCnt
GO k
dhlVl = hgh - lw
cumadVl = cumadVl + IIF(dhlVl = 0, 0, (2.0 * cls - lw - hgh) * vlm / dhlVl)
REPLACE cumad WITH cumadVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'cumad'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Accumulation_Distribution', '', nFldsVl, @arrFlds, @arrGTps, .T., .T.)
Индекс товарного канала (Commodity Channel Index, CCI) измеряет отклонение цены актива от его среднестатистической цены (рис. 14).
Рис. 14. CCI
Расчет:
CCIi = (Ti – MAi(T, n)) / (MDi * 0.015), где MDi = sum(|MAi(T, n) – Ti|) / n
Высокие значения индекса указывают на то, что цена серьезно превышает среднюю цену, а низкие – на то, что цена слишком занижена.
Использование:
Программа:
* Click-обработчик кнопки CCI
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD ma N(8, 2) ADD cci N(8, 2)
IF opgACVl = 2
maVl = 0.0
FOR k = 1 TO n - 1
maVl = maVl + mV
NEXT
maVl = maVl / (n - 1)
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
DO CASE
CASE opgACVl = 1
maVl = clcSMA('mV', kS, k)
CASE opgACVl = 2
maVl = clcEMA('mV', maVl, k, n)
CASE opgACVl = 3
maVl = clcSMA('mV * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE ma WITH maVl
NEXT
n2 = 2 * n
FOR k = n2 + 1 TO rCnt
mdVl = clcSMA('ABS(ma - mV)', k - n2 + 1, k)
GO k
REPLACE cci WITH (mV - ma) / (0.015 * mdVl)
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'cci'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Commodity_Channel_Index(' + TRANSFORM(n) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Осциллятор Чайкина (Chaikin's Oscillator, ChO) – это разность скользящих средних индикатора A/D. Таким образом, ChO измеряет темп изменения A/D.
Рис. 15. ChO
Расчет:
ChO = MA(A/D, Shrt) – MA(A/D, Lng), где
Shrt – длительность короткого временного промежутка, по умолчанию равна 3,
Lng – длительность длинного интервала, по умолчанию равна 10.
Использование:
Сигналы на покупку.
Сигналы на продажу.
Употребляется совместно с индикаторами торгового диапазона (конверты скользящих средних, полосы Боллинжера и др.) и с индикаторами, которые показывают зоны перекупленности и перепроданности (RSI, SO, CCI и др.). Автор индикатора полагает, что сигналы в направлении текущей тенденции всегда более надежны, чем сигналы противоположные существующему тренду.
Недостаток: трудно интерпретировать резкие движения индикатора.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки ChO
clcltChO(thisForm, 1)
* Расчет и оценка индикатора ChO
PROCEDURE clcltChO(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
shrt = 3
lng = 10
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, lng)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD cumad N(15, 2) ADD cho N(15, 2)
GO TOP
dhlVl = hgh - lw
cumadVl = IIF(dhlVl = 0, 0, (2.0 * cls - lw - hgh) * vlm / dhlVl)
FOR k = 2 TO rCnt
GO k
dhlVl = hgh - lw
cumadVl = cumadVl + IIF(dhlVl = 0, 0, (2.0 * cls - lw - hgh) * vlm / dhlVl)
REPLACE cumad WITH cumadVl
NEXT
STORE 0 TO maVl, maVl2
IF opgACVl = 2
FOR k = 2 TO lng - 1
IF k < shrt
maVl = maVl + cumad
ENDIF
maVl2 = maVl2 + cumad
NEXT
maVl = maVl / (shrt - 1)
maVl2 = maVl2 / (lng - 1)
ENDIF
FOR k = shrt TO rCnt
kS = k - shrt + 1
kS2 = k - lng + 1
DO CASE
CASE opgACVl = 1
maVl = clcSMA('cumad', kS, k)
IF k >= lng
maVl2 = clcSMA('cumad', kS2, k)
ENDIF
CASE opgACVl = 2
maVl = clcEMA('cumad', maVl, k, shrt)
IF k >= lng
maVl2 = clcEMA('cumad', maVl2, k, lng)
ENDIF
CASE opgACVl = 3
maVl = clcSMA('cumad * vlm', kS, k) / clcSMA('vlm', kS, k)
IF k >= lng
maVl2 = maVl = clcSMA('cumad * vlm', kS2, k) / clcSMA('vlm', kS2, k)
ENDIF
ENDCASE
GO k
REPLACE cho WITH maVl - maVl2
NEXT
nFldsVl = IIF(hwVl < 3, 1, 5)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
IF hwVl < 3
arrFlds[1] = 'cho'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
ELSE
arrFlds[1] = 'mV'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'bsg'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'bsg2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
arrFlds[4] = 'ssg'
arrGTps[4] = 'V 0.0 0.0 1.0 0.0'
arrFlds[5] = 'ssg2'
arrGTps[5] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Chaikin_Oscillator(' + TRANSFORM(shrt) + '_' + TRANSFORM(lng) +')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT fndNxtMnMx('cho', 'mV') && Buy signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT fndNxtMnMx('-cho', '-mV') && Sell signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltChO
*
* Buy (sell) signal
FUNCTION fndNxtMnMx(fld, fld2)
fldVl = &fld
SKIP
DO WHILE NOT EOF() AND &fld >= fldVl && Move up
fldVl = &fld
SKIP
ENDDO
DO WHILE NOT EOF() AND &fld <= fldVl && Move down
fldVl = &fld
SKIP
ENDDO
fld2Vl = &fld2
DO WHILE NOT EOF() AND &fld2 >= fld2Vl && Move up
fld2Vl = &fld2
SKIP
ENDDO
DO WHILE NOT EOF() AND &fld2 <= fld2Vl && Move down
fld2Vl = &fld2
SKIP
ENDDO
RETURN NOT EOF() AND &fld > fldVl
ENDFUNC && fndNxtMnMx
Полосы Боллинджера (Bollinger Bands, BB) строятся вместе с графиком цены и представляют собой три линии, расстояние между которыми (ширина полос) пропорционально стандартному отклонению SD цены (рис. 16).
Рис. 16. BB (график цены показан черным цветом)
Расчет:
BBLower = MA(P, n) – k * SD(P, n) – нижняя ограничительная линия;
ВВMiddle = MA(P, n) – средняя скользящая;
BBUpper = MA(P, n) + k * SD(P, n) – верхняя ограничительная линия;
SD = SQRT(sum(P – MA(P, n))^2) / n) – стандартное отклонение цены.
По умолчанию n = 20, k = 2.
Использование:
Ширина полос зависит от устойчивости рынка: полоса расширяется при нестабильности рынка и сужается при более устойчивых ценах.
Интерпретация индикатора:
Движение цен, начавшееся от одной границы BB, нередко достигает противоположной границы BB.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки BB
clcltBB(thisForm, 1)
* Расчет и оценка индикатора BB
PROCEDURE clcltBB(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = 20
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
kSDVl = 2
ALTER TABLE (ali) ADD bbl N(8, 2) ADD bbm N(8, 2) ADD bbu N(8, 2)
IF opgACVl = 2
GO n
bbmVl = mV
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
* See someProcs.prg
DO CASE
CASE opgACVl = 1
bbmVl = clcSMA('mV', kS, k)
CASE opgACVl = 2
bbmVl = clcEMA('mV', bbmVl, k, n)
CASE opgACVl = 3
bbmVl = clcSMA('mV * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE bbm WITH bbmVl
NEXT
n2 = 2 * n
FOR k = n2 TO rCnt
kS = k - n + 1
* See someProcs.prg
sdVl = kSDVl * clcSD('mV', 'bbm', kS, k)
GO k
REPLACE bbl WITH bbm - sdVl bbu WITH bbm + sdVl
NEXT
nFldsVl = 4
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'bbl'
arrFlds[2] = 'bbm'
arrFlds[3] = 'bbu'
arrFlds[4] = 'mV'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
arrGTps[3] = 'L 0.0 0.0 1.0 0.0'
arrGTps[4] = 'L 0.0 0.0 0.0 0.0'
ttlVl = 'Bollinger_Bands(' + TRANSFORM(n) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .T., .F.)
ELSE
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
*
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
CALCULATE MAX(mV) TO mVSllVl
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
GO TOP
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllWhnCrrs('mV', 'bbl') && Buy signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllWhnCrrs('mV', 'bbu') && Sell signal
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
ENDIF
ENDPROC && clcltBB
*
* Buy / sell when fld & fld2 are crossing
PROCEDURE bSllWhnCrrs(fld, fld2)
DO WHILE NOT EOF()
fldVl = &fld
fld2Vl = &fld2
SKIP
IF NOT EOF()
IF fldVl <= fld2Vl AND &fld >= &fld2 OR fldVl >= fld2Vl AND &fld <= &fld2
RETURN .T.
ENDIF
ENDIF
ENDDO
RETURN .F.
ENDPROC && bSllWhnCrrs
Индикатор Конверты (Огибающие линии, Envelopes) включает две скользящие средние (MA). При этом одна МА строится со сдвигом вверх, а вторая – со сдвигом вниз. Огибающие линии (рис. 17) определяют верхнюю и нижнюю границы текущего торгового диапазона актива.
Рис. 17. Envelopes (график цены показан синим цветом)
Расчет:
LUp = MA(P, n) * (1 + k / 100) – верхняя линия;
LDown = MA(P, n) * (1 – k / 100) – нижняя линия
По умолчанию n = 20, k = 2.
Использование:
Сигнал продажи формируется, когда цена достигает верхней границы, а покупки – при достижении нижней границы. Оптимальное значение сдвига k зависит от волатильности актива: чем больше волатильность, тем выше сдвиг.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки Envelopes
clcltNvlps(thisForm, 1)
* Расчет и оценка индикатора Envelopes
PROCEDURE clcltNvlps(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = oFrm.SpinnerPrd.Value
kSD = 0.015
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD ml N(8, 2) ADD mu N(8, 2)
IF opgACVl = 2
GO n
maVl = mV
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
* See someProcs.prg
DO CASE
CASE opgACVl = 1
maVl = clcSMA('mV', kS, k)
CASE opgACVl = 2
maVl = clcEMA('mV', maVl, k, n)
CASE opgACVl = 3
maVl = clcSMA('mV * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
dVl = maVl * kSD
GO k
REPLACE ml WITH maVl - dVl mu WITH maVl + dVl
NEXT
nFldsVl = IIF(hwVl < 3, 3, 7)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'ml'
arrFlds[2] = 'mu'
arrFlds[3] = 'mV'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
arrGTps[3] = 'L 0.0 0.0 0.0 0.0'
IF hwVl = 3
arrFlds[4] = 'bsg'
arrGTps[4] = 'V 1.0 0.0 0.0 0.0'
arrFlds[5] = 'bsg2'
arrGTps[5] = 'S 1.0 0.0 0.0 0.0'
arrFlds[6] = 'ssg'
arrGTps[6] = 'V 0.0 0.0 1.0 0.0'
arrFlds[7] = 'ssg2'
arrGTps[7] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Envelopes(' + TRANSFORM(n) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .T., .F.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
CALCULATE MIN(mV) TO mnVl
IF hwVl = 3
mxVl = mVSllVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
dstVl = 0.1 * (mVSllVl - mnVl)
mssDStrtVl = oFrm.CheckMssDStrt.Value
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT prcNrBrdr('ml', dstVl, mssDStrtVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT prcNrBrdr('mu', dstVl, mssDStrtVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltNvlps
*
* Buy (sell) signal
FUNCTION prcNrBrdr(fld, dstVl, mssDStrtVl)
DO WHILE NOT EOF()
IF mssDStrtVl
DO WHILE DELETED()
SKIP
ENDDO
ENDIF
SKIP
IF ABS(&fld - mV) < dstVl
RETURN .T.
ENDIF
ENDDO
RETURN .F.
ENDFUNC && prcNrBrdr
Скользящее среднее (Moving Average, MA) используется как самостоятельный индикатор (рис. 18).
Рис. 18. SMA (график цены показан зеленым цветом)
Использование:
Сигналы на покупку поступают, когда цена актива превышает MA.
Сигналы на продажу подаются, когда цена находится ниже MA.
MA не находит минимум и максимум цены, чтобы подать сигнал о входе в рынок или выходе из него. С помощью МА можно начать покупать (продавать) при приближении к текущему ценовому минимума (максимуму).
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
Замечание. Приводимая ниже процедура clcltMA также вызывается при нажатии на кнопки SROC и PCU.
* Click-обработчик кнопки MA
clcltMA(thisForm, 1)
* Расчет и оценка индикатора MA
PROCEDURE clcltMA(oFrm, hwVl, srcVl, lVl, uVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
prdVl = oFrm.SpinnerPrd.Value
IF hwVl < 4
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, prdVl)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
IF hwVl = 3 && PCU
ALTER TABLE (ali) ADD lCh N(8, 2) ADD uCh N(8, 2)
ELSE
ALTER TABLE (ali) ADD ma N(8, 2)
IF hwVl = 2 && SROC
ALTER TABLE (ali) ADD sroc N(8, 4)
ENDIF
ENDIF
k2Vl = IIF(hwVl = 2, 2, 1)
LOCAL k24
FOR k24 = 1 TO k2Vl
n = prdVl - IIF(k24 = 2, srcVl, 0)
IF opgACVl = 2
maVl = 0.0
FOR k = 1 TO n - 1
maVl = maVl + mV
NEXT
maVl = maVl / (n - 1)
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
DO CASE
CASE opgACVl = 1
maVl = clcSMA('mV', kS, k)
CASE opgACVl = 2
maVl = clcEMA('mV', maVl, k, n)
CASE opgACVl = 3
maVl = clcSMA('mV * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
DO CASE
CASE hwVl = 3 && PCU
REPLACE lCh WITH maVl * (1 - lVl) uCh WITH maVl * (1 + uVl)
CASE k24 = 1
REPLACE ma WITH maVl
CASE k24 = 2 && SROC
REPLACE sroc WITH ma / maVl * 100
ENDCASE
NEXT
NEXT
DO CASE
CASE hwVl = 1 OR hwVl > 3 && MA
nFldsVl = IIF(hwVl = 5, 6, 2)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'ma'
arrFlds[2] = 'mV'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 0.0 0.0 0.0'
ttlVl = 'Moving_Average(' + TRANSFORM(prdVl) + ')'
IF hwVl = 5
arrFlds[3] = 'bsg'
arrGTps[3] = 'V 1.0 0.0 0.0 0.0'
arrFlds[4] = 'bsg2'
arrGTps[4] = 'S 1.0 0.0 0.0 0.0'
arrFlds[5] = 'ssg'
arrGTps[5] = 'V 0.0 0.0 1.0 0.0'
arrFlds[6] = 'ssg2'
arrGTps[6] = 'S 0.0 0.0 1.0 0.0'
ENDIF
CASE hwVl = 2 && SROC
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'sroc'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
ttlVl = 'Smoothed_Rate_Of_Change(' + TRANSFORM(prdVl) + '_' + TRANSFORM(srcVl)+ ')'
CASE hwVl = 3 && PCU
nFldsVl = 4
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'lCh'
arrFlds[2] = 'uCh'
arrFlds[3] = 'hgh'
arrFlds[4] = 'lw'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
arrGTps[3] = 'V 0.0 0.0 0.0 0.0'
arrGTps[4] = 'S 0.0 0.0 0.0 0.0'
ttlVl = 'Price_Channel_Upper(' + TRANSFORM(prdVl) + ')'
ENDCASE
IF hwVl < 4
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 5
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
dffrncVl = 0.0045
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllSgnlSFndMA('b', 1.0 + dffrncVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllSgnlSFndMA('s', 1.0 - dffrncVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltMA
*
* Retuns .T. if buy / sell signal is found
FUNCTION bSllSgnlSFndMA(bSllVl, dffrncVl)
DO WHILE NOT EOF()
SKIP
IF bSllVl = 'b'
IF ma > dffrncVl * mV
RETURN .T.
ENDIF
ELSE
IF ma < dffrncVl * mV
RETURN .T.
ENDIF
ENDIF
ENDDO
RETURN .F.
ENDFUNC && bSllSgnlSFnd
Индикатор Волатильность Чайкина (Chaikin's Volatility, ChV) оценивает расстояние между максимальной и минимальной ценами (рис. 19).
Рис. 19. ChV
Расчет:
SP = H – L
CV = (MAi(SP, n) – MAi–n(SP, n)) / MAi–n(SP, n) * 100
По умолчанию n = 10.
Использование:
Резкий рост индикатора может означать, что цена приближается к своему минимуму; продолжительное снижение индикатора сигнализирует о росте цены актива. Рекомендуется подтверждать сигналы индикатора такими индикаторами, как MA и Envelopes.
Программа:
* Click-обработчик кнопки ChV
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 10
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD chv N(8, 2)
n2 = 2 * n
mVVl = '(hgh - lw)'
IF opgACVl = 2
STORE 0 TO maVl, maVl2
FOR k = 1 TO n - 1
maVl = maVl + &mVVl
NEXT
maVl = maVl / (n - 1)
maVl2 = 0.0
FOR k = n TO n2 - 1
maVl2 = maVl2 + &mVVl
NEXT
maVl2 = maVl2 / (n - 1)
ENDIF
FOR k = n2 TO rCnt
kS = k - n2 + 1
kS2 = k - n + 1
DO CASE
CASE opgACVl = 1
maVl = clcSMA(mVVl, kS, kS + n - 1)
maVl2 = clcSMA(mVVl, kS2, kS2 + n - 1)
CASE opgACVl = 2
maVl = clcEMA(mVVl, maVl, k - n, n)
maVl2 = clcEMA(mVVl, maVl2, k, n)
CASE opgACVl = 3
maVl = clcSMA(mVVl + ' * vlm', kS, kS + n - 1) / clcSMA('vlm', kS, kS + n - 1)
maVl2 = clcSMA(mVVl + ' * vlm', kS2, kS2 + n - 1) / clcSMA('vlm', kS2, kS2 + n - 1)
ENDCASE
GO k
REPLACE chv WITH (maVl2 - maVl) / maVl * 100
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'chv'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Chaikin_Volatility(' + TRANSFORM(n) + ')',;
'H-L_EMA', nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Схождение/расхождение скользящих средних (Moving Average Convergence/Divergence, MACD) используется для оценки силы тренда, его направления и прогнозирования колебаний цен и точек разворота. Предложен Джеральдом Аппелем (Gerald Appel). Выводится в виде гистограммы и сигнальной линии (рис. 20).
Рис. 20. MACD
Расчет:
MACD = МА(P, Lng) – MA(P, Shrt), выведен на рис. 20 в виде гистограммы;
MACD_Signal = MA(MACD, n), выведен на рис. 20 в виде линии
По умолчанию Lng = 26, Shrt = 12, n = 9.
Использование:
Программа:
* Click-обработчик кнопки MACD
PARAMETERS hstgtVl
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
sVl = 12
lVl = 20
n = 9
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, lVl)
RETURN
ENDIF
ALTER TABLE (ali) ADD mcd N(8, 2) ADD sgnl N(8, 2)
IF opgACVl = 2
GO sVl
mcdSVl = mV
GO lVl
mcdLVl = mV
ENDIF
FOR k = lVl TO rCnt
rStrt1 = k - sVl + 1
rStrt2 = k - lVl + 1
DO CASE
CASE opgACVl = 1
mcdSVl = clcSMA('mV', rStrt1, k)
mcdLVl = clcSMA('mV', rStrt2, k)
CASE opgACVl = 2
mcdSVl = clcEMA('mV', mcdSVl, rStrt1, sVl)
mcdLVl = clcEMA('mV', mcdLVl, rStrt2, lVl)
CASE opgACVl = 3
mcdSVl = clcSMA('mV * vlm', rStrt1, k) / clcSMA('vlm', rStrt1, k)
mcdLVl = clcSMA('mV * vlm', rStrt2, k) / clcSMA('vlm', rStrt2, k)
ENDCASE
GO k
REPLACE mcd WITH mcdLVl - mcdSVl
NEXT
IF opgACVl = 2
GO lVl + n
sgnlVl = mcd
ENDIF
FOR k = lVl + n TO rCnt
rStrt1 = k - n + 1
DO CASE
CASE opgACVl = 1
sgnlVl = clcSMA('mcd', rStrt1, k)
CASE opgACVl = 2
sgnlVl = clcEMA('mcd', sgnlVl, rStrt1, n)
CASE opgACVl = 3
sgnlVl = clcSMA('mcd * vlm', rStrt1, k) / clcSMA('vlm', rStrt1, k)
ENDCASE
GO k
REPLACE sgnl WITH sgnlVl
NEXT
IF NOT hstgtVl
nFldsVl = 2
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'mcd'
arrFlds[2] = 'sgnl'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
arrGTps[2] = 'L 0.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'MACD(' + TRANSFORM(sVl) + '-' + TRANSFORM(lVl) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'mcd - sgnl'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'MACD_Histogam(' + TRANSFORM(sVl) + '-' + TRANSFORM(lVl) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ENDIF
Осциллятор ценовых моментов Чанде (Chande Momentum Oscillator, CMO) сигнализирует о перекупленности/перепроданности актива.
Рис. 19. CMO
Расчет:
CMO = (sum1 – sum2) / (sum1 + sum2) * 100,
где sum1 = sum(CMO1, n) – суммарное значение CMO1 за n интервалов.
sum2 = sum(CMO2, n) – суммарное значение CMO2 за n интервалов.
df = Pi – Pi–1.
Если df > 0, то CMO1 = df, CMO2 = 0. Если df < 0, то CMO2 = –df, CMO1 = 0.
В качестве P преимущественно берется цена закрытия.
Использование:
Эти уровни соответствуют уровням 70/30 индикатора RSI.
Программа:
* Click-обработчик кнопки CMO
LOCAL pDtVl, IDSVl, opgACVl,chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD cmo1 N(8, 2) ADD cmo2 N(8, 2) ADD cmo N(8, 2)
FOR k = 2 TO rCnt
GO k - 1
mVVl = mV
GO k
dfVl = mV - mVVl
STORE 0 TO cmoVl1, cmoVl2
DO CASE
CASE dfVl > 0
cmoVl1 = dfVl
CASE dfVl < 0
cmoVl2 = -dfVl
ENDCASE
REPLACE cmo1 WITH cmoVl1 cmo2 WITH cmoVl2
NEXT
FOR k = n TO rCnt
kS = k - n + 1
sCmoVl1 = clcSMA('cmo1', kS, k) * n
sCmoVl2 = clcSMA('cmo2', kS, k) * n
cmoVl = (sCmoVl1 - sCmoVl2) / (sCmoVl1 + sCmoVl2) * 100
GO k
REPLACE cmo WITH cmoVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'cmo'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Chande_Momentum_Oscillator(' + TRANSFORM(n) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индекс силы Элдера (Elder's Force Index, EFI). Предложен А. Элдером. Измеряет силу быков после поддержки и силу медведей после понижения (рис. 22).
Рис. 22. EFI
Расчет:
Сила движения рынка зависит от его направления, размаха и объема. Если текущий бар закрывается выше предыдущего, это свидетельствует о том, что сила положительна, если наоборот ниже, то сила отрицательна. Чем больше цены различаются, тем существеннее сила. Чем больше объем сделок, тем больше сила.
FI = (1 – Pi–1 / Pi) * Vi
EFIi = MA(FI, n)
По умолчанию n = 14
Использование:
EFI можно применять как в сочетании со скользящей средней, так и отдельно. При короткой скользящей средней можно выявить наиболее оптимальные моменты для открытия и закрытия позиций, а при длинной индикатор может определить грядущую смену тренда.
Подает следующие сигналы:
Программа:
* Click-обработчик кнопки EFI
LOCAL pDtVl, IDSVl, opgACVl,chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD fi N(15, 4) ADD efi N(15, 4)
FOR k = 2 TO rCnt
GO k - 1
mVVl = mV
GO k
REPLACE fi WITH (1.0 - mVVl / mV) * vlm
NEXT
FOR k = n TO rCnt
efiVl = clcSMA('fi', k - n + 1, k)
GO k
REPLACE efi WITH efiVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'efi'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Elder_Force_Index(' + TRANSFORM(n) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индекс относительной силы (Relative Strength Index, RSI, рис. 23), предложенный У. Вайлдером (Welles Wilder), – это следующий за ценами осциллятор, который колеблется от 0 до 100.
Рис. 23. RSI
Расчет:
RSI = 100 / (1 + D(P, n) / U(P, n)), где
U(P, n) – скользящее среднее роста цены;
D(P, n) – скользящее среднее падения цены.
По умолчанию n = 14; популярны значения 9, 10 и 25 (меньшие значения берутся при торговле на краткосрочных ценовых движениях).
Использование:
Распространенным методом анализа RSI является поиск расхождения (дивергенции) между ценами и значением индикатора. Подобное расхождение свидетельствует о вероятности разворота цен. Сигналы RSI используются совместно с сигналами разворота тренда, подаваемыми иными индикаторами.
RSI может предоставить ранний сигнал покупки/продажи.
RSI сигнализирует о перепроданности/перекупленности рынка. На графике RSI задаются два контрольных уровня (по умолчанию 30 и 70, нередко употребляются 20 и 80). Подъем RSI выше 70 означает перенасыщенность рынка покупками и вхождение в область продаж. Снижение RSI ниже 30 говорит о перенасыщенности рынка продажами и вхождение в область покупок. Действительные сигналы на покупку/продажу даются при развороте RSI. Пересечения RSI уровня 50 также можно использовать как сигналы покупки/продажи.
Сигналы RSI:
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки RSI
clcltRSI(thisForm, 1)
* Расчет и оценка индикатора RSI
PROCEDURE clcltRSI(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = oFrm.SpinnerPrd.Value
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD rsi N(7, 2)
FOR k = n + 1 TO rCnt
kS = k - n + 1
uVl = clcUDMA('mV', kS, k, .T.)
dVl = clcUDMA('mV', kS, k, .F.)
GO k
REPLACE rsi WITH 100.0 / (1.0 + IIF(uVl = 0, 0, dVl / uVl))
NEXT
nFldsVl = IIF(hwVl < 3, 1, 5)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
IF hwVl < 3
arrFlds[1] = 'rsi'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
ELSE
arrFlds[1] = 'mV'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'bsg'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'bsg2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
arrFlds[4] = 'ssg'
arrGTps[4] = 'V 0.0 0.0 1.0 0.0'
arrFlds[5] = 'ssg2'
arrGTps[5] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Relative_Strength_Index(' + TRANSFORM(n) + ')'
prcKndVl = LEFT(prcKndVl, RAT('_', prcKndVl)) + 'UDMA'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
brdrVl = 30
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllSgnlSFndRS('rsi', brdrVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllSgnlSFndRS('-rsi', -100 + brdrVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltRSI
*
* Retuns .T. if buy / sell signal is found
FUNCTION bSllSgnlSFndRS(fld, brdrVl)
LOCAL fldVl, fldVl2, fldVl3, fldVl4, sKVl, sKVl2
fldVl = &fld
SKIP
DO WHILE NOT EOF() AND &fld >= fldVl && Move up
fldVl = &fld
SKIP
ENDDO
DO WHILE NOT EOF() AND &fld <= fldVl && Move down
fldVl = &fld
SKIP
ENDDO
sKVl = NOT EOF() AND fldVl < brdrVl
fldVl2 = IIF(sKVl, fldVl, '')
DO WHILE NOT EOF() AND &fld >= fldVl && Move up
fldVl = &fld
SKIP
ENDDO
fldVl3 = IIF(EOF(), '', fldVl)
DO WHILE NOT EOF() AND &fld <= fldVl && Move down
fldVl = &fld
SKIP
ENDDO
fldVl4 = IIF(EOF(), '', fldVl)
DO WHILE NOT EOF() AND &fld >= fldVl && Move up
fldVl = &fld
IF fldVl > fldVl3
RETURN IIF(EMPTY(fldVl2), .F., fldVl4 >= fldVl2 AND fldVl4 < brdrVl)
ENDIF
SKIP
ENDDO
RETURN .F.
ENDFUNC && bSllSgnlSFndRS
Индикатор Ишимоку Кинко Хайо (Ichimoku Kinko Hyo, IKH) предназначен для определения рыночного тренда, уровней поддержки и сопротивления и для генерации сигналов покупки и продажи. Лучше всего индикатор работает на недельных и дневных графиках. Состоит из линий Tenkan-sen (TS, разворотная линия, красная), Kijun-sen (KS, основная линия, зеленая) и Chinkou Span (CS, запаздывающая линия, синяя) и линий Senkou Span A (SSA, желтая) и Senkou Span B (SSB, фиолетовая), между которыми штрихуется область, называемая облаком (рис. 24).
Рис. 24. IKH (график цены показан черным цветом)
Расчет:
По умолчанию n = 9, m = 26 и z = 52 (число недель в году).
На дневном графике 9 – это 1.5 рабочих недели, 26 – число рабочих дней в месяце (в Японии на момент создания IKH).
На недельном графике: 9 недель – это примерно 2 месяца, 26 недель составляют полугодие.
Использование:
Замечание. В качестве цены берется значение Close.
Линии IKH оперативно реагируют на появление новых экстремумов (не запаздывают, как скользящие).
Во флэте сложно эффективно использовать индикатор.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки IKH
clcltIKH(thisForm, 1)
* Расчет и оценка индикатора IKH
PROCEDURE clcltIKH(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = 9
m = 26
z = 52
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, z + m)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD ts N(8, 2) ADD ks N(8, 2) ADD cs N(8, 2) ADD ssa N(8, 2) ADD ssb N(8, 2)
FOR k = z + m TO rCnt
tsVl = clcPrcMddl(k, n)
ksVl = clcPrcMddl(k, m)
GO MIN(rCnt, k + m)
csVL = cls
ssaVL = 0.5 * (clcPrcMddl(k - m, n) + clcPrcMddl(k - m, m))
ssbVL = clcPrcMddl(k - m, z)
GO k
REPLACE ts WITH tsVl ks WITH ksVl cs WITH csVl ssa WITH ssaVl ssb WITH ssbVl
NEXT
nFldsVl = 8
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'ts'
arrFlds[2] = 'ks'
arrFlds[3] = 'cs'
arrFlds[4] = 'ssa'
arrFlds[5] = 'ssb'
arrFlds[6] = 'ssa'
arrFlds[7] = 'ssb'
arrFlds[8] = 'mV'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
arrGTps[3] = 'L 0.0 0.0 1.0 0.0'
arrGTps[4] = 'L 0.5 0.5 0.0 0.0'
arrGTps[5] = 'L 0.0 1.0 1.0 0.0'
arrGTps[6] = 'V 0.5 0.5 0.5 0.0'
arrGTps[7] = 'S 0.0 0.0 0.0 0.0'
arrGTps[8] = 'L 0.0 0.0 0.0 0.0'
ttlVl = 'Ichimoku_Kinko_Hyo(' + TRANSFORM(n) + '_' + TRANSFORM(m) + '_' + TRANSFORM(z) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
ELSE
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
*
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
CALCULATE MAX(mV) TO mVSllVl
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
IF kVl < 3
bWhnCrssBT('ts', 'ks', kVl, @smVl2, smVl, fpVl, @mntBsVl, @mntSllsVl, @stcsMntVl, @smLftVl2, @fVl, @mVSllVl, pDtVl)
ELSE
bWhnCrssBT('mV', 'ssb', kVl, @smVl2, smVl, fpVl, @mntBsVl, @mntSllsVl, @stcsMntVl, @smLftVl2, @fVl, @mVSllVl, pDtVl)
ENDIF
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
ENDIF
ENDPROC && clcltIKH
Индекс облегчения рынка Билла Уильямса (Bill Williams Market Facilitation Index, BW MFI) показывает изменение цены на каждом интервале указанного временного диапазона (рис. 25).
Рис. 25. BW MFI
Расчет:
BW MFI = (H – L) / V
Использование:
BW MFI употребляется совместно с графиком объема продаж:
Программа:
* Click-обработчик кнопки BW MFI
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD bmwfi N(8, 2)
CALCULATE AVG(vlm) TO vgVlmVl IN (ali)
REPLACE bmwfi WITH (hgh - lw) / (vlm / vgVlmVl) ALL IN (ali)
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'bmwfi'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Bill_Williams_Market_Facilitation_Index', '', nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Индикатор темпа Момент цены (Momentum) измеряет колебание цены актива (рис. 26).
Рис. 26. Momentum
Расчет:
Mmi = Pi / Pi – n * 100
По умолчанию n = 5
Использование:
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки Momentum
clcltMmntm(thisForm, 1)
* Расчет и оценка индикатора Momentum
PROCEDURE clcltMmntm(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = oFrm.SpinnerPrd.Value
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD mmntm N(8, 2)
FOR k = n + 1 TO rCnt
GO k - n
mVVl = mv
GO k
REPLACE mmntm WITH 100.0 * mV / mVVl
NEXT
nFldsVl = IIF(hwVl < 3, 1, 5)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
IF hwVl < 3
arrFlds[1] = 'mmntm'
arrGTps[1] = 'L 1.0 0.0 0.0 1.0'
ELSE
arrFlds[1] = 'mV'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'bsg'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'bsg2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
arrFlds[4] = 'ssg'
arrGTps[4] = 'V 0.0 0.0 1.0 0.0'
arrFlds[5] = 'ssg2'
arrGTps[5] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Momentum(' + TRANSFORM(n) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
mxVl = mVSllVl
CALCULATE MIN(mV) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllSgnlSFndMmntm('mmntm')
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllSgnlSFndMmntm('-mmntm')
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltMmntm
*
* Retuns .T. if buy / sell signal is found
FUNCTION bSllSgnlSFndMmntm(fld)
fldVl = &fld
SKIP
DO WHILE NOT EOF() AND &fld >= fldVl && Move up
fldVl = &fld
SKIP
ENDDO
DO WHILE NOT EOF() AND &fld <= fldVl && Move down
fldVl = &fld
SKIP
ENDDO
RETURN .T.
ENDFUNC && bSllSgnlSFndMmntm
Индекс денежных потоков (Money Flow Index, MnFI) показывает интенсивность, с которой деньги вкладываются в актив или выводятся из него. Разработан Ласло Бириньи мл. (Laszlo Birinyi, Jr.), как вариант индикатора OBV. Построение и интерпретация индикатора аналогична RSI, с той разницей, что в MnFI учитывается и объем: торги с большим объемом дают больший вклад в MnFI, чем торги с меньшим объемом (рис. 27).
Рис. 27. MnFI
Расчет:
MnFIj = 100 – 100 / (1 + mRj)
Отношение денежных потоков (money ratio):
mRj = sum(pMFi) / sum(nMFi), i = j – n + 1, j
Положительный денежный поток (positive money flow):
pMFi = Ti * Vi, если Ti > Ti – 1
Отрицательный денежный поток (negative money flow):
nMFi = Ti * Vi, если Ti < Ti – 1
По умолчанию n = 14.
Денежный поток возвращает функция clcMF
Использование:
MnFI полезен при выборе актива, поскольку информирует о его сильных и слабых сторонах.
Цена обычно следует за MnFI: как правило, он показывает, что на восходящем тренде финансовые потоки направлены в рынок и меняют направление при падении цены.
При наличии подтверждения от иных индикаторов MnFI может быть употреблен для выбора точки входа.
Сигналы MnFI:
Программа:
* Click-обработчик кнопки MnFI
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD mnfi N(8, 2)
FOR k = n + 1 TO rCnt
pMFVl = clcMF(k, n, .T.)
nMFVl = clcMF(k, n, .F.)
GO k
REPLACE mnfi WITH 100.0 - IIF(nMFVl = 0.0, 0, 100.0 / (1.0 + pMFVl / nMFVl))
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'mnfi'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Money_Flow_Index(' + TRANSFORM(n) + ')', '', nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Индикатор Балансовый объем (On Balance Volume, OBV) предложен Джо Гранвиллем (Joe Granville). Показывает направление движения денежных средств: на рынок или в обратном направлении (рис. 28).
Рис. 28. OBV
Расчет:
OBVi = OBVi – 1 + Vi, если Pi > Pi – 1
OBVi = OBVi – 1 – Vi, если Pi < Pi – 1
Использование:
Интерпретация OBV основана на предположении, что изменения OBV опережают ценовые. Тогда повышение OBV свидетельствует о том, что в актив вкладывают средства крупные игроки (осведомленных трейдеров или «умные деньги» можно увидеть, когда OBV начинает рост). Цена и OBV продолжат рост, когда вслед интерес к активу проявит и широкая публика.
Если цена опережает в своем движении OBV, то возникает так называемое "отсутствие подтверждения". Это может наблюдаться на вершине бычьего рынка, когда цена растет без соответствующего роста OBV или опережая рост OBV, или в основании медвежьего рынка, когда цена падает без соответствующего уменьшения OBV или снижается быстрее OBV.
О восходящей тенденции OBV можно говорить, если каждый новый пик выше предыдущего и каждая новая впадина выше предыдущей. По аналогии, нисходящая тенденция OBV предполагает последовательное понижение пиков и впадин. Установившаяся тенденция остается в силе до перелома OBV.
Перелом тенденции OBV может произойти двумя способами. В первом случае тенденция изменяется с восходящей на нисходящую, или с нисходящей на восходящую. Во втором случае тенденция OBV переходит в неопределенную и остается таковой на протяжении более трех интервалов.
Когда тенденция OBV меняется на восходящую или нисходящую, происходит так называемый "прорыв". Поскольку прорывы индикатора обычно предшествуют ценовым прорывам, инвесторам следует занимать длинные позиции при прорывах OBV вверх и, соответственно, продавать в случае прорыва OBV вниз. Открытые позиции нужно сохранять до тех пор, пока направление тенденции не изменится.
OBV может быть использован и для подтверждения текущего ценового движения, и для предупреждения о возможном развороте тренда. Если наблюдается дивергенция OBV и цены, то возможен разворот тренда.
Важны не действительные значения OBV, а его тренд.
Изменение OBV часто предшествует изменениям цены.
Пробитие OBV обычно влечет пробитие ценового тренда. Пробитие индикатора вверх является сигналом к покупке.
OBV подходит для торговли в краткосрочном цикле. Гранвиль советует, чтобы инвесторы действовали быстро и решительно, если они хотят получить прибыль от краткосрочного анализа OBV.
Сигналы OBV:
Имеются и иные учитывающие объем торгов индикаторы, например MnFI.
Программа:
* Click-обработчик кнопки OBV
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD obv N(20, 2)
GO TOP
mVVl = mV
obvVl = mVVl
REPLACE obV WITH obvVl
FOR k = 2 TO rCnt
GO k
DO CASE
CASE mV > mVVl
obvVl = obvVl + mV
CASE mV < mVVl
obvVl = obvVl - mV
ENDCASE
REPLACE obv WITH obvVl
mVVl = mV
NEXT
REPLACE obv WITH 0.1 * obv ALL
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'obv'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
prcKndVl = LEFT(prcKndVl, RAT('_', prcKndVl) - 1)
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'On_Balance_Volume',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Параболическая система (Parabolic SAR, Parabolic Stop and Reverse, PSAR) – это система определения точек разворота позиций. Предложен У. Вайлдером (Welles Wilder) для анализа трендовых рынков в дополнение к другим следующим за рынком индикаторам (рис. 29).
Рис. 29. PSAR
Расчет:
Нисходящий тренд: SARi = (Hi – 1 – SARi – 1) * AF + SARi – 1
Восходящий тренд: SARi = (Li – 1 – SARi – 1) * AF + SARi – 1
По умолчанию коэффициент ускорения AF = 0.02.
Использование:
Индикатор аналогичен скользящей средней, однако PSAR движется с большим ускорением и может менять положение относительно цены. Если цена пересекает PSAR, то происходит переворот индикатора: последующие его значения располагаются по другую сторону от цены. При восходящем тренде индикатор располагается ниже цен, в случае нисходящего тренда – выше. Переворот индикатора – это сигнал либо об окончании тренда, либо об его развороте. PSAR следует пользоваться при наличии тренда. При его отсутствии PSAR дает ложные сигналы.
PSAR является полезным инструментом для определения свежих трендовых движений на ранних стадиях, подавая сигналы покупки/продажи.
Когда PSAR ниже цены, следует покупать или становиться в длинную позицию. Когда PSAR выше цены, то следует продавать или открывать короткую позицию. Сигналы нужно подтверждать сигналами иных индикаторов. Так, Джон Мэрфи (John Murphy), автор Технического анализа финансовых рынков (Technical Analysis of the Financial Markets), рекомендует использовать с PSAR индекс DMI. В частности, когда +DI находится выше –DI, все PSAR-сигналы на продажу можно игнорировать.
Программа:
* Click-обработчик кнопки PSAR
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
afVl = 0.02
ALTER TABLE (ali) ADD psar N(8, 2)
GO TOP
psarVl = (1.0 + afVl) * hgh
sShrtVl = .F.
FOR k = 1 TO rCnt
GO k
REPLACE psar WITH psarVl
DO CASE
CASE NOT sShrtVl AND hgh > psarVl
psarVl = (1.0 - afVl) * lw
sShrtVl = .T.
CASE sShrtVl AND lw < psarVl
psarVl = (1.0 + afVl) * hgh
sShrtVl = .F.
CASE sShrtVl
psarVl = (lw - psarVl) * afVl + psarVl
OTHERWISE
psarVl = (hgh - psarVl) * afVl + psarVl
ENDCASE
NEXT
nFldsVl = 3
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'psar'
arrFlds[2] = 'hgh'
arrFlds[3] = 'lw'
arrGTps[1] = 'P 1.0 0.0 0.0 0.0'
arrGTps[2] = 'V 0.0 0.0 0.0 0.0'
arrGTps[3] = 'S 0.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Parabolic_SAR', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Parabolic_SAR', '', 'P', nFldsVl, @arrFlds, .F., .T.)
Стохастический осциллятор (Stochastic Oscillator, SO) показывает, когда цена подходит близко к границе торгового диапазона, взятого за определенный период времени. Предложен Джорджем Лейном (Dr. George Lane). Состоит из двух кривых: быстрой, более чувствительной к изменению цены %К и медленной %D (рис. 30).
Рис. 30. SO (кривая %D показана пунктиром)
Расчет:
%K0 = 100 * (С – Ln) / (Hn – Ln)
%K = MA(%K0, m)
%D = MA(%K, m2), где
Ln и Hn – соответственно минимальная и максимальная цена за последние n интервалов.
По умолчанию n = 5 (обычно n берут из диапазона 5 – 21), а m = m2 = 3.
Значения Ln и Hn возвращают соответственно функции clcMinP и clcMaxP
Использование:
Сигналы SO:
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки SO
clcltSO(thisForm, 1)
* Расчет и оценка индикатора SO
PROCEDURE clcltSO(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
m = 3
m2 = 3
n = oFrm.SpinnerPrd.Value && 5 by default
mn = MAX(m, m2, n)
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, mn)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD pk N(8, 2) ADD pk2 N(8, 2) ADD pd N(8, 2)
FOR k = n + 1 TO rCnt
lVl = clcMinP(k, n)
hlVl = clcMaxP(k, n) - lVl
pkVl = IIF(hlVl = 0.0, 100, 100 * (cls - lVl) / hlVl)
GO k
REPLACE pk WITH pkVl
NEXT
IF opgACVl = 2
pk2Vl = 0.0
FOR k = 1 TO m - 1
pk2Vl = pk2Vl + pk
NEXT
pk2Vl = pk2Vl / (m - 1)
ENDIF
FOR k = m TO rCnt
kS = k - m + 1
DO CASE
CASE opgACVl = 1
pk2Vl = clcSMA('pk', kS, k)
CASE opgACVl = 2
pk2Vl = clcEMA('pk', pk2Vl, k, n)
CASE opgACVl = 3
pk2Vl = clcSMA('pk * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE pk2 WITH pk2Vl
NEXT
IF opgACVl = 2
pdVl = 0.0
FOR k = 1 TO m2 - 1
pdVl = pdVl + pk2
NEXT
pdVl = pdVl / (m2 - 1)
ENDIF
FOR k = m2 TO rCnt
kS = k - m2 + 1
DO CASE
CASE opgACVl = 1
pdVl = clcSMA('pk2', kS, k)
CASE opgACVl = 2
pdVl = clcEMA('pk2', pdVl, k, n)
CASE opgACVl = 3
pdVl = clcSMA('pk2 * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE pd WITH pdVl
NEXT
nFldsVl = IIF(hwVl < 3, 2, 5)
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
IF hwVl < 3
arrFlds[1] = 'pk2'
arrFlds[2] = 'pd'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'D 0.0 0.0 1.0 0.0'
ELSE
*!* arrFlds[1] = 'mV'
arrFlds[1] = 'pk2'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'bsg'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'bsg2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
arrFlds[4] = 'ssg'
arrGTps[4] = 'V 0.0 0.0 1.0 0.0'
arrFlds[5] = 'ssg2'
arrGTps[5] = 'S 0.0 0.0 1.0 0.0'
ENDIF
ttlVl = 'Stochastic_Oscillator(' + TRANSFORM(n) + '_' + + TRANSFORM(m) + '_' + TRANSFORM(m2) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
CALCULATE MAX(mV) TO mVSllVl
IF hwVl = 3
*!* mxVl = mVSllVl
*!* CALCULATE MIN(mV) TO mnVl
CALCULATE MAX(pk2) TO mxVl
CALCULATE MIN(pk2) TO mnVl
ALTER TABLE (ali) ADD bsg N(8, 2) ADD bsg2 N(8, 2) ADD ssg N(8, 2) ADD ssg2 N(8, 2)
REPLACE bsg WITH mnVl bsg2 WITH mnVl ssg WITH mnVl ssg2 WITH mnVl ALL
ELSE
mxVl = ''
ENDIF
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
brdrVl = 20
LOCATE FOR dy = DAY(pDtVl)
DO WHILE NOT EOF()
DO WHILE NOT EOF() AND NOT bSllSgnlSFndSO('pk2', 'pd', brdrVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
ENDIF
DO WHILE NOT EOF() AND NOT bSllSgnlSFndSO('-pk2', '-pd', -100 + brdrVl)
ENDDO
IF NOT EOF()
IF kVl = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDDO
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
ENDIF
ENDPROC && clcltSO
*
* Retuns .T. if buy / sell signal is found
FUNCTION bSllSgnlSFndSO(fld, fld2, brdrVl)
LOCAL fldVl, fldVl2, sKVl
fldVl = &fld
fldVl2 = &fld2
SKIP
DO WHILE NOT EOF() AND (&fld >= fldVl OR &fld2 >= fldVl2) && Move up
fldVl = &fld
fldVl2 = &fld2
SKIP
ENDDO
sKVl = .F.
DO WHILE NOT EOF() AND (&fld <= fldVl OR &fld2 <= fldVl2) && Move down
fldVl = &fld
fldVl2 = &fld2
skVl = skVl OR fldVl < brdrVl AND fldVl2 < brdrVl
SKIP
ENDDO
sKVl = NOT EOF() AND skVl
DO WHILE NOT EOF() AND (&fld >= fldVl OR &fld2 >= fldVl2) AND &fld < brdrVl AND &fld2 < brdrVl && Move up
fldVl = &fld
fldVl2 = &fld2
SKIP
ENDDO
RETURN NOT EOF() AND sKVl
ENDFUNC && bSllSgnlSFndSO
Процентный Диапазон Вильямса (Williams Percent Range, %R) фиксирует перекупленность/перепроданность актива. Предложен Лари Вильямсом (Larry Williams). %R схож с SO; различия в том, что первый имеет перевернутую шкалу (рис. 31), а второй строится с использованием внутреннего сглаживания.
Рис. 31. %R
Расчет:
%R = –100 * (Hn – C) / (Hn – Ln)
По умолчанию n = 5.
Значения Ln и Hn возвращают соответственно функции clcMinP и clcMaxP
Использование:
По опыту Вильямса %R является лучшие часовым инструментом для определения перекупленности/перепроданности:
По общему для всех индикаторов перекупленности/перепроданности правилу действовать по их сигналам следует, дождавшись поворота цен в соответствующем направлении. Так, если индикатор перекупленности/перепроданности указывает на состояние перекупленности, то прежде, чем продавать актив, разумно дождаться поворота цены вниз.
%R способен предвосхищать ценовые развороты. Он почти всегда образует пик и поворачивает вниз за определенный промежуток времени до того, как цена достигает пика и поворачивает вниз. Точно так же %R обычно образует впадину и заблаговременно поворачивает вверх. %R доказал свою эффективность при определении разворотов рынка.
Выделение доминирующего тренда при работе с %R обязательно. Для этого Вильямс советует использовать 10-недельные скользящие средние.
Как и другие индикаторы темпа, %R не эффективен при боковом тренде.
Сигналы %R:
Программа:
* Click-обработчик кнопки %R
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 5
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD wpr N(8, 2)
FOR k = n + 1 TO rCnt
hVl = clcMaxP(k, n)
hlVl = hVl - clcMinP(k, n)
wprVl = -IIF(hlVl = 0.0, 100, 100 * (hVl - cls) / hlVl)
GO k
REPLACE wpr WITH wprVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'wpr'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Williams_Percent_Range(' + TRANSFORM(n) + ')', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индикатор Сила медведей (Bears Power, BrsP), введенный А. Элдером, указывает на возможное изменение направления тренда (рис. 32).
Рис. 32. BrsP
Расчет:
BrsP = L – EMA(P, n); по умолчанию n = 13
Использование:
BrsP используется вместе с трендовыми индикаторами, например c MA. Сигнал покупки возникает, когда трендовый индикатор направлен вверх, BrsP растет, хотя и находится ниже нуля. При этом желательно, чтобы на графике трендового индикатора наблюдалось расхождение.
Программа:
* Click-обработчик кнопки BrsP
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 13
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD brsp N(8, 2)
maVl = 0.0
FOR k = 1 TO n - 1
maVl = maVl + lw
NEXT
maVl = maVl / (n - 1)
FOR k = n TO rCnt
maVl = clcEMA('lw', maVl, k, n)
GO k
REPLACE brsp WITH lw - maVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'brsp'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Bears_Power_L_EMA(' + TRANSFORM(n) + ')', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индикатор Сила быков (Bulls Power, BllsP), введенный А. Элдером, указывает на возможное изменение направления тренда (рис. 33).
Рис. 33. BllsP
Расчет:
BllsP = H – EMA(P, n); по умолчанию n = 13
Использование:
BllsP используется вместе с трендовыми индикаторами, например c MA. Сигнал продажи возникает, когда трендовый индикатор имеет нисходящее направление, а BllsP расположен выше нуля, хотя убывает. При этом желательно, чтобы на графике трендового индикатора наблюдалось расхождение.
Программа:
* Click-обработчик кнопки BllsP
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 13
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD bllsp N(8, 2)
maVl = 0.0
FOR k = 1 TO n - 1
maVl = maVl + hgh
NEXT
maVl = maVl / (n - 1)
FOR k = n TO rCnt
maVl = clcEMA('hgh', maVl, k, n)
GO k
REPLACE bllsp WITH hgh - maVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'bllsp'
arrGTps[1] = 'C 1.0 0.0 0.0 1.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Bulls_Power_H_EMA(' + TRANSFORM(n) + ')', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индикатор Демарка (DeMarker, рис. 34) использует разницу ценовых максимумов и минимумов текущего и предыдущего баров.
Рис. 34. Индикатор DeMarker
Расчет:
Расчет длительных интервалов позволяет уловить долгосрочную тенденцию на рынке, а расчет коротких обеспечивает попадание сделки в русло основной тенденции.
DMrkr = MA(DeMax, n) / (MA(DeMax, n) + MA(DeMin, n)), где
Если Hi > Hi – 1, то DeMaxi = Hi – Hi – 1, иначе DeMaxi = 0
Если Li < Li – 1, то DeMini = Li – 1 – Li, иначе DeMini = 0
По умолчанию n = 7.
Использование:
При значении индикатора ниже 0.3 вероятно движение цены вверх, а выше 0.7 – вниз.
Программа:
* Click-обработчик кнопки DeMarker
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 7
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD dx N(8, 2) ADD dn N(8, 2) ADD dmrkr N(8, 4)
FOR k = 2 TO rCnt
GO k - 1
hVl = hgh
lVl = lw
GO k
REPLACE dx WITH IIF(hgh > hVl, hgh - hVl, 0) dn WITH IIF(lw < lVl, lVl - lw, 0)
NEXT
IF opgACVl = 2
STORE 0.0 TO dxVl, dnVl
FOR k = 1 TO n - 1
dxVl = dxVl + dx
dnVl = dnVl + dn
NEXT
dxVl = dxVl / (n - 1)
dnVl = dnVl / (n - 1)
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
DO CASE
CASE opgACVl = 1
dxVl = clcSMA('dx', kS, k)
dnVl = clcSMA('dn', kS, k)
CASE opgACVl = 2
dxVl = clcEMA('dx', dxVl, k, n)
dnVl = clcEMA('dn', dnVl, k, n)
CASE opgACVl = 3
dxVl = clcSMA('dx * vlm', kS, k) / clcSMA('vlm', kS, k)
dnVl = clcSMA('dn * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE dmrkr WITH dxVl / (dxVl + dnVl)
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'dmrkr'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'DeMarker(' + TRANSFORM(n) + ')', prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Индикатор Скользящая средняя осциллятора (Moving Average Of Oscillator, OsMA) – это разность между осциллятором и его сглаживанием. Частным случаем OsMA является MACD-гистограмма (рис. 35), в которой осциллятор – это основная линия MACD, а его сглаживание – сигнальная линия.
Рис. 35. OsMA (MACD-histogram)
Расчет:
OSMA = MACD – MACD_Signal
Использование:
Рост гистограммы говорит об увеличении силы быков. Это сигнал для сделок на повышение.
Падение гистограммы означает усиление медведей. Это сигнал для сделок на понижение.
Дивергенция означает ослабление тренда и возможную сильную коррекцию или разворот. Чем больше длина кадра графика цены, тем сильнее сигнал.
Программа:
* Click-обработчик кнопки MACD
thisForm.CmdMACD.Click(.T.)
Индикатор Средний истинный диапазон (Average True Range, ATR, рис. 36), введенный У. Вайлдером (Welles Wilder), характеризует волатильность актива.
Рис. 36. ATR
Расчет:
TRi = max(Hi – Li, |Hi – C i - 1 |, |Li – Ci - 1|)
ATR = MA(TR, n)
По умолчанию n = 14.
Использование:
ATR используется и самостоятельно, и в составе иных индикаторов, например в ADX.
Нередко ATR достигает высоких значений в основаниях рынка после стремительного падения цен, вызванного паническими продажами. Продолжительные горизонтальные движения на вершинах рынка и во время консолидации дают низкие значения индикатора. Повышение ATR сигнализирует о смене тренда, понижение – о сохранении тренда.
Программа:
* Click-обработчик кнопки ATR
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD tr N(8, 2) ADD atr N(8, 2)
GO 1
clsVl = cls
hghVl = hgh
lwVl = lw
REPLACE tr WITH hgh - lw
FOR k = 2 TO rCnt
GO k
REPLACE tr WITH MAX(hgh - lw, ABS(hgh - clsVl), ABS(lw - clsVl))
clsVl = cls
hghVl = hgh
lwVl = lw
NEXT
IF opgACVl = 2
atrVl = 0.0
FOR k = 1 TO n
GO k
atrVl = atrVl + tr
NEXT
atrVl = atrVl / n
ENDIF
FOR k = n + 1 TO rCnt
DO CASE
CASE opgACVl = 1
atrVl = clcSMA('tr', k - n, k)
CASE opgACVl = 2
atrVl = clcEMA('tr', atrVl, k, n)
CASE opgACVl = 3
atrVl = clcSMA('tr * vlm', k - n, k) / clcSMA('vlm', k - n, k)
ENDCASE
REPLACE atr WITH atrVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'atr'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Average_True_Range(' + TRANSFORM(n) + ')', prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Индикатор Фракталы (Fractals, рис. 37), предложенный Б. Вильямсом (B. Williams), подает сигналы покупки/продажи.
Рис. 37. Фракталы
Фракталы на покупку показаны красной точкой, а на продажу – синей.
Расчет:
Фрактал на покупку – это серия из пяти последовательных баров, в которой перед самым высоким максимумом и за ним находятся по два бара с более низкими максимумами.
Фрактал на продажу – это серия из пяти последовательных баров, в которой перед самым низким минимумом и за ним находятся по два бара с более высокими минимумами.
Фракталы на покупку и на продажу могут иметь общие бары.
Вариант использования:
Фракталы используются совместно с Аллигатором. Они подают следующие сигналы:
Текущий фрактал может быть преодолен либо в результате "поражения" (появления антагонистического фрактала), либо в результате появления нового фрактала в том же направлении. В этих случаях предыдущий сигнал отменяется, а отложенный ордер снимается.
Войти в рынок можно после преодоления первого фрактала на покупку (отсчет ведется от начала текущей торговой сессии), приняв и оценив сигналы других индикаторов Б. Вильямса (Alligator, АО и AC).
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки Fractals
clcltLlgtr(thisForm, .T., .F., 1)
Гатор осциллятор (Gator Oscillator, рис. 38) показывает схождение/расхождения линий баланса Аллигатора.
Рис. 38. Gator
Расчет:
Gator отображается в виде двух гистограмм:
Использование:
Gator упрощает визуальное определение наличия или отсутствия тренда. С помощью Gator хорошо видны интервалы сближения и переплетения (Аллигатор спит) и интервалы расхождения (Аллигатор бодрствует) Линий Баланса.
Программа:
* Click-обработчик кнопки Gator
clcltLlgtr(thisForm, .F., .T., 1)
Индекс относительной бодрости (Relative Vigor Index, RVI) исходит из того, что на бычьем рынке цена закрытия, как правило, выше цены открытия, а на медвежьем рынке наблюдается обратная картина. RVI выводится в виде базовой (красной) и сигнальной (зеленой) линий (рис. 39)
Рис. 39. RVI
Расчет:
Ai = (Ci – Oi + 2 * (Ci – 1 – Oi – 1) + 2 * (Ci – 2 – Oi – 2) + Ci – 3 – Oi – 3) / 6
B = (Hi – Li + 2 * (Hi – 1 – Li – 1) + 2 * (Hi – 2 – Li – 2) + Hi – 3 – Li – 3) / 6
NM = sum(A, n)
DNM = sum(B, n)
RVI = NM / DNM
RVIS = (RVI + 2 * RVIi – 1 + 2 * RVIi – 2 + RVIi – 3) / 6
По умолчанию n = 10.
Использование:
Пересечение линий RVI –это сигнал на покупку или продажу.
Программа:
* Click-обработчик кнопки RVI
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 10
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD a N(8, 2) ADD b N(8, 2) ADD rvi N(8, 4) ADD rvis N(8, 4)
DIMENSION arrAVl[4], arrBVl[4]
FOR k = 1 TO 4
GO k
arrAVl[k] = cls - pn
arrBVl[k] = hgh - lw
NEXT
FOR k = 5 TO rCnt
aVl = (arrAVl[4] + 2.0 * arrAVl[3] + 2.0 * arrAVl[2] + arrAVl[1]) / 6.0
bVl = (arrBVl[4] + 2.0 * arrBVl[3] + 2.0 * arrBVl[2] + arrBVl[1]) / 6.0
GO k - 1
REPLACE a WITH aVl b WITH bVl
FOR k2 = 1 TO 3
arrAVl[k2] = arrAVl[k2 + 1]
arrBVl[k2] = arrBVl[k2 + 1]
NEXT
GO k
arrAVl[4] = cls - pn
arrBVl[4] = hgh - lw
NEXT
GO rCnt
REPLACE a WITH aVl b WITH bVl
FOR k = n + 4 TO rCnt
kS = k - n + 1
nmVl = clcSMA('a', kS, k)
dnmVl = clcSMA('b', kS, k)
GO k
REPLACE rvi WITH nmVl / dnmVl
NEXT
DIMENSION arrRSVl[4]
k2 = 0
FOR k = n + 4 TO n + 7
GO k
k2 = k2 + 1
arrRSVl[k2] = rvi
NEXT
FOR k = n + 8 TO rCnt
rsVl = (arrRSVl[4] + 2.0 * arrRSVl[3] + 2.0 * arrRSVl[2] + arrRSVl[1]) / 6.0
GO k - 1
REPLACE rvis WITH rsVl
FOR k2 = 1 TO 3
arrRSVl[k2] = arrRSVl[k2 + 1]
NEXT
GO k
arrRSVl[4] = rvi
NEXT
GO rCnt
REPLACE rvis WITH rsVl
nFldsVl = 2
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'rvi'
arrFlds[2] = 'rvis'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Relative_Vigor_Index(' + TRANSFORM(n) + ')', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Накопление/Распределение Вильямса (Williams Accumulation/Distribution, WA/D) иллюстрирует рис. 40.
Рис. 40. WA/D
Расчет:
CumWADi = CumWadi – 1 + WADi, где
WADi = Pi – TL, если Pi > Pi – 1;
WADi = Pi – TH, если Pi < Pi – 1;
WADi = 0, если Pi = Pi – 1;
TH = max(Pi – 1, Hi) – истинный диапазон максимумов;
TL = min(Pi – 1, Li) – истинный диапазон минимумов.
Использование:
Показывает распределение актива, если цена формирует новые максимумы, а индикатор нового максимума сформировать не может.
Показывает накопление актива, если цена достигает новых минимумов, а индикатор достигнуть нового минимума не может.
Программа:
* Click-обработчик кнопки WA/D
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD cumwad N(8, 2)
GO TOP
pVl = cls
cumwadVl = 0
FOR k = 2 TO rCnt
GO k
cumwadVl = cumwadVl + IIF(cls > pVl, cls - MIN(pVl, lw), IIF(cls < pVl, cls - MAX(pVl, hgh), 0))
REPLACE cumwad WITH cumwadVl
pVl = cls
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'cumwad'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Williams_Accumulation_Distribution', 'Close', nFldsVl, @arrFlds, @arrGTps, .T., .T.)
Пример графика индикатора Скорость изменения цены (Price Rate Of Change, ROC) показан на рис. 41.
Рис. 41. ROC
Расчет:
ROCi = (Pi – Pi – n) / Pi – n * 100
По умолчанию n = 5.
Использование:
Аналогичен индикатору Momentum.
Программа:
* Click-обработчик кнопки ROC
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 5
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n + 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD roc N(8, 2)
FOR k = n + 1 TO rCnt
GO k - n
mVVl = mv
GO k
REPLACE roc WITH 100.0 * (mV - mVVl) / mVVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'roc'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
prcKndVl = LEFT(prcKndVl, RAT('_',prcKndVl) - 1)
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Price_Rate_Of_Change(' + TRANSFORM(n) + ')', prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
График индикатора Сглаженная скорость изменения (Smoothed Rate Of Change, SROC) показан на рис. 42.
Рис. 42. SROC
Расчет:
SROC = MA(P, n) / MA(P, n – k) * 100
По умолчанию P – это C, n = 10, а величина сглаживающего коэффициента k = 5.
Использование:
SROC вырабатывает меньше сигналов, чем ROC, но их достоверность выше.
Программа:
* Click-обработчик кнопки SROC
clcltMA(thisForm, 2, 5)
График индикатора Стандартное отклонение (Standard Deviation, SD) приведен на рис. 43.
Рис. 43. SD (график SMA показан красным цветом)
Расчет:
SDj = SQRT(sum(Pi – MAi(P, n))^2) / n), где i = j – n + 1, j.
По умолчанию n = 10.
Использование:
При больших значениях SD рынок сильно волатилен (цены разбросаны относительно скользящего среднего).
При маленьких значениях индикатора рынок более стабилен (цены близки к скользящему среднему).
Интерпретация SD:
SD используется при расчете иных индикаторов, например BB.
Программа:
* Click-обработчик кнопки SD
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 10
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD ma N(8, 2) ADD sd N(8, 2)
IF opgACVl = 2
GO n
maVl = mV
ENDIF
FOR k = n TO rCnt
kS = k - n + 1
* See someProcs.prg
DO CASE
CASE opgACVl = 1
maVl = clcSMA('mV', kS, k)
CASE opgACVl = 2
maVl = clcEMA('mV', maVl, k, n)
CASE opgACVl = 3
maVl = clcSMA('mV * vlm', kS, k) / clcSMA('vlm', kS, k)
ENDCASE
GO k
REPLACE ma WITH maVl
NEXT
n2 = 2 * n
FOR k = n2 TO rCnt
kS = k - n + 1
* See someProcs.prg
sdVl = clcSD('mV', 'ma', kS, k)
GO k
REPLACE sd WITH sdVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'sd'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Standard_Deviation(' + TRANSFORM(n) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
График индикатора Тройная экспоненциально-сглаженная скользящая средняя (Triple Exponential Moving Average, TRIX) показан на рис. 44.
Рис. 44. TRIX
Расчет:
LnP = ln(P)
mLnP = EMA(LnP, n)
mLnP2 = EMA(mLnP, n)
mLnP3 = EMA(mLnP2, n)
TRIXi = (1 – mLnP3i / mLnP3i – 1) * 100
По умолчанию P – это C и n = 7.
Использование:
TRIX работает как фильтр, который отсеивает движения цены актива, незначительные по отношению к большему тренду. Значения TRIX колеблются около нулевой линии.
Программа:
* Click-обработчик кнопки TRIX
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 7
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 3 * n + 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD lnp N(8, 2) ADD mlnp N(8, 2) ADD mlnp2 N(8, 2) ADD mlnp3 N(8, 2) ADD trix N(8, 4)
REPLACE lnp WITH LOG(mV) ALL
GO n
mlnpVl = lnp
FOR k = n TO rCnt
mlnpVl = clcEMA('lnp', mlnpVl, k, n)
GO k
REPLACE mlnp WITH mlnpVl
NEXT
n2 = 2 * n
GO n2
mlnpVl2 = mlnp
FOR k = n2 TO rCnt
mlnpVl2 = clcEMA('mlnp', mlnpVl2, k, n)
GO k
REPLACE mlnp2 WITH mlnpVl2
NEXT
n3 = 3 * n
GO n3
mlnpVl3 = mlnp2
FOR k = n3 TO rCnt
mlnpVl3 = clcEMA('mlnp2', mlnpVl3, k, n)
GO k
REPLACE mlnp3 WITH mlnpVl3
NEXT
FOR k = n3 + 1 TO rCnt
GO k - 1
mlnpVl3 = mlnp3
GO k
REPLACE trix WITH (1.0 - mlnp3 / mlnpVl3) * 100.0
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'trix'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Triple_Exponential_Moving_Average(' + TRANSFORM(n) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
График индикатора Вертикально-горизонтальный фильтр (Vertical Horizontal Filter, VHF) приведен на рис. 45.
Рис. 45. VHF
Расчет:
VHFi = Ai / Bi
Ai = Hj – Lj)
Bi = sum(abs(Pj – Pj – 1)), где
j = i – n + 1, i;
Hj и Lj – максимальная и минимальная цены взаданном временном промежутке из n интервалов, возвращаемые соответственно функциями clcMinP и clcMaxP.
По умолчанию P – это C и n = 28.
Сумма ценовых изменений возвращается функцией clcSPCH.
Использование:
VHF показывает, находятся ли цены в фазе тренда или в фазе застоя.
Программа:
* Click-обработчик кнопки VHF
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
n = 28
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
RETURN
ENDIF
ALTER TABLE (ali) ADD vhf N(8, 4)
GO TOP
FOR k = n TO rCnt
aVl = clcMaxP(k, n) - clcMinP(k, n)
bVl = clcSPCH('mV', k, n)
GO k
REPLACE vhf WITH aVl / bVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'vhf'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
prcKndVl = LEFT(prcKndVl, RAT('_',prcKndVl) - 1)
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Vertical_Horizontal_Filter(' + TRANSFORM(n) + ')', prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .F.)
Осциллятор объема (Volume Oscillator, VO) – это разность двух МА объема продаж, выраженная в процентах (рис. 46).
Рис. 46. VO
Расчет:
VO = (MA(V, Shrt) – MA(V, Lng)) / MA(V, Lng) * 100
По умолчанию MA – это EMA, Shrt = 5 и Lng = 10.
Использование:
VO может использоваться с целью определения направления движения основной тенденции объема (повышение или снижение). Так, повышение VO выше нуля может означать, что краткосрочный объемный тренд преобладает над долгосрочным объемным трендом.
Программа:
* Click-обработчик кнопки VO
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
sVl = 5
lVl = 10
n = 9
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, lVl)
RETURN
ENDIF
ALTER TABLE (ali) ADD vo N(8, 4)
IF opgACVl = 2
GO sVl
maSVl = vlm
GO lVl
maLVl = vlm
ENDIF
FOR k = lVl TO rCnt
rStrt1 = k - sVl + 1
rStrt2 = k - lVl + 1
DO CASE
CASE opgACVl = 1 OR opgACVl = 3
maSVl = clcSMA('vlm', rStrt1, k)
maLVl = clcSMA('vlm', rStrt2, k)
CASE opgACVl = 2
maSVl = clcEMA('vlm', maSVl, rStrt1, sVl)
maLVl = clcEMA('vlm', maLVl, rStrt2, lVl)
ENDCASE
GO k
REPLACE vo WITH (maSVl - maLVl) / maLVl * 100
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'vo'
arrGTps[1] = 'L 1.0 0.0 0.0 1.0'
prcKndVl = LEFT(prcKndVl, RAT('_', prcKndVl, 2) - 1);
+ 'Volume' + SUBSTR(prcKndVl, RAT('_', prcKndVl))
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl,;
'Volume_Oscillator(' + TRANSFORM(sVl) + '-' + TRANSFORM(lVl) + ')',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индикатор Канал цен (Price Channel Upper, PCU, рис. 47) – это сдвинутая вверх и вниз скользящая средняя.
Рис. 47. PCU (график цены показан черным цветом)
Расчет:
U = MA(P, n) * (1 + u / 100);
L = MA(P, n) * (1 – d / 100), где
U – верхняя полоса канала цен;
L – нижняя полоса канала цен;
u – величина сдвига вверх;
d – величина сдвига вниз.
По умолчанию u = d = 10.
Использование:
При удачном выборе параметров канал будет соответствовать равновесному состоянию рынка, а все выходы цены за его пределы должны сопровождаться возвращением ее назад. Параметры u и d подбираются так, что около 95% цен располагаются внутри канала.
Программа:
* Click-обработчик кнопки PCU
clcltMA(thisForm, 3, 0, 0.02, 0.015)
Индикатор направленного изменения (Directional Movement, +/–DM, рис. 48), введенный У. Вайлдером (Welles Wilder), использует фильтрацию по темпам и направлению изменения цены.
Рис. 48. +/–DM
На рис. 48 +DI выведен красным цветом, а –DI – зеленым.
Расчет:
Порядок расчета приведен при описании индикатора ADX.
Использование:
Предназначен для выявления трендовых участков рынка. Индикатор показывает долговременную тенденцию рынка и силу тренда.
Сигналы индикатора (см. также ADX):
Программа:
* Click-обработчик кнопки +/-DM
clcltADX(thisForm, 2, 14)
Индикатор аккумуляции объема (Volume Accumulation, VA, рис. 49) предложен M. Чайкиным (M. Chaikin) и Д. Ламбертом (D. Lambert).
Рис. 49. VA
Расчет:
VAi = VAi – 1 + ((Ci – Li) – (Hi – Ci)) / (Hi – Li) * Vi
Использование:
Индикатор VA схож с OBV.
Сигналы VA:
Программа:
* Click-обработчик кнопки VA
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD va N(20, 2)
GO TOP
REPLACE va WITH IIF(hgh - lw = 0, 0, (2 * cls - lw - hgh) / (hgh - lw))
vaVl = va
FOR k = 2 TO rCnt
GO k
vaVl = vaVl + IIF(hgh - lw = 0, 0, (2 * cls - lw - hgh) / (hgh - lw))
REPLACE va WITH vaVl
NEXT
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'va'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Volume_Accumulation', '', nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Объемный тренд цены (Volume Price Trend, VPT, рис. 50), учитывает не только направление изменения цены, но и сопутствующий объем.
Рис. 50. VPT
Расчет:
VPTi = VPTi – 1 + Vi * (Pi – Pi – 1) / Pi – 1
Использование:
Большое положительное значение свдетельствует о перекупленности актива, большое отрицательное значение – о перепроданнности актива.
Программа:
* Click-обработчик кнопки VPT
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 1)
RETURN
ENDIF
ALTER TABLE (ali) ADD vpt N(20, 2)
GO TOP
mVVl = mV
vptVl = 0
REPLACE vpt WITH vptVl
FOR k = 2 TO rCnt
GO k
vptVl = vptVl + vlm * (mV - mVVl) / mVVl
REPLACE vpt WITH vptVl
mVVl = mV
NEXT
REPLACE vpt WITH 0.01 * vpt ALL
nFldsVl = 1
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'vpt'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
prcKndVl = LEFT(prcKndVl, RAT('_', prcKndVl) - 1)
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, 'Volume_Price_Trend',;
prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Осциллятор (Oscillator, OSC, рис. 51.) выявляет движения цен с заданным периодом.
Рис. 51. OSC
Иное название индикатора – Price Oscillator.
Расчет:
OSC = MA(P, Lng) – MA(P, Shrt), где
Lng – протяженность длинного временного промежутка, по умолчанию равна 34;
Shrt – протяженность короткого временного промежутка, по умолчанию равна 5.
По умолчанию P – это M.
Использование (см. также AO)
Большие положительные значения индикатора OSC означают завышенные цены по отношению к долгосрочной тенденции и дают сигнал к покупке. И наоборот, большие отрицательные значения индикатора дают сигнал к продаже.
Классический сигнал: бычье расхождение (медвежье схождение). При этом на явном подтвержденном бычьем тренде пересечение OSC снизу-вверх нулевой линии дает сигнал покупки (более ранним сигналом является разворот находящегося ниже нуля индикатора в направлении динамики тренда). И наоборот для медвежьего рынка.
Сигналы против тренда – разворот и выход индикатора из зоны перекупленности/перепроданности.
В итоге:
Программа:
* Click-обработчик кнопки OSC
clcltAO(thisForm, 2, 5, 34)
Временные зоны Фибоначчи (Fibonacci Time Zones, FTZ, рис. 52) – это зоны, между вертикальными линиями, проведенными в точках временной оси, отвечающим числам Фибоначчи: 0, 1, 1, 2, 3, 5, 8, … (каждое число последовательности равно сумме двух предыдущих чисел).
Рис. 52. FTZ
Расчет:
Первая линия FTZ проходит через точку минимума (максимума) графика, а следующие линии проводятся через точки временной оси, расстояние между которыми растет в соответствии с числами Фибоначчи.
Порядок построения FTZ следующий:
Использование:
FTZ предполагает значительные изменения цены либо на самих линиях, либо около них.
FTZ более надежны при долгосрочном анализе ценовых колебаний и менее точны на краткосрочных графиках.
Программа:
* Click-обработчик кнопки FTZ
LOCAL pDtVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt
IF NOT prpsT(thisForm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, 3)
RETURN
ENDIF
LOCAL ali2, tbl2
ali2 = 'stcksTL'
tbl2 = _tmpPth + ali2
dVl = DAY(pDtVl)
SELECT mV, tm, dy;
FROM (ali);
WHERE dy = dVl;
INTO TABLE (tbl2)
ALTER TABLE (ali2) ADD tmx I ADD tpnts C(2) ADD ftz N(8, 2) ADD ftz2 N(8, 2)
REPLACE tmx WITH VAL(CHRTRAN(tm, ':', '')) ALL
* Try to understand a kind of trend (D, U or S)
* Try D trend first
STORE 0 TO dtVlD, mvMVlD, dtVlD2, mvMVlD2, dtVlU, mvMVlU, dtVlU2, mvMVlU2
rCntVl = RECCOUNT()
tLD = trnd('d', @dtVlD, @mvMVlD, @dtVlD2, @mvMVlD2, rCntVl)
LOCATE FOR tpnts = 't'
rFTZDVl = IIF(FOUND(), RECNO(), 0)
LOCATE FOR tpnts = 'm'
rFTZDVl2 = IIF(FOUND(), RECNO(), 0)
* Try U trend next
REPLACE tpnts WITH '' ALL
tLU = trnd('u', @dtVlU, @mvMVlU, @dtVlU2, @mvMVlU2, rCntVl)
LOCATE FOR tpnts = 't'
rFTZUVl = IIF(FOUND(), RECNO(), 0)
LOCATE FOR tpnts = 'm'
rFTZUVl2 = IIF(FOUND(), RECNO(), 0)
IF tLU > tLD
* tk = 'U'
rFTZVl = rFTZUVl
dFTZVl = rFTZUVl2 - rFTZUVl
ELSE
* tk = 'D'
rFTZVl = rFTZDVl
dFTZVl = rFTZDVl2 - rFTZDVl
ENDIF
IF dFTZVl = 0
MESSAGEBOX("No Fibonacci Time Zones found")
RETURN
ENDIF
CALCULATE MAX(mV) TO mxVl
CALCULATE MIN(mV) TO mnVl
REPLACE ftz WITH mnVl ftz2 WITH mnVl ALL
fbVl = 0
rFTZVlCrrnt = rFTZVl
fbVlPrv = 0
fbVlCrrnt = 1
DO WHILE rFTZVlCrrnt <= rCntVl
GO rFTZVlCrrnt
REPLACE ftz WITH mxVl
rFTZVlCrrnt = rFTZVl + fbVlCrrnt * dFTZVl
fbVlTmp = fbVlPrv + fbVlCrrnt
fbVlPrv = fbVlCrrnt
fbVlCrrnt = fbVlTmp
ENDDO
ALTER TABLE (ali2) DROP tmx
nFldsVl = 3
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'mV'
arrGTps[1] = 'L 0.0 0.0 0.0 0.0'
arrFlds[2] = 'ftz'
arrGTps[2] = 'V 1.0 0.0 0.0 0.0'
arrFlds[3] = 'ftz2'
arrGTps[3] = 'S 1.0 0.0 0.0 0.0'
pVl = RAT('_', prcKndVl) - 1
svMVDtFls(chckNldVl, ali2, IDSVl, pDtVl, 'Fibonacci_Time_Zones',;
LEFT(prcKndVl, pVl), nFldsVl, @arrFlds, @arrGTps, .F., .T.)
Индикатор Mesa-синусоиды (Mesa Sine Wave, MESASWI, рис. 53), введенный Дж. Элхерсом (John Elhers), строится на основе двух синусоид Sine (красная линия) и Lead Sine (зеленая линия) для определения, находится ли рынок в циклической стадии или в стадии тренда.
Рис. 53. MESASWI
Расчет:
RealParti = Σnj = 0sin(2π* j / (n + 1)) * Ci – n + j
ImagParti = Σnj = 0cos(2π * j / (n + 1)) * Ci – n + j
if ImagParti < 0 then
DCPhasei = 3π / 2
else
if ImagParti > 0.001 then
DCPhasei = atan(RealParti / ImagParti) + π / 2
else
DCPhasei = π / 2
if DCPhasei > 3π / 2 then
DCPhasei = DCPhasei – 2π
Sinei = sin(DCPhasei)
LeadSinei = sin(DCPhasei + π / 4)
Sinei = SMA(Sinei, n)
LeadSinei = SMA(LeadSinei, n)
По умолчанию n = 9
Использование:
При четком направленном движении обе линии Sine и Lead Sine движутся параллельно и показывают своим положением друг относительно друга направление тренда; при боковом же тренде линия Sine быстро реагирует на развороты рынка.
Открывайте длинную/закрывайте короткую позицию, когда Lead Sine ниже, чем Sine.
Открывайте короткую/закрывайте длинную позицию, когда Lead Sine выше, чем Sine.
Состояние цикла.
Состояние тренда.
Анализ ситуации ведется по иным индикаторам, использующим, в частности, скользящие средние.
Эффективность:
Следование сигналам индикатора привело на тестовой выборке к сокращению портфеля.
Программа:
* Click-обработчик кнопки MESASWI
clcltMESASWI(thisForm, 1)
* Расчет и оценка индикатора MESASWI
PROCEDURE clcltMESASWI(oFrm, hwVl, thsVl)
LOCAL pDtVl, IDSVl, opgACVl, slctVl, prcKndVl, ali, rCnt
n = 14
IF hwVl = 1
LOCAL chckNldVl
prpsVl = prpsT(oFrm, @pDtVl, @IDSVl, @opgACVl, @chckNldVl, @slctVl, @prcKndVl, @ali, @rCnt, n)
ELSE
LOCAL dsMntVl, smVl, kVl, fpVl
prpsVl = prpsT2(oFrm, thsVl, @pDtVl, @dsMntVl, @IDSVl, @opgACVl, @slctVl, @prcKndVl, @ali, @rCnt, @smVl, @fpVl, @kVl, 2)
ENDIF
IF NOT prpsVl
RETURN
ENDIF
ALTER TABLE (ali) ADD sn N(8, 4) ADD lsn N(8, 4) ADD msn N(8, 4) ADD mlsn N(8, 4)
STORE 0.0 TO rpVl, mpVl
piVl = PI()
p2Vl = 0.5 * piVl
p3Vl = 3.0 * p2Vl
p4Vl = 0.25 * piVl
FOR k = n + 1 TO rCnt
clcRPMP('cls', k, n, @rpVl, @mpVl)
DO CASE
CASE mpVl < 0.0
dcVl = p3Vl
CASE mpVl > 0.001
dcVl = ATAN(rpVl / mpVl) + p2Vl
OTHERWISE
dcVl = p2Vl
ENDCASE
dcVl = IIF(dcVl > p3Vl, dcVl - 2.0 * piVl, dcVl)
GO k
REPLACE sn WITH SIN(dcVl) lsn WITH SIN(dcVl + p4Vl)
NEXT
FOR k = n TO rCnt
kS = k - n + 1
msnVl = clcSMA('sn', kS, k)
mlsnVl = clcSMA('lsn', kS, k)
GO k
REPLACE msn WITH msnVl mlsn WITH mlsnVl
NEXT
nFldsVl = 2
DIMENSION arrFlds[nFldsVl], arrGTps[nFldsVl]
arrFlds[1] = 'msn'
arrFlds[2] = 'mlsn'
arrGTps[1] = 'L 1.0 0.0 0.0 0.0'
arrGTps[2] = 'L 0.0 1.0 0.0 0.0'
ttlVl = 'Mesa_Sine_Wave(' + TRANSFORM(n) + ')'
IF hwVl = 1
svMVDtFls(chckNldVl, ali, IDSVl, pDtVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps, .F., .T.)
ELSE
svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, nFldsVl, @arrFlds, @arrGTps)
*
smVl2_2 = clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
CALCULATE MAX(mV) TO mVSllVl
smVl2 = smVl
STORE 0 TO stcsMntVl, mntBsVl, mntSllsVl, fVl, smLftVl2
bWhnCrssBT('mlsn', 'msn', kVl, @smVl2, smVl, fpVl, @mntBsVl, @mntSllsVl, @stcsMntVl, @smLftVl2, @fVl, @mVSllVl, pDtVl)
frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
ENDIF
ENDPROC && clcltMESASWI
Имитируется работа автоматического трейдера на базе одного или нескольких индикаторов. (Этот трейдер заключает сделки в автоматическом режиме.) Автомат продает и покупает выбранный актив в заданном временном интервале, работая по следующей схеме:
Оценка выполняется на недельном интервале: торги начинаются в понедельник и завершаются в пятницу.
Приведенная схема поддерживается показанной на рис. 54 формой.
Рис. 54. Форма оценки автоматического трейдера
В качестве результата в форме выводятся рентабельность автомата, число покупок и продаж, а также возможная выгода (выводится в поле Рентабельность 2), вычисляемая исходя из предположения, что в день проводится одна сделка – покупка по минимальной цене дня и продажа по максимальной цене дня.
График цены одного из употребляемых в режиме оценки активов показан на рис. 55 (по оси X отложены номера точек, расстояние между точками равно 5 мин.).
Рис. 55. ОАО Газпром: график цены в тестовом интервале
Приводимые ниже процедуры prpsT2, svMVDtFls2, nldMv2, clcXptdPrft, bWhnCrssBT, oneBuy, oneSll и frmPdt используются при оценке эффективности индикаторов ТА.
*
* Подготовка к оценке эффективности индикатора ТА (режим одной недели)
FUNCTION prpsT2(oForm, thsVl, pDtVl, dsMntVl, IDSVl, opgACVl, chckNldVl, slctVl, prcKndVl, ali, rCnt, smVl, fpVl, kVl, kXVl)
WITH oForm
kVl = .SpinnerSNmbr.Value
IF kVl > kXVl
STORE 0 TO .TxtMntBs.Value, .TxtMntSlls.Value, .TxtPrft.Value
MESSAGEBOX('kVl must be < ' + TRANSFORM(kXVl + 1))
RETURN .F.
ENDIF
pDtVl = .PDt.Value
dsMntVl = .TxtDsMnt.Value
IDSVl = .IDSlct
opgACVl = .OpgAC.Value
opgACVl2 = .OpgAC2.Value
.LabelNdctr.Caption = thsVl.Caption
STORE 0 TO .TxtPrft.Value, .TxtFPL.Value, .TxtMntBs.Value, .TxtMntSlls.Value
smVl = .TxtSm.Value
fpVl = 0.01 * .TxtFP.Value
ENDWITH
DO CASE
CASE opgACVl2 = 2
slctVl = 'hgh'
prcKndVl = 'High_'
CASE opgACVl2 = 3
slctVl = 'lw'
prcKndVl = 'Low_'
CASE opgACVl2 = 4
slctVl = 'cls'
prcKndVl = 'Close_'
CASE opgACVl2 = 5 OR opgACVl2 < 2
slctVl = '0.5 * (hgh + lw)'
prcKndVl = 'Median_'
CASE opgACVl2 = 6
slctVl = '(hgh + lw + cls) / 3.0'
prcKndVl = 'Typical_'
ENDCASE
DIMENSION rrMV[3]
rrMV[1] = 'S'
rrMV[2] = 'E'
rrMV[3] = 'V'
prcKndVl = prcKndVl + rrMV[opgACVl] + 'MA'
pDtVl0 = pDtVl - 3
pDtVl2 = pDtVl + dsMntVl - 1
ali0 = 'stcksTrdngF'
ali = 'crStcksTrdng'
tbl = _tmpPth + ali
SELECT &slctVl AS mV, pn, cls, hgh, lw, vlm, DAY(dt) AS dy,;
TRANSFORM(HOUR(dt)) + ":" + IIF(MINUTE(dt) > 5, TRANSFORM(MINUTE(dt)),;
'0' + TRANSFORM(MINUTE(dt))) AS tm;
FROM (ali0);
WHERE IDS = IDSVl;
AND TTOD(dt) BETWEEN pDtVl0 AND pDtVl2;
ORDER BY dt;
INTO TABLE (tbl)
rCnt = _TALLY
IF rCnt = 0
MESSAGEBOX("No records selected")
RETURN .F.
ENDIF
RETURN .T.
ENDFUNC && prpsT2
*
* Выгрузка индикатора ТА в mVDt-файлы (режим оценки)
PROCEDURE svMVDtFls2(ali, IDSVl, pDtVl, dsMntVl, ttlVl, prcKndVl, n, arrFlds, arrGTps)
LOCAL k, kFFlsWrdVl, mvBsVl, mVDtVl, flNmVl
* Kind of files
FOR k = 1 TO n
mVDtVl = 'mVDt' + TRANSFORM(k)
flNmVl = _prjPth + mVDtVl + '.txt'
IF k = 1
kFFlsWrdVl = mVDtVl + _NEXTLINE + arrGTps[k]
nldMv2(ali, IDSVl, pDtVl, dsMntVl, 'ttl2.txt', ttlVl, prcKndVl, arrFlds[k], flNmVl)
else
kFFlsWrdVl = kFFlsWrdVl + _NEXTLINE + mVDtVl + _NEXTLINE + arrGTps[k]
nldMv2(ali, IDSVl, pDtVl, dsMntVl, '', '', '', arrFlds[k], flNmVl)
ENDIF
NEXT
* Create file kFFls2.txt with types of unloaded files
STRTOFILE(kfFlsWrdVl, _prjPth + 'kFFls2.txt')
MESSAGEBOX('mvDt-file' + IIF(n = 1, ' is', 's are') + ' created')
ENDPROC && svMVDtFls2
*
* Выгружает в файл fn график цены или индикатора ТА (поле mV) из таблицы ali
PROCEDURE nldMv2(ali, IDSVl, pDtVl, dsMntVl, ttlFnVl, ttlVl, prcKndVl, mV, fn)
LOCAL f, dVl, pDtVl_, k
dVl = DAY(pDtVl)
IF NOT EMPTY(ttlFnVl)
SEEK IDSVl IN stcks ORDER IDN
SEEK stcks.IDC IN cmpns ORDER IDN
SEEK stcks.IDK IN stcksKnds ORDER IDN
pDtVl_ = CHRTRAN(TRANSFORM(pDtVl + 1), '.', '')
stckVl = TRIM(cmpns.NmShrt) + '_' + TRIM(stcksKnds.NmShrt2)
SELECT (ali)
LOCATE FOR dy = dVl
k = RECNO()
* Title-file
ttlWrd = stckVl + '_' + pDtVl_+ '_' + TRANSFORM(dsMntVl) + '_' + ttlVl + '_' + prcKndVl +;
_NEXTLINE + '0' + _NEXTLINE + '1' + _NEXTLINE + TRANSFORM(RECCOUNT() - k + 1)
STRTOFILE(ttlWrd, _prjPth + ttlFnVl)
ENDIF
f = FCREATE(fn)
k = 0
SCAN FOR dy >= dVl
k = k + 1
FPUTS(f, TRANSFORM(k) + ' ' + TRANSFORM(&mV))
ENDSCAN
FCLOSE(f)
ENDPROC && nldMv2
*
* Расчет ожидаемого дохода
FUNCTION clcXptdPrft(smVl, dsMntVl, pDtVl, fpVl)
LOCAL smVl2, stcsMntVl, fVl, smLftVl2, m, dVl, rcVl, mXVl
smVl2 = smVl
STORE 0 TO stcsMntVl, fVl, smLftVl2
FOR m = 0 TO dsMntVl - 1
dVl = DAY(pDtVl + m)
CALCULATE CNT() FOR dy = dVl TO dRcrdsMntVl
LOCATE FOR dy = dVl
FOR k = 1 TO 0.15 * dRcrdsMntVl
DELETE && To miss day start
SKIP
NEXT
CALCULATE MIN(mV) TO mNVl FOR dy = dVl
LOCATE FOR mV = mNVl AND dy = dVl
rcVl = RECNO()
CALCULATE MAX(mV) TO mXVl FOR dy = dVl AND RECNO() > rcVl
IF mXVl > 0
oneBuy(smVl2, smVl, fpVl, mNVl, 0, @stcsMntVl, @smLftVl2, @fVl)
oneSll(@smVl2, fpVl, mXVl, 0, stcsMntVl, smLftVl2, @fVl)
ENDIF
NEXT
RETURN smVl2 - smVl - fVl
ENDFUNC && clcXptdPrft
*
* Покупай, когда fld пересекает fld2 снизу вверх. Подавай, когда fld пересекает fld2 сверху вниз
PROCEDURE bWhnCrssBT(fld, fld2, kVl, smVl2, smVl, fpVl, mntBsVl, mntSllsVl, stcsMntVl, smLftVl2, fVl, mVSllVl, pDtVl, mxVl)
LOCATE FOR dy = DAY(pDtVl)
DO WHILE &fld >= &fld2 AND NOT EOF()
SKIP
ENDDO
DO WHILE NOT EOF()
DO WHILE &fld <= &fld2 AND NOT EOF()
SKIP
ENDDO
IF NOT EOF()
IF MOD(kVl, 2) = 1
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ELSE
IF stcsMntVl = 0 AND mV < mVSllVl
oneBuy(smVl2, smVl, fpVl, mV, @mntBsVl, @stcsMntVl, @smLftVl2, @fVl, mxVl)
ENDIF
ENDIF
DO WHILE &fld >= &fld2 AND NOT EOF()
SKIP
ENDDO
IF NOT EOF()
IF MOD(kVl, 2) = 1
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
ELSE
smTmpVl = mV * stcsMntVl + smLftVl2
IF smTmpVl > smVl2
oneSll(@smVl2, fpVl, mV, @mntSllsVl, @stcsMntVl, smLftVl2, @fVl, mxVl)
mVSllVl = mV
ENDIF
ENDIF
ENDIF
ENDIF
ENDDO
ENDPROC && bWhnCrssBT
*
* Расчет одной покупки
PROCEDURE oneBuy(smVl2, smVl, fpVl, mVVl, mntBsVl, stcsMntVl, smLftVl2, fVl, mxVl)
LOCAL smVl3, smVl4
mntBsVl = mntBsVl + 1
smVl3 = MIN(smVl2, smVl)
stcsMntVl = INT(smVl3 / mVVl)
smVl4 = mVVl * stcsMntVl
smLftVl2 = smVl2 - smVl4
fVl = fVl + fpVl * smVl4
IF NOT EMPTY(mxVl)
REPLACE bsg WITH mxVl
ENDIF
ENDPROC && oneBuy
*
* Расчет одной продажи
PROCEDURE oneSll(smVl2, fpVl, mVVl, mntSllsVl, stcsMntVl, smLftVl2, fVl, mxVl)
LOCAL smVl4
smVl4 = mVVl * stcsMntVl
smVl2 = smVl4 + smLftVl2
stcsMntVl = 0
mntSllsVl = mntSllsVl + 1
fVl = fVl + fpVl * smVl4
IF NOT EMPTY(mxVl)
REPLACE ssg WITH mxVl
ENDIF
ENDPROC && oneSll
*
* Вывод результата в форму
PROCEDURE frmPdt(oFrm, stcsMntVl, smVl2, smLftVl2, mntBsVl, mntSllsVl, smVl, fVl, smVl2_2)
IF stcsMntVl > 0
GO BOTTOM
smVl2 = mV * stcsMntVl + smLftVl2
ENDIF
WITH oFrm
.TxtMntBs.Value = mntBsVl
.TxtMntSlls.Value = mntSllsVl
.TxtPrft.Value = smVl2 - smVl - fVl
.TxtPrft2.Value = smVl2_2
.TxtFPL.Value = fVl
ENDWITH
ENDPROC && frmPdt
Результаты оценки ниже описанных стратегий сведены в приводимую ниже таблицу (стартовый размер портфеля равен 5000 руб., приводятся оценки базового и модифицированного вариантов, заголовок последнего предваряется звездочкой).
Актив | Индикатор | Сделки / Выгода, руб. | *Сделки / Выгода, руб. | Расчетная выгода, руб. |
---|---|---|---|---|
Газпром (ао) | AC | 18 / –342 | 2 / –280 | 260 |
ADX | 27 / –360 | 1 / –448 | ||
AO | 11 / –292 | 2 / –345 | ||
BB | 14 / –606 | 2 / –229 | ||
ChO | 26 / –516 | 3 / –421 | ||
Envelopes | 12 / –75 | 1 / –265 | ||
IKH | 12 / –242 | 1 / –221 | ||
MA | 8 / –245 | 1 / –349 | ||
MESASWI | 18 / –477 | 1 / –452 | ||
Momentum | 59 / –861 | 2 / –326 | ||
RSI | 1 / –3 | 1 / –3 | ||
SO | 11 / –226 | 1 / –329 | ||
Fractals | 6 / –364 | 1 / –323 | ||
Сбербанк (ап) | AC | 8 / –146 | 1 / –148 | 420 |
ADX | 32 / –334 | 6 / 35 | ||
AO | 9 / –276 | 2 / –106 | ||
BB | 16 / –464 | 2 / –6 | ||
ChO | 20 / –320 | 3 / –106 | ||
Envelopes | 3 / 23 | 2 / 69 | ||
IKH | 12 / –36 | 1 / –5 | ||
MA | 5 / –264 | 1 / –133 | ||
MESASWI | 18 / –216 | 1 / –127 | ||
Momentum | 63 / –928 | 2 / –87 | ||
RSI | 2 / 64 | 1 / 4 | ||
SO | 10 / –276 | 1 / –113 | ||
Fractals | 5 / –249 | 1 / –54 | ||
Татнефть (ап) | AC | 6 / 94 | 4 / 152 | 519 |
ADX | 23 / –687 | 2 / 29 | ||
AO | 5 / 143 | 5 / 143 | ||
BB | 6 / –154 | 2 / 2 | ||
ChO | 12 / –197 | 3 / –24 | ||
Envelopes | 2 / 122 | 2 / 122 | ||
IKH | 5 / –44 | 2 / 110 | ||
MA | 6 / 73 | 1 / 72 | ||
MESASWI | 9 / –219 | 3 / 98 | ||
Momentum | 28 / –164 | 9 / 31 | ||
RSI | 1 / 61 | 1 / 61 | ||
SO | 6 / –44 | 1 / –13 | ||
Fractals | 3 / –145 | 1 / –102 |
Далее приводятся проверяемые стратегии и код, эту проверку обеспечивающий.
Проверяемая стратегия:
* Click-обработчик кнопки AC
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltAC(thisForm, hwVl, this)
Проверяемая стратегия:
* Click-обработчик кнопки ADX
clcltADX(thisForm, 3, 14, this)
Проверяемая стратегия:
Замечание. Пересечение с нулевой линией анализируется, если в функции fndScndMnOrXCrssng снят комментарий.
* Click-обработчик кнопки AO
clcltAO(thisForm, 3, 5, 34, this)
Проверяемая стратегия:
* Click-обработчик кнопки BB
clcltBB(thisForm, 2, this)
Проверяемая стратегия:
* Click-обработчик кнопки ChO
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltChO(thisForm, hwVl, this)
Проверяемая стратегия:
* Click-обработчик кнопки Envelopes
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltNvlps(thisForm, hwVl, this)
На рис. 56 черным цветом показан график цены, красным и зеленым – линии Envelopes; красные вертикальные линии показывают покупки, а синие – продажи актива.
Рис. 56. Покупки и продажи Envelopes
Проверяются две следующие стратегии (в приведенную выше таблицу внесены данные по стратегии 1).
* Click-обработчик кнопки IKH
clcltIKH(thisForm, 2, this)
Проверяемая стратегия:
* Click-обработчик кнопки MA
hwVl = IIF(thisForm.CheckShwSgnls.Value, 5, 4) && 4 to see curve; 5 - buy / sell signals
clcltMA(thisForm, hwVl, 0, 0, 0, this)
Проверяемая стратегия:
* Click-обработчик кнопки MESASWI
clcltMESASWI(thisForm, 2, this)
Проверяемая стратегия:
* Click-обработчик кнопки Momentum
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltMmntm(thisForm, hwVl, this)
Проверяемая стратегия:
* Click-обработчик кнопки RSI
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltRSI(thisForm, hwVl, this)
Проверяемая стратегия:
* Click-обработчик кнопки SO
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltSO(thisForm, hwVl, this)
На рис. 57 черным цветом показан график %K; красные вертикальные линии показывают покупки, а синие – продажи актива.
Рис. 57. Покупки и продажи SO
Проверяемая стратегия:
* Click-обработчик кнопки Fractals
hwVl = IIF(thisForm.CheckShwSgnls.Value, 3, 2) && 2 to see curve; 3 - buy / sell signals
clcltLlgtr(thisForm, .T., .F., hwVl, this)
Наблюдаемые результаты говорят о том, что механическое следование сигналам индикаторов не гарантирует положительного сальдо. Более того, при нисходящем тренде примененные стратегии убыточны.
Таким образом, проблема выбора индикатора остается открытой.