package.path = package.path .. ";" .. getWorkingFolder() .."\\LuaIndicators\\modules\\" .. "?.lua";
require ("Format");
require ("Round");
require ("Lines");
Settings={
Name = "0_28.02.2019_0",--имя индикатора
AssetID = "sber",--идентификатор инструмента
LabelName = "D:\метка.bmp",--имя файла метки "down-254095_1280_1",
stopper = false,--обработка на каждом тике
complect = 0,
-- начальное местоположение меток
fplace = 100,
splace = 5,
Yvalue = 0,
line=
{
{
Name = "ChTrnd",
Type =TYPE_LINE,
Width = 1,
Color = RGB(255,255, 0)
},
{
Name = "UpTrend",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,255,0)
},
{
Name = "DnTrend",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,255, 0)
},
{
Name = "APointLvl",
Type =TYPE_LINE,
Width = 1,
Color = RGB(120,90,140)
},
{
Name = "BPointLvl",
Type =TYPE_LINE,
Width = 1,
Color = RGB(120,90,140)
},
{
Name = "IntLine1",
Type =TYPE_LINE,
Width = 1,
Color = RGB(105,105,105)--DimGray
},
{
Name = "IntLine2",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0,255)--Blue
},
{
Name = "IntLine3",
Type =TYPE_LINE,
Width = 1,
Color = RGB(218,165,32)--Goldenrod
},
{
Name = "IntLine4",
Type =TYPE_LINE,
Width = 1,
Color = RGB(255,0,0)--Red
},
{
Name = "IntLine5",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,128,0)--Green
},
{
Name = "IntLine6",
Type =TYPE_DASHDOT,
Width = 2,
Color = RGB(255,0,0)--Red
}
}
}
--глобальные переменные
-- Внимание, название всех параметров меток должны писаться большими буквами
label={
--TEXT="метка";
IMAGE_PATH=Settings.LabelName;
--TRANSPARENCY=50,
--TRANSPARENT_BACKGROUND=1,
--YVALUE=Settings.Yvalue,
DATE=0,
TIME=0;
--R=255;
--G=255;
--B=255;
}
t={}--исходная таблица данных свечек
tposixByTime={}--индексы свечек проиндексированные по времени
tposixOldLabelTime={}--таблица старых значений даты-времени выведенных на чарт меток в POSIX-формате
count=0--ограничитель количества циклов
Label_Id = {}--массив с идентификаторами меток
ScriptPath=""--полный путь к иконке (для метки)
flagIndExist=false--флаг существования индикатора на чарте
flagLblModify=false--флаг, сигнализирующий о перемещении метки
a=0
b=0
c=0
k=0
v=0
tDT={}
g_PriceStep = 0--шаг цены
g_PriceScale = 0--точность цены
g_tChLines={}
g_APointIdx=0;
g_BPointIdx=0;
g_APointLvl=0;
g_BPointLvl=0;
function Init()
--объявление переменных. Присваиваем начальные значения чтобы сразу типизировать.
local n = 0--количество строк в таблице (количество свечек)
local l = ""--подпись инструмента
local NmbrOfCandles = 0--номер последней справа свечи на графике
local CandleIndex = 0
--local tDT={}
---[[
if Settings.AssetID == "" then
message("Необходимо установить идентификатор инструмента")
end
--ScriptPath = getScriptPath().."\\"..Settings.LabelName; --путь к файлу метки
--message("Init_ScriptPath "..ScriptPath);
--label["IMAGE_PATH"]=ScriptPath;
--номер предпоследней справа свечи на графике. Нумерация начинается с нуля.
NmbrOfCandles = getNumCandles(Settings.AssetID)-2;
--получим таблицу с данными всех свечек, проиндексированную по номеру свечки
--t - таблица значений свечек
--n - количество полученных свечек(строк таблицы)
--l - подпись к инструменту
--текущую свечу не получаем
t,n,l = getCandlesByIndex(Settings.AssetID,0,0,NmbrOfCandles);
--получить индекс двух свечек, номера которых заданы во входных параметрах
--и установить метки
CandleIndex = NmbrOfCandles-Settings.splace;
tposixOldLabelTime["splace"], Label_Id["splace"] = PUTLABEL(CandleIndex);
CandleIndex = NmbrOfCandles-Settings.fplace;
tposixOldLabelTime["fplace"], Label_Id["fplace"] = PUTLABEL(CandleIndex);
--берем из таблицы только время-дату свечи
count = 0;
for k=0,NmbrOfCandles-1 do
count = count + 1; if count > 100000 then break end;
--преобразуем в POSIX-формат поле datetime
--транспонируем таблицу - индексируем по времени
tDT[k] = os.time (t[k].datetime);
b=k;
tposixByTime[tDT[b]] = b;
--[[
if NmbrOfCandles-Settings.splace==b then
--message("Initsplace "..tostring(tDT[b]).." "..tostring(tposixByTime[b]))
end;
if NmbrOfCandles-Settings.fplace==b then
--message("Initfplace "..tostring(tDT[b]).." "..tostring(tposixByTime[b]))
end
--]]
end
return 11
end
function OnCalculate(index)
local info={}
local CandleIndex
local LblIdF = 0
local LblIdS = 0
local indput
local IndLines={}
local VChTrend
local VAPointLvl
local VBPointLvl
local flagIndChange=false--true-перестроить индикатор, false - не перестраивать
if index==1 then
info = getDataSourceInfo();
--шаг цены
g_PriceStep = getParamEx(info.class_code, info.sec_code, 'SEC_PRICE_STEP').param_value
--точность цены
g_PriceScale = getParamEx(info.class_code, info.sec_code, 'SEC_SCALE').param_value
end
if t==nil then
--номер предпоследней справа свечи на графике. Нумерация начинается с нуля.
NmbrOfCandles = getNumCandles(Settings.AssetID)-2;
--получим таблицу с данными всех свечек, проиндексированную по номеру свечки
--t - таблица значений свечек
--текущую свечу не получаем
t,n,l = getCandlesByIndex(Settings.AssetID,0,0,NmbrOfCandles);
--берем из таблицы только время-дату свечи
count = 0;
for k=0,NmbrOfCandles-1 do
count = count + 1; if count > 100000 then break end;
--преобразуем в POSIX-формат поле datetime
--транспонируем таблицу - индексируем по времени
tDT[k] = os.time (t[k].datetime);
b=k;
tposixByTime[tDT[b]] = b;
--[[
if NmbrOfCandles-Settings.splace==b then
--message("Initsplace "..tostring(tDT[b]).." "..tostring(tposixByTime[b]))
end;
if NmbrOfCandles-Settings.fplace==b then
--message("Initfplace "..tostring(tDT[b]).." "..tostring(tposixByTime[b]))
end
--]]
end
end
---[[
--если флаг перемещения метки не установлен
if flagLblModify==false then
--проверяем перемещалась ли первая метка
LblIdF=IsLabelChange("fplace");
--проверяем вторую метку
LblIdS=IsLabelChange("splace");
--если индикатор существует, то выходим без расчетов, возвращаем массив линий
if flagIndExist==true then
flagIndChange=false;
--иначе строим индикатор, возвращаем массив линий
else
flagIndChange=true;
end
--если метка перемещалась flagLblModify==true
else
--строим индикатор, выставляем флаг изменения индикатора,
--сбрасываем флаг метки, возвращаем индикатор
flagIndChange=true;
end
--рассчитываем индикатор или выводим линии без расчета
VChTrend,VChUp,VChDn,VAPointLvl,VBPointLvl,VIntLine1=PUTINDICATOR(LblIdF,LblIdS,flagIndChange,index)
--]]
if index==0 then VChTrend=nil end
if index >= Size() then VChTrend=nil end
return VChTrend,VChUp,VChDn,VAPointLvl,VBPointLvl,VIntLine1,VIntLine2,VIntLine3,VIntLine4,VIntLine5,VIntLine6
end
function IsLabelChange(place)
--функция принимает индекс массива Label_Id("строка")
--устанавливает глобальные флаги и
--записывает posix-время в глобальную таблицу tposixOldLabelTime
--возврашает Id метки
local LblId = 0
local posixNewLblTime = 0
local posixOldLblTime = 0
--проверяем перемещалась ли метка
--считываем Id метки из массива
LblId = Label_Id[place];
--считываем posix-время для этой метки
posixOldLblTime = tposixOldLabelTime[place];
--преобразуем время метки с чарта в posix-формат
--если функция вернула nil, время не меняем
if GETLABLEPOSIXTIME (LblId)== 0 then
posixNewLblTime = posixOldLblTime
else
posixNewLblTime = GETLABLEPOSIXTIME (LblId)
end
--если время не совпадает, выставляем флаги отсутствия индикатора и модификации метки
if posixOldLblTime ~= posixNewLblTime then
--выставляем флаги
--метка перемещена
flagLblModify=true;
--индикатор не построен
flagIndExist=false;
--изменяем время метки в массиве
tposixOldLabelTime[place] = posixNewLblTime;
end
return LblId
end
PUTLABEL = function (index)
--[[функция для установки метки на чарт по индексу
принимает индекс свечи
возвращает время метки в posix-формате и Id метки
входные параметры:
-индекс свечи
-строка с названием точки для индексации массива установленных меток
вызывается в Init()
--]]
local Date=""--дата свечки
local Time=""--время свечки
local Yvalue=0
LabelId=0
--message ("PUTLABELindex.."..tostring(index));
--дата и время свечи
Date=t[index].datetime.year..Format.FTEXT(t[index].datetime.month)..Format.FTEXT(t[index].datetime.day); --дата
Time=Format.FTEXT(t[index].datetime.hour)..Format.FTEXT(t[index].datetime.min)..Format.FTEXT(t[index].datetime.sec);
--привязка к оси У
Yvalue = t[index].high;
--заполнить структуру данных метки
label={
IMAGE_PATH=Settings.LabelName;
YVALUE=Settings.Yvalue+Yvalue;
DATE=Date,
TIME=Time
};
--добавляем метку на чарт и запоминаем Id метки в массиве, проиндексированном принятой строкой
LabelId = AddLabel(Settings.AssetID,label);
--message ("PUTLABELindex LabelId "..tostring(LabelId))
return os.time (t[index].datetime), LabelId
end
function GETLABLEPOSIXTIME (LabelId)
--функция принимает Id метки и возвращает ее время в posix-формате
--при перемещении метки временно Id может стать нулем, поэтому функция выдает ошибку ноль
local id--Id метки
local NewLbLParam = {}--структура параметров метки
local LabelTime = ""--строка с данными даты-времени метки
local dt={}--структура в формате datetime
local err=0
local retval
---[[
id = LabelId;
--получаем таблицу с параметрами метки (в нижнем регистре в формате строки)
if LabelId==0 then retval=err
else
NewLbLParam = GetLabelParams(Settings.AssetID, id);
--преобразуем в формат datetime
dt.year,dt.month,dt.day = string.match(NewLbLParam.date,"(%d%d%d%d)(%d%d)(%d%d)")
if #NewLbLParam.time == 5 then
LabelTime="0".. NewLbLParam.time
else LabelTime="".. NewLbLParam.time
end
dt.hour,dt.min,dt.sec = string.match(LabelTime,"(%d%d)(%d%d)(%d%d)");
--преобразуем в формат POSIX
retval = os.time (dt)
end;
return retval;
end
function PUTINDICATOR(LblId1,LblId2,boolIndChange,idx)
local a=0
local i
local j
local k
local TrndH=0
local TrndL=0
local h
local l
local CndlIdx1=0
local CndlIdx2=0
local tABIdx={}
local IntervalCndlNmbr=0
local koef
local tChTrend={}
local tChUp={}
local tChDn={}
local ChUpMax=0
local ChDnMin=0
local posixLblTime1
local posixLblTime2
local APointIdx
local BPointIdx
local APointLvl
local BPointLvl
local idxUpMax
local idxDnMin
local AidxUp
local AidxDn
local BidxUp
local BidxDn
local ChTrnd--=200
local ChUp--=210
local ChDn--=190
local APntLvl--=220
local BPntLvl--=180
local StepsUp
local TrUp=false
local TrDn=false
local Lu
g_tChLines["ChTrend"]=tChTrend;
g_tChLines["ChUp"]=tChUp;
g_tChLines["ChDn"]=tChDn;
--если метка перемещалась или индикатор строится впервые рассчитываем линии и выводим их
if boolIndChange then
--для каждой свечи в интервале между метками получить максимальное и минимальное
--значение цены
--сравниваем время меток для задания переменной цикла
--если GETLABLEPOSIXTIME вернула ошибку
if GETLABLEPOSIXTIME (LblId1)==0 or LblId1==0 then
--считываем старое время из массива
posixLblTime1 = tposixOldLabelTime.fplace
--иначе считываем новое время метки
else posixLblTime1 = GETLABLEPOSIXTIME (LblId1)
end
--так же и для второй метки
if GETLABLEPOSIXTIME (LblId2)==0 or LblId2==0 then
posixLblTime2 = tposixOldLabelTime.splace
else posixLblTime2 = GETLABLEPOSIXTIME (LblId2)
end
--получаем значения индекса свечи по его posix-времени
CndlIdx1=tposixByTime[posixLblTime1];
CndlIdx2=tposixByTime[posixLblTime2];
--если метка перемещена вправо за последнюю свечу, то индекс = максимальному
if CndlIdx1 == nil then CndlIdx1 = Size() end
if CndlIdx2 == nil then CndlIdx2 = Size() end
--находим более раннюю свечу
if CndlIdx1 < CndlIdx2 then
j=CndlIdx1;
k=CndlIdx2
else
j=CndlIdx2;
k=CndlIdx1
end
--message("PUTINDICATOR_CndlIdx1_CndlIdx2_j_k_"..tostring(CndlIdx1).."_"..tostring(CndlIdx2).."_"..tostring(j).."_"..tostring(k));
--для всех свечей внутри диапазона меток
for i = j, k, 1 do
--находим максимальное и минимальное значение и индекс свечки
h = t[i].high;
l = t[i].low;
if h~=0 then
if h >= TrndH then
TrndH = h;
tABIdx["hi"] = i--индекс свечки
end;
end
if l~=0 then
if TrndL==0 then TrndL = l end;
if l <= TrndL then
TrndL = l;
tABIdx["lo"] = i--индекс свечки
end;
end
--message("PUTINDICATOR_h_l_"..tostring(h).."_"..tostring(l));
--message("PUTINDICATOR_TrndH_TrndL_tABIdx.hi_tABIdx.lo_"..tostring(TrndH).."_"..tostring(TrndL).."_"..tostring(tABIdx["hi"]).."_"..tostring(tABIdx["lo"]));
end
--находим количество свечек на интервале тренда (от точек А и В)
IntervalCndlNmbr = tABIdx["hi"] - tABIdx["lo"];
--если получили отрицательное число(слева индекс максимума, тренд вниз), то инвертируем
if IntervalCndlNmbr < 0 then
TrUp=false;
TrDn=true;
APointIdx=tABIdx["hi"];
BPointIdx=tABIdx["lo"];
APointLvl=TrndH;
BPointLvl=TrndL;
else
TrUp=true;
TrDn=false;
APointIdx=tABIdx["lo"];
BPointIdx=tABIdx["hi"];
APointLvl=TrndL;
BPointLvl=TrndH;
IntervalCndlNmbr=-IntervalCndlNmbr
end;
--message("PUTINDICATOR_APointIdx_BPointIdx_APointLvl_BPointLvl_"..tostring(APointIdx).."_"..tostring(BPointIdx).."_"..tostring(APointLvl).."_"..tostring(BPointLvl));
--вычисляем коэффициент наклона прямой
--отрицательный (тренд вниз),положительный (тренд вверх)
koef = (APointLvl - BPointLvl)/IntervalCndlNmbr
--message("PUTINDICATOR koef "..tostring(koef));
--цикл для вычисления значений всеx линий
--заносим значения в таблицу
--tChTrend[APointIdx] = Round.math_round(APointLvl,g_PriceScale);
--g_tChLines.tChTrend = tChTrend[APointIdx]
--tChTrend[BPointIdx] = Round.math_round(BPointLvl,g_PriceScale);
--g_tChLines.tChTrend = tChTrend[BPointIdx]
j=0;
for i=APointIdx, BPointIdx, 1 do
--вычисляем значения точек основного тренда
--i-индекс свечи, j - номер шага
tChTrend[i] = Round.math_round(APointLvl+koef*j,g_PriceScale);
--заносим значения тренда в глобальную таблицу
g_tChLines.tChTrend = tChTrend[i]
--вычисляем значения точек верхней и нижней границы канала
h = t[i].high;
l = t[i].low;
if h - tChTrend[i] > 0 and h~=0 then
if
ChUpMax < h - tChTrend[i]
then
--максимальное отклонение от тренда вверх
ChUpMax = h - tChTrend[i];
--индекс свечи с максимальным отклонением от тренда
idxUpMax = i;
end
end
if tChTrend[i] -l > 0 and l~=0 then
if
ChDnMin < tChTrend[i] -l
then
ChDnMin = tChTrend[i] - l;
idxDnMin = i;
end
end
j=j+1;
end
--количество шагов от точки А
StepsUp=Round.math_round(ChUpMax/koef,0)
--сдвиг назад
AidxUp = APointIdx - StepsUp;
BidxUp = BPointIdx - StepsUp;
--количество шагов от точки А
StepsDn=Round.math_round(ChDnMin/koef,0)
--сдвиг вперед
AidxDn = APointIdx + StepsDn;
BidxDn = BPointIdx + StepsDn;
---[[
--цикл по сдвинутому назад диапазону
j=0;
for i=AidxUp, BidxUp, 1 do
--линия тренда верхней границы канала
tChUp[i] = math_round(APointLvl+koef*j,g_PriceScale);
g_tChLines.tChUp = tChUp[i]
--message("PUTINDICATOR tChUp_i "..tostring( tChUp[i]).." "..tostring(i));
j=j+1;
end
--цикл по сдвинутому вперед диапазону
j=0;
for i=AidxDn, BidxDn, 1 do
--линия тренда нижней границы канала
tChDn[i] = math_round(APointLvl+koef*j,g_PriceScale);
g_tChLines.tChDn = tChDn[i]
--message("PUTINDICATOR tChDn_i "..tostring( tChDn[i]).." "..tostring(i));
j=j+1;
end
if TrUp==true then
--уровени IntLine
IntLine1=tChUp[APointIdx]
IntLine2=tChTrend[AidxDn]
IntLine3=tChUp[AidxDn]
IntLine4=tChTrend[BidxUp]
IntLine5=tChDn[BidxUp]
IntLine6=tChDn[BPointIdx]
end
if TrDn==true then
--уровень IntLine1
IntLine1=tChDn[APointIdx]
IntLine2=tChTrend[AidxUp]
IntLine3=tChDn[AidxUp]
IntLine4=tChTrend[BidxDn]
IntLine5=tChUp[BidxDn]
IntLine6=tChUp[BPointIdx]
end
g_APointIdx=APointIdx;
g_BPointIdx=BPointIdx;
g_APointLvl=APointLvl;
g_BPointLvl=BPointLvl;
--]]
ChTrnd=GETTRENDLINE(1,g_APointIdx,g_BPointIdx,"ChTrend")
ChUp=GETTRENDLINE(2,AidxUp,BidxUp,"ChUp")
ChDn=GETTRENDLINE(3,AidxDn,BidxDn,"ChDn")
APntLvl=GETHORLINE(g_APointLvl,4,g_APointIdx)
BPntLvl=GETHORLINE(g_BPointLvl,5,g_BPointIdx)
IntLin1=GETHORLINE(IntLine1,6,g_APointIdx)
if TrUp then Lu=AidxDn end
if TrDn then Lu=AidxUp end
IntLin2=GETHORLINE(IntLine2,7,Lu)
IntLin3=GETHORLINE(IntLine3,8,Lu)
if TrUp then Lu=BidxUp end
if TrDn then Lu=BidxDn end
IntLin4=GETHORLINE(IntLine4,9,Lu)
IntLin5=GETHORLINE(IntLine5,10,Lu)
IntLin6=GETHORLINE(IntLine6,11,g_BPointIdx)
--перестроили индикатор-устанавливаем флаг
flagIndExist=true;
flagLblModify=false
end
return ChTrnd,ChUp,ChDn,APntLvl,BPntLvl,IntLin1,IntLin2,IntLin3,IntLin4,IntLin5,IntLin6
--]]
end
function math_round (num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function GETHORLINE(Level,LineNumber,Luch)
--Luch - индекс свечи от которой начнется прямая
local indx
local Line
local z
indx=Size()
for i=0,indx do
if Luch==nil then
Line=Level
else
if i<=Luch then
Line=nil
else
Line=Level
end
end
z=SetValue(i, LineNumber, Line)
end
--message("GETHORLINE Line "..tostring(Line));
return Line
end
function GETTRENDLINE(LineNumber,APntIdx,BPntIdx,Trend)
---[[
local Line
local indx
local TrLine={}
--message("GETTRENDLINE LineNumber Trend "..tostring(LineNumber).." "..tostring(Trend));
--message("GETTRENDLINE APntIdx BPntIdx "..tostring(APntIdx).." "..tostring(BPntIdx));
SetValue(1, LineNumber, nil)
indx=Size();
for i=1,indx do
if i < APntIdx then
TrLine[i]=nil
SetValue(i+1, LineNumber, TrLine[i])
end
if i > BPntIdx then
TrLine[i]=nil
SetValue(i+1, LineNumber, TrLine[i])
end
if i>=APntIdx and i<=BPntIdx then
TrLine[i]=g_tChLines[Trend][i]
--message("GETTRENDLINE TrLine_i "..tostring(i).." "..tostring(TrLine[i]));
SetValue(i+1, LineNumber, TrLine[i])
end
end
return TrLine
--]]
end
function OnDestroy ()
local tmp
tmp=DelAllLabels(Settings.AssetID)
end
|