Избранное трейдера anvil
Приветствую!
В предыдущей статье писал, о целях поиска локального боковика с помощью алгоритма. Расскажу с какими сложностями при этом приходится сталкиваться.
1 Что есть боковик? почему в одном случае мы считаем что это боковик, а в другом похожем случае это не является боковиком?
2 Размер боковика! Локальный боковик может быть как 0.1% от цены так и несколько процентов от цены.
Так же можно описать множество пунктов, но они все смежные будут с выделенными двумя пунктами.
Как определить, что рынок возле той или иной цены остановится и пойдет обратно? только не постфактум, а именно онлайн. Да, мы рисуем уровни руками, или же смотрим на объемы и тд, но изначально никто не знает где и почему цена остановилась. Мы всегда наблюдаем уже постфактум, либо это синусоида цены, либо накопление объемов на уровне и тд. А значит мы с определением боковика всегда будем опаздывать от реального рынка.
Второй же пункт, это границы бокового движения. Пример сбера, последние две три недели он гулял в большом диапазоне от 20300 до 21000 грубо говоря, но при этом были и локальные уровни остановки цены в пределах 100-200р канала. В таком ракурсе получается, что при движении от нижнего канала к верхнему с учетом остановок, можно получать 300-400р с движения если отталкиваться от того, что цена вышла из маленького боковика и движется к большому.
Именно эти сложности приходится преодолевать при алгоритмизации. Ведь алгоритм должен сам определить боковое это движение или вялотекущее направленное.
Пока что не придумал ничего толкового. Есть идея, которую наполовину реализовал
1 проверяю выше закрытие предыдущего или нет, и строю верхний канал по большему значению
2 аналогично для нижнего канала, проверяю ниже мы предыдущего закрытия или нет.
3 слежу за ситуациями при которых верхнее значение канала как и нижнее значение не менялось более 60минут (это уже параметр, можно и без него конечно, через счетчик получив просто силу канала, например что мы 5 часов не вышли за границы, или же например сколько раз «кололи» канал но вернулись в его границы и тд)
4 канал считается не действительным при резком закреплении цены выше его границ, допустим большой минутной свечой закрылись выше/ниже границ
5 границы канала должны меняться после направленного движения и новой остановки
6 размах от верхнего к нижнему значению, не должен превышать Х% от цены
Какие минусы
1 Процент размаха дает возможность смотреть маленький ли канал в данный момент или большой, но это является параметром, а значит может привести к «лудоманству». Каких либо других возможностей поиска локального боковика пока что, не видится возможным, потому остановился на этом
2 Я всегда опаздываю за ценой. Если действовать сразу и брать с первых же баров определение боковика, то будет очень большое количество ложных определений, и соответственно, множество не правильных входов
3 Любые остановы движения цены, ломают логику и идет поиск очередного боковика, обычно это преждевременно получается.
4 Ложное расширение боковика, которое можно определить только постфактумом и нужно перерисовывать границы.
Ниже примеры в картинках

Ложный выход из боковика

Settings=
{
Name = "Zigzag2", -- название индикатора
delta=2, -- параметр индикатора
line=
{
{
Name = "zigzagline2",
Type =TYPE_LINE,
Width = 2,
Color = RGB(120,90, 140)
}
}
}
function Init()
vMin = 0
vMax = 0
vMinindex = 0
vMaxindex = 0
voldMinindex = 0
voldMaxindex = 0
return 1
end
function OnCalculate(index)
local printz = 0
if index == 1 then
vMin = C(index)
vMax = C(index)
vMinindex = index
vMaxindex = index
voldMinindex = index
voldMaxindex = index
ve = C(index)
else
if voldMaxindex >= voldMinindex then
if C(index) > (1 + Settings.delta/100)*vMin then
vMin = C(index)
vMax = C(index)
vMaxindex = index
voldMinindex = vMinindex
vFrom = voldMaxindex
vTo = vMinindex
printz = 1
else
if vMin > C(index) then
vMin = C(index)
vMinindex = index
vFrom = voldMaxindex
vTo = index
printz = 0
else
vFrom = vMinindex
vTo = index
printz = 0
end
end
else
if voldMaxindex <= voldMinindex then
if C(index) < (1 - Settings.delta/100)*vMax then
vMax = C(index)
vMin = C(index)
vMinindex = index
voldMaxindex = vMaxindex
vFrom = voldMinindex
vTo = vMaxindex
printz = 1
else
if vMax < C(index) then
vMax = C(index)
vMaxindex = index
vFrom = voldMinindex
vTo = index
printz = 0
else
vFrom = vMaxindex
vTo = index
printz = 0
end
end
end
end
if (printz == 1) or (Size() == index) then
for i = vFrom, vTo do
k = (C(vTo)- C(vFrom))/(vTo- vFrom);
v = i*k + C(vTo) - vTo*k
SetValue(i, 1, v)
ve = v
end
if (Size() == index) then
ve = C(index)
if voldMaxindex >= voldMinindex then
vFrom = voldMaxindex
vTo = vMinindex
end
if voldMaxindex <= voldMinindex then
vFrom = voldMinindex
vTo = vMaxindex
end
for i = vFrom, vTo do
k = (C(vTo)- C(vFrom))/(vTo- vFrom);
v = i*k + C(vTo) - vTo*k
SetValue(i, 1, v)
end
end
end
end
return ve
endВсех приветствую!
Первый год публичной алго торговли закончился с результатом +100%.
Первый пост о моем пути к алготрейдингу тут
В этом посте подробно разберу результаты за прошлый год, а также попытаюсь ответить на вопрос – одурачен ли я случайностью?
На рисунке изменение депозита и фьючерса долл./руб.

Все системы торговали на фьючерсе долл./руб. Примерно 75% систем работают на волатильности, остальные пытаются поймать тренд. В начале года затишье, которое к концу марта привело к просадке в 30%. Ну а дальше роботы оседлали взрыв рынка. 8 августа вывел 10% от первоначального депо, в этот же период был удержан НДФЛ на всю сумму накопившегося дохода.
Красным цветом выделил зоны, где алгоритмы не смогли заработать на волатильности. То есть движения были, но они были «плохими». В эти периоды дневные свечи имели большие тени как с верху, так и снизу. Поэтому, не смотря на хорошую волатильность их возило по стопам. Зеленые зоны – экстремально низкая волатильность и сильные просадки.

Settings={
Name="STATDIV3",
period=50,
line=
{
{
Name="curve",
Color=RGB(0,0,255),
Type=TYPE_LINE,
Width=1
},
{
Name="line",
Color=RGB(255,0,0),
Type=TYPE_LINE,
Width=1
},
{
Name="MA",
Color=RGB(0,0,255),
Type=TYPE_LINE,
Width=1
},
{
Name="MA2",
Color=RGB(0,128,128),
Type=TYPE_LINE,
Width=1
},
{
Name="line2",
Color=RGB(0,0,255),
Type=TYPE_LINE,
Width=1
},
{
Name="line3",
Color=RGB(0,128,128),
Type=TYPE_LINE,
Width=1
}
}
}
function Init()
cache_ind={}
cache_ind2={}
cache_ind3={}
return 2
end
function OnCalculate(index)
if index < Settings.period then
return nil
else
local sum1=0
local sum2=0
local sum0=0
local sum02=0
local sum03=0
for i=index-Settings.period+1, index do
do
if C(i) > O(i) then
sum1 = sum1 + C(i) - O(i)
sum2 = sum2 + C(i) - O(i)
else
sum2 = sum2 + O(i) - C(i)
end
end
cache_ind[index] = sum1/sum2
if index > Settings.period+12 then
--[[
sum0 = 1*cache_ind[index]+
(1)*cache_ind[index-1]+
(1)*cache_ind[index-2]+
(1)*cache_ind[index-3]+
(1)*cache_ind[index-4]+
(1)*cache_ind[index-5]+
(1)*cache_ind[index-6]+
(1)*cache_ind[index-7]+
(1)*cache_ind[index-8]+
(1/2)*cache_ind[index-9]+
(1/3)*cache_ind[index-10]+
(1/4)*cache_ind[index-11]+
(1/5)*cache_ind[index-12]
--]]
sum0 = 1*cache_ind[index]+
(1/2)*cache_ind[index-1]+
(1/3)*cache_ind[index-2]+
(1/4)*cache_ind[index-3]+
(1/5)*cache_ind[index-4]+
(1/6)*cache_ind[index-5]+
(1/7)*cache_ind[index-6]+
(1/8)*cache_ind[index-7]+
(1/9)*cache_ind[index-8]+
(1/10)*cache_ind[index-9]+
(1/11)*cache_ind[index-10]+
(1/12)*cache_ind[index-11]+
(1/13)*cache_ind[index-12]
end
--[[
sum0 = sum0/(1+1+1+1+1+1+1+1+1+1/2+1/3+1/4+1/5)
--]]
sum0 = sum0/(1+1/2+1/3+1/4+1/5+1/6+1/7+1/8+1/9+1/10+1/11+1/12+1/13)
cache_ind2[index] = sum0
if index > Settings.period+50 then
sum02 = 1*cache_ind2[index]+
(1)*cache_ind2[index-1]+
(1)*cache_ind2[index-2]+
(1)*cache_ind2[index-3]+
(1)*cache_ind2[index-4]+
(1)*cache_ind2[index-5]+
(1)*cache_ind2[index-6]+
(1)*cache_ind2[index-7]+
(1/2)*cache_ind2[index-8]+
(1/3)*cache_ind2[index-9]+
(1/4)*cache_ind2[index-10]+
(1/5)*cache_ind2[index-11]+
(1/6)*cache_ind2[index-12]
--[[
sum02 = 1*cache_ind2[index]+
(1/2)*cache_ind2[index-1]+
(1/3)*cache_ind2[index-2]+
(1/4)*cache_ind2[index-3]+
(1/5)*cache_ind2[index-4]+
(1/6)*cache_ind2[index-5]+
(1/7)*cache_ind2[index-6]+
(1/8)*cache_ind2[index-7]+
(1/9)*cache_ind2[index-8]+
(1/10)*cache_ind2[index-9]+
(1/11)*cache_ind2[index-10]+
(1/12)*cache_ind2[index-11]+
(1/13)*cache_ind2[index-12]
--]]
end
sum02 = sum02/(1+1+1+1+1+1+1+1+1/2+1/3+1/4+1/5+1/6)
--[[
sum02 = sum02/(1+1/2+1/3+1/4+1/5+1/6+1/7+1/8+1/9+1/10+1/11+1/12+1/13)
--]]
cache_ind3[index] = sum0 - sum02
if index > Settings.period+50 then
sum03 = 1*cache_ind3[index]+
(1/2)*cache_ind3[index-1]+
(1/3)*cache_ind3[index-2]+
(1/4)*cache_ind3[index-3]+
(1/5)*cache_ind3[index-4]+
(1/6)*cache_ind3[index-5]+
(1/7)*cache_ind3[index-6]+
(1/8)*cache_ind3[index-7]+
(1/9)*cache_ind3[index-8]+
(1/10)*cache_ind3[index-9]+
(1/11)*cache_ind3[index-10]+
(1/12)*cache_ind3[index-11]+
(1/13)*cache_ind3[index-12]
end
sum03 = sum03/(1+1/2+1/3+1/4+1/5+1/6+1/7+1/8+1/9+1/10+1/11+1/12+1/13)
end
if sum1/sum2 > 0.5 and sum03 > 0 then
sum1 = sum03
else
if sum1/sum2 < 0.5 and sum03 < 0 then
sum1 = sum03
else
sum1 = 0
end
end
return sum1, 0
end
endЕсли у вас есть проблемы с определением потенциального разворота рынка, тогда этот урок для вас. Ценовой паттерн Pivot Point Reversal — это один из тех сигналов, которые используют профессиональные трейдеры для нахождения точек разворота тренда. Никакие индикаторы в данном методе не используются. В данном уроке упоминается внутренний бар, о котором я уже писал руководство - https://smart-lab.ru/blog/518242.php.
Что такое Pivot Point Reversal?Pivot Point Reversal — это разворотный ценовой паттерн, который состоит из трёх и более свечей, и сделка открывается в направлении пробоя поддержки или сопротивления главной свечи: для медвежьего сетапа ожидаем пробоя поддержки, для бычьего сетапа ожидаем пробоя сопротивления.
--Массив с Тикерами, добавьте нужные тикеры
aTickerList = {"MSNG", "GAZP", "LKOH",
"SIBN", "GMKN","ROSN",
"SBER", "TATN", "NVTK",
"IRAO", "RSTI", "SBERP",
"PHOR", "SNGS", "TRNFP",
"VTBR", "FEES", "MVID",
"RASP", "MFON", "AFLT",
"MAGN", "ALRS", "MTSS", "MOEX",
"RTKM", "MGNT", "NLMK", "SNGSP",
"CHMF", "MTLR", "HYDR", "MFON",
"RSTI", "PLZL", "BANEP", "POLY"
};
--Функция поиска цены
function fGetPrice(sTickerName, sNum)
--Подключаемся к источнику данных
local ds=CreateDataSource("TQBR", sTickerName, INTERVAL_D1);
while (Error=="" or Error == nil) and ds:Size() ==0 do sleep(10) end;
if Error ~="" and Error ~=nil then message("Error: "..Error, 1) end;
local sSize=ds:Size();
local sCurrentPrice=ds:O(sSize);
local sLastWeekPrice7=0;
local sLastWeekPrice14=0;
--Берем цену закрытия свечи неделю назад
sLastWeekPrice7=ds:C(sSize-4);
--Берем цену закрытия свечи 2 недели назад
sLastWeekPrice14=ds:C(sSize-8);
--Вычисляем проценты
local sPrc7=math.floor((100-((sLastWeekPrice7*100)/sCurrentPrice))*100)/100;
local sPrc14=math.floor((100-((sLastWeekPrice14*100)/sCurrentPrice))*100)/100;
--Заполняем таблицу значениями
SetCell(t_id, sNum, 0, tostring(sTickerName));
SetCell(t_id, sNum, 1, tostring(sCurrentPrice),sCurrentPrice);
SetCell(t_id, sNum, 2, tostring(sLastWeekPrice7),sLastWeekPrice7);
SetCell(t_id, sNum, 3, tostring(sLastWeekPrice14),sLastWeekPrice14);
SetCell(t_id, sNum, 4, tostring(sPrc7),sPrc7);
SetCell(t_id, sNum, 5, tostring(sPrc14),sPrc14);
--Текущая цена больше цены прошлой недели - раскрашиваем зеленым
if sCurrentPrice>sLastWeekPrice7 then
fGreen(sNum);
end;
--Текущая цена меньше цены прошлой недели - раскрашиваем красным
if sCurrentPrice<sLastWeekPrice7 then
fRed(sNum);
end;
--Текущая цена больше цены прошлой недели и цена прошлой недели больше цены позапрошлой недели
--раскрашиваем желтым
if sCurrentPrice>sLastWeekPrice7 and sLastWeekPrice7>sLastWeekPrice14 then
fYellow(sNum);
end;
end;
--- Функция создает таблицу
function CreateTable()
-- Получает доступный id для создания
t_id = AllocTable();
-- Добавляет 6 колонок
AddColumn(t_id, 0, "Тикер", true, QTABLE_INT_TYPE, 15);
AddColumn(t_id, 1, "Сегодня", true, QTABLE_INT_TYPE, 15);
AddColumn(t_id, 2, "Неделя", true, QTABLE_INT_TYPE, 15);
AddColumn(t_id, 3, "2 Недели", true, QTABLE_INT_TYPE, 15);
AddColumn(t_id, 4, "Неделя (%)", true, QTABLE_INT_TYPE, 15);
AddColumn(t_id, 5, "2 Недели (%)", true, QTABLE_INT_TYPE, 15);
-- Создаем
t = CreateWindow(t_id);
-- Даем заголовок
SetWindowCaption(t_id, "7 Days");
-- Добавляем строки
for k,v in pairs(aTickerList) do
InsertRow(t_id, k);
end;
end;
--- Функции раскрашивают ячейки таблицы
function fRed(col)
SetColor(t_id, col, -1, RGB(255,168,164), RGB(0,0,0), RGB(255,168,164), RGB(0,0,0));
end;
function fGreen(col)
SetColor(t_id, col, -1, RGB(157,241,163), RGB(0,0,0), RGB(157,241,163), RGB(0,0,0));
end;
function fYellow(col)
SetColor(t_id, col, -1, RGB(249,247,172), RGB(0,0,0), RGB(249,247,172), RGB(0,0,0));
end;
--Основная функция
function main()
-- Создаем таблицу
CreateTable();
--Пробегаемся по массиву тикеров
for k,v in pairs(aTickerList) do
fGetPrice(v, k);
end;
end;как выглядит в квике: