при выводе таблиц по DDE в Эксель Quik - это сервер или клиент? Если сервер, то где в Эксель находятся ячейки с DDE запросом и почему вывод таблицы обезличенных сделок идет построчно с записью в каждую новую строку?
Я так понимаю, что вывод организован через библиотеку DLL. Для ускорения работы по DDE в Эксель рекомендуют использовать метод SetLinkOnData, но в нем в качестве параметра нужно указать DDE-ссылку с запросом к серверу. В выводимой таблице я таких ссылок не обнаружил. Посему вопрос - где можно эту ссылку увидеть, в какую ячейку выводятся данные и как организовано копирование из одной ячейки в строки. Хотя бы в общих чертах, чтобы понять куда рыть. Заранее благодарен за ответ.
Для правильного расчета индикаторов мне необходимо посчитать количество свечек на графике. В моменты отсутствия торгов свечи на графике просто пропускаются. Возможно ли вывести на месте отсутствующих свечек цену закрытия сессии на каждой свече вплоть до начала следующей сессии. Если такой вопрос уже поднимался, прошу поделиться ссылкой.
function GETTRENDLINE(LineNumber,APntIdx,BPntIdx,Trend)
---[[
local Line
local indx
local TrLine={}
indx=Size()-1;
for i=0,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]
if LineNumber==2 then
message("GETTRENDLINE "..tostring( g_tChLines[Trend][i]).." "..tostring(i))
end
SetValue(i+1, LineNumber, TrLine[i])
end
end
return TrLine
--]]
end
В коде индикатора вычисляю значения и записываю их в массив
Код
j=0;
for i=AidxUp, BidxUp, 1 do
--линия тренда верхней границы канала
tChUp[i] = math_round(APointLvl+koef*j,g_PriceScale);
g_tChLines.tChUp = tChUp[i]
if idx==Size() then
message("PUTINDICATOR_Up "..tostring(g_tChLines.tChUp).." "..tostring(i))
end
j=j+1;
end
вызываю функцию
Код
ChUp=GETTRENDLINE(2,AidxUp,BidxUp,"ChUp")
и получаю странный результат - в передаваемом массиве внутри функции и в нем же при вычислении не совпадает последнее значение массива
Недавно я пытался получить разъяснения по поводу получения данных с графика. Получил такой ответ:"вместо getCandlesByIndex() в индикаторе надо использовать функции O, H, L, C, V, T которые вернут данные о свечке по ее индексу на которую наложен индикатор."
НаписАл код:
Код
Settings = {
Name = "0_Candle",
line =
{
{
Name = "__Trend",
Color = RGB(255, 255, 128),
Width = 2,
Type = TYPE_LINE
}
}
}
dt={}
function Init()
local Num=Size()
for i=1, Num do
dt=T(i)
message(tostring(dt(i).hour))
end
return 1
end
function OnCalculate(index)
return Line1
end
И получил ошибку обращения к таблице dt. Что в коде не так?
Вчера я выкладывал код индикатора, который работает на всех ТФ Н4 и ниже и отказывается работать на дневках и выше. И вот какие раскопал неожиданности. В функции Init() я создаю таблицу всех свечек, затем вот таким кодом вывожу ее:
Код
t,n,l = getCandlesByIndex(Settings.AssetID,0,0,NmbrOfCandles);
for i=0, NmbrOfCandles do
message("Init_t "..tostring(t[i]))
end
При запуске индикатора получаю шестнадцатиричные значения - вроде как таблица заполнена. Затем в функции PUTINDICATOR, которая вызывается из OnCalculate в строке:
Код
h = t[i].high;
на каждой свече получаю ошибку с описанием "попытка индексации неизвестного (?) поля (nil value). Никаких преобразований с таблицей в коде после ее создания я не произвожу, только считываю значения. Еще раз обращаю внимание, что код нормально работает на ТФ Н4 и ниже. Как такое может быть?
Прошу помочь в таком вопросе - меняю тип линии в Settings - реакции ноль, выводится только сплошная. Пытаюсь изменить тип в диалоге редактирования - такая же байда. Что делаю не так?
Собственно сам вопрос задан в теме. Количество заданных линий пять, но странности возникают при выводе. Сам алгоритм индикатора таков, что сначала рассчитываются трендовые линии, а затем принудительно при помощи SetValue они выводятся на график. Таких линий три.Затем пытаюсь добавить две горизонтальные линии, проходящие через концы трендовых, но горизонтальные мало того, что не отображаются, так еще и не выводятся в окне редактирования. Причем последнее обстоятельство обнаружил случайно на третий день мучений и вскипания мозга. Кто-нибудь с таким сталкивался?
Прошу ответить всех кто сталкивался с подобным поведением. Добавляю в код всего одну строку require ("Lbels"); и индикатор исчезает из списка в окне доступных индикаторов. Я так понимаю, что такое поведение интерпретатора наблюдается при ошибках в синтаксисе. Но где здесь ошибка? Может что-то не так с системными файлами или виртуальной машиной LUA? Кто сталкивался с такой проблемой и как такое можно решить?
Функция ниже пишет - ошибка в строке.... попытка индексации локальной переменной TrLine в блоке if i > BPntIdx then TrLine[i]=nil SetValue(i, LineNumber, TrLine[i]) end
хотя точно в таком же блоке выше ошибки не возникает. В чем может быть проблема?
Код
function GETTRENDLINE(LineNumber,APntIdx,BPntIdx)
local Line
local indx
local TrLine={}
indx=Size();
for i=1,indx do
if i < APntIdx then
TrLine[i]=nil
SetValue(i, LineNumber, TrLine[i])
end
if i>=APntIdx and i<=BPntIdx then
TrLine=g_tChLines["ChTrends"][i]
SetValue(i, LineNumber, TrLine)
end
if i > BPntIdx then
TrLine[i]=nil
SetValue(i, LineNumber, TrLine[i])
end
end
return TrLine
end
Здравствуйте форумчане и разработчики. Прошу пояснить такой вопрос - как работает функция OnCalculate(). Я кодом Lua выбрасываю на график две метки, затем перемещаю их руками и затем провожу расчет индикатора на интервале между метками. Ожидал, что все линии индикатора изменятся после расчета. Но...алгоритм работы функции OnCalculate() не соответствует моим ожиданиям. На скрине ниже все видно - сначала выводятся рассчитанные значения до перемещения меток и только на последней свечке (по приходу тиков) выводятся рассчитанные значения. Это так задумано изначально?
Прошу разработчиков рассмотреть вопрос по добавлению следующих изменений в клиентский терминал: 1. На вкладке "дополнительно" окна редактирования инструмента в окно идентификатора автоматически прописывать название окна графика для инструмента верхнего слоя, естественно с возможностью редактирования и считывания прописанного по умолчанию значения строки из этого окна в программном коде индикатора. Это существенно облегчит написание кода индикаторов. В этом случае при обращении к функциям getNumCandles() и getCandlesByIndex() не придется лезть в программный код индикатора для внесения вручную изменений ID инструмента в секции Settings при смене графика инструмента, достаточно будет считать значение по умолчанию. Я, например, не использую более одного графика цены в каждом окне и меня сильно напрягает, что при смене окна и инструмента нужно лезть в программный код индикатора и вносить правки вручную. Сделать же это после присоединения индикатора к графику невозможно, поскольку указанные выше функции я использую в секции Init() и к моменту запуска индикатора эта секция уже должна получить все параметры. Для тех же, кому нужно использовать более одного графика инструмента в окне, останется возможность редактирования значения по умолчанию ручками.
2. Создать в интерфейсе кнопку с программным кодом, эмулирующим выдачу тика цены для любого инструмента. Это нужно для отладки программного кода индикаторов без подключения к серверу. Особенно это актуально в часы отсутствия торгов.
Здравствуйте форумчане. В коде ниже функция GETLABLEPOSIXTIME внутри себя рассчитывается корректно (должна возвращать время метки в формате posix, в сообщении его и выводит), но при обращении к ней в функции IsLabelChange переменная posixNewLblTime получает значение nil. Второй день бьюсь, не пойму в чем косяк. Что не так делаю?
--глобальные переменные -- Внимание, название всех параметров меток должны писаться большими буквами 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={}
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); --message("Initsplace "..tostring(tposixOldLabelTime["splace"])); --message("Initsplace "..tostring(Label_Id["splace"]));
CandleIndex = NmbrOfCandles-Settings.fplace; tposixOldLabelTime["fplace"], Label_Id["fplace"] = PUTLABEL(CandleIndex); --message("Initfplace "..tostring(tposixOldLabelTime["fplace"])); --message("Initfplace "..tostring(Label_Id["fplace"])); --берем из таблицы только время-дату свечи 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 1
end
function OnCalculate(index)
local LblIdF = 0 local LblIdS = 0 local posixNewLblTimeF = 0 local posixOldLblTimeF = 0 local posixNewLblTimeS = 0 local posixOldLblTimeS = 0 local indput local IndLines={} local ChTrend local flagIndChange=false--false-перестроить индикатор, true - не перестраивать
---[[ --если флаг перемещения метки не установлен if flagLblModify==false then --проверяем перемещалась ли первая метка LblIdF=IsLabelChange("fplace"); --проверяем вторую метку LblIdS=IsLabelChange("splace"); --если индикатор существует, то выходим без расчетов, возвращаем массив линий if flagIndExist==true then flagIndChange=true; --иначе строим индикатор, выставляем его флаг, возвращаем массив линий else flagIndChange=false; flagIndExist=true; end --если метка перемещалась flagLblModify==true else --строим индикатор, выставляем флаг индикатора, --сбрасываем флаг метки, возвращаем индикатор flagIndChange=false; flagIndExist=true; flagLblModify=false end --рассчитываем индикатор или выводим линии без расчета --ChTrend=PUTINDICATOR(LblIdF,LblIdS,flagIndChange) --]] return ChTrend end
function OnDestroy ()
local tmp tmp=DelAllLabels(Settings.AssetID) end
function IsLabelChange(place) --функция принимает индекс массива Label_Id["строка"] --устанавливает глобальные флаги и --записывает posix-время в глобальную таблицу tposixOldLabelTime --возврашает Id метки local LblId = 0 local posixNewLblTime = 0 local posixOldLblTime = 0
--проверяем перемещалась ли метка --считываем Id метки из массива LblId = Label_Id[place]; message(tostring(LblId).." IsLabelChange_LblId") --считываем posix-время для этой метки posixOldLblTime = tposixOldLabelTime[place]; message(tostring(posixOldLblTime).." IsLabelChange_posixOldLblTime"); --преобразуем время метки с чарта в posix-формат posixNewLblTime = GETLABLEPOSIXTIME (LblId); message(tostring(posixNewLblTimeF).." IsLabelChange_posixNewLblTime") ---[[ --если время не совпадает, выставляем флаги отсутствия индикатора и модификации метки if posixNewLblTime ~= nil then if posixOldLblTime ~= posixNewLblTime then --выставляем флаги --метка перемещена flagLblModify=true; --индикатор не построен flagIndExist=false; --изменяем время метки в массиве tposixOldLabelTime[place] = posixNewLblTime; --message(tostring(posixOldLblTime).." IsLabelChange_posixOldLblTime") --message(tostring(posixNewLblTimeF).." IsLabelChange_posixNewLblTime") --message("IsLabelChange_LblId "..tostring(LblId)); end end return LblId end
FTEXT = function (V) --функция подставляет нули при их отсутствии на первой позиции даты-времени V=tostring (V) if string.len (V) == 1 then V = "0".. V end return V end
PUTLABEL = function (index) --[[функция для установки метки на чарт по индексу принимает индекс свечи возвращает время метки в posix-формате и Id метки
входные параметры: -индекс свечи -строка с названием точки для индексации массива установленных меток --]] local Date=""--дата свечки local Time=""--время свечки local Yvalue=0 LabelId=0 --message ("PUTLABELindex.."..tostring(index)); --дата и время свечи Date=t[index].datetime.year..FTEXT(t[index].datetime.month)..FTEXT(t[index].datetime.day); --дата
--привязка к оси У 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-формате local id--Id метки local NewLbLParam = {}--структура параметров метки local LabelTime = ""--строка с данными даты-времени метки local dt={}--структура в формате datetime local osTime=0 ---[[ id = LabelId; --message("GETLABLEPOSIXTIME_LabelId "..tostring(id)); --получаем таблицу с параметрами метки (в нижнем регистре в формате строки) NewLbLParam = GetLabelParams(Settings.AssetID, id); --message("GETLABLEPOSIXTIME_LbLParam.date "..tostring(NewLbLParam.date)); --message("GETLABLEPOSIXTIME_LbLParam.time "..tostring(NewLbLParam.time)); --преобразуем в формат 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)") --[[ message("GETLABLEPOSIXTIME_dt.year "..tostring(dt.year)); message("GETLABLEPOSIXTIME_dt.month "..tostring(dt.month)); message("GETLABLEPOSIXTIME_dt.day "..tostring(dt.day)); message("GETLABLEPOSIXTIME_dt.hour "..tostring(dt.hour)); message("GETLABLEPOSIXTIME_dt.min "..tostring(dt.min)); message("GETLABLEPOSIXTIME_dt.sec "..tostring(dt.sec)); message("GETLABLEPOSIXTIME_os.time "..tostring(os.time (dt))); --]] --преобразуем в формат POSIX osTime = os.time (dt); message("GETLABLEPOSIXTIME_os.time "..tostring(osTime)); return osTime;
end
function PUTINDICATOR(LblId1,LblId2,boolIndExist)
local i local j local k local TrndH=0 local TrndL=0 local h local l local CndlIdx1=0 local CndlIdx2=0 local ABIdx={} local IntervalCndlNmbr=0 local koef local VChLines={} local VChTrend={} local VChUp={} local VChDn={} local VChUpMax local VChDnMin 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 VChTrnd=0
Здравствуйте. Задача вкратце: Нужно выбросить две метки на чарт для их интерактивного использования - задания диапазона вычисления индикатора. На данном этапе метки выводятся, я считываю их параметры. Для упрощения нахождения положения метки на чарте я решил исходную таблицу всех свечек чарта переиндексировать по времени в формате POSIX, тогда, получив новое местоположение метки можно напрямую из этой таблицы получить индекс свечи, к которой привязана метка. Переиндексировать таблицу решил в Init(), тк.к это нужно делать всего один раз при присоединении индикатора к графику. Засада вот в чем - переиндексация производится в цикле, внутри цикла все работает как надо. Но при выходе из цикла значения таблицы nil. В чем косяк?
Нужная таблица в коде называется tposixByTime.
Код
Settings={
Name = "2_ind",--имя индикатора
AssetID = "sber",--идентификатор иструмента
LabelName = "D:\метка.bmp",--имя файла метки
stopper = false,--обработка на каждом тике
complect = 0,
-- начальное местоположение меток
fplace = 40,
splace = 5,
Yvalue = 0,
line=
{
{
Name = "High",
Type =TYPE_LINE,
Width = 1,
Color = RGB(120,90, 140)
}--,
--{
--Name = "Low",
--Type =TYPE_LINE,
--Width = 1,
--Color = RGB(120,90,140)
--},
--{
--Name = "Close",
--Type =TYPE_LINE,
-- Width = 1,
--Color = RGB(120,90, 140)
--},
--{
--Name = "Open",
--Type =TYPE_LINE,
--Width = 1,
--Color = RGB(120,90,140)
--}
--}
}
}
--глобальные переменные
-- Внимание, название всех параметров меток должны писаться большими буквами
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={}
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; --путь к файлу метки
--номер предпоследней справа свечи на графике. Нумерация начинается с нуля.
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["spl"] = PUTLABEL(CandleIndex);
--message("Initsplace "..tostring(tposixOldLabelTime["splace"]));
--message("Initsplace "..tostring(Label_Id["spl"]));
CandleIndex = NmbrOfCandles-Settings.fplace;
tposixOldLabelTime["fplace"], Label_Id["fpl"] = PUTLABEL(CandleIndex);
--message("Initfplace "..tostring(tposixOldLabelTime["fplace"]));
--message("Initfplace "..tostring(Label_Id["fpl"]));
--берем из таблицы только время-дату свечи
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 1
end