pos1={} pos2={} for j=0,getNumberOf("DEPO_LIMITS")-1 do pos1[#pos1+1]=getItem("DEPO_LIMITS",j).sec_code pos2[#pos2+1]=getItem("DEPO_LIMITS",j).currentbal endПроблема такого варианта в том, что он показывает ненулевые значения в currentbal только для позиций, которые были открыты ранее (возможно, по которым прошло +2 дня). По позициям, которые были открыты сегодня, он точно показывает 0.
Пост немного не по теме трейдинга, скорее его надо задавать программистам, но среди трейдеров таких полно, может поделитесь опытом.
Многолетнее использование Lua в QUIK`е подтолкнуло к идее использовать скриптовый язык в других приложениях.
Из всего немногочисленного набора того, что есть для C# удалось найти:
— NLua — 18K скачиваний в NuGet
— LuaInterface -?
— NeoLua – 50k скачиваний в NuGet
— LuBox – 1k скачиваний в NuGet
Автор проекта LuaInterface давно не поддерживает проект и прямо говорит, что NLua успешно продолжает его дело.
NeoLua – наиболее популярен среди программистов в NuGet.
LuBox показался удобным и наиболее «молодым» проектом.
Кто-нибудь из смартлабовцев использовал какую-то из этих библиотек для встраивания Lua-скриптов? Поделитесь опытом использования: плюсы, минусы, баги.
require"QL" log = "sbrf.log" seccode = "SRM6" lots_in_trade = 80 accnt = "" better = -5 chart = "sberbankxxx" is_run = true prev_datetime = {} len = 100 basis = 9 k_bal = {0,1,2,3} sell = false buy = false id = 0 first = true function trade_signal(shift) number_of_candles = getNumCandles(chart) bars_temp,res,legend = getCandlesByIndex(chart,0,number_of_candles-2*len-shift,2*len) bars={} i=len j=2*len while i>=1 do if bars_temp[j-1].datetime.hour>=10 then sk=true if bars_temp[j-1].datetime.hour==18 and bars_temp[j-1].datetime.min==45 then sk=false end if sk then bars[i]=bars_temp[j-1] i=i-1 end end j=j-1 end t = len+1 do_sell = false do_buy = true value = 0 if do_sell then value = 1 end if do_buy then value = -1 end toLog(log,"value="..value.." on candle: "..bars[len].datetime.year.."-"..bars[len].datetime.month.."-"..bars[len].datetime.day.." "..bars[len].datetime.hour..":"..bars[len].datetime.min.." O="..bars[len].open.." H="..bars[len].high.." L="..bars[len].low.." C="..bars[len].close.." V="..bars[len].volume) return value end function mysplit(inputstr, sep) if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end function OnInit(path) log=getScriptPath()..'\\'..log toLog(log,"==========OnInit: START") toLog(log,"==========OnInit: FINISH") end function OnStop() is_run = false toLog(log,"==========OnStop: script finished manually") end function CheckBit(flags, bit) -- Проверяет, что переданные аргументы являются числами if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!"); end; if type(bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!"); end; local RevBitsStr = ""; -- Перевернутое (задом наперед) строковое представление двоичного представления переданного десятичного числа (flags) local Fmod = 0; -- Остаток от деления local Go = true; -- Флаг работы цикла while Go do Fmod = math.fmod(flags, 2); -- Остаток от деления flags = math.floor(flags/2); -- Оставляет для следующей итерации цикла только целую часть от деления RevBitsStr = RevBitsStr ..tostring(Fmod); -- Добавляет справа остаток от деления if flags == 0 then Go = false; end; -- Если был последний бит, завершает цикл end; -- Возвращает значение бита local Result = RevBitsStr :sub(bit+1,bit+1); if Result == "0" then return 0; elseif Result == "1" then return 1; else return nil; end; end; function killorders(ccode,scode) for i=0,getNumberOf("orders")-1,1 do local t=getItem("orders", i) if t ~= nil and type(t) == "table" then if( t.seccode == scode and CheckBit(t.flags, 0) == 1) then local transaction={ ["TRANS_ID"]=tostring(math.random(2000000000)), ["ACTION"]="KILL_ORDER", ["CLASSCODE"]=ccode, ["SECCODE"]=scode, ["ACCOUNT"] = accnt, ["ORDER_KEY"]=tostring(t.ordernum), } res=sendTransaction(transaction) end end end end function killstoporders(ccode,scode) for i=0,getNumberOf("stop_orders")-1,1 do local t=getItem("stop_orders", i) if t ~= nil and type(t) == "table" then if( t.seccode == scode and CheckBit(t.flags, 0) == 1) then local transaction={ ["TRANS_ID"]=tostring(math.random(2000000000)), ["ACTION"]="KILL_STOP_ORDER", ["CLASSCODE"]=ccode, ["SECCODE"]=scode, ["ACCOUNT"] = accnt, ["STOP_ORDER_KEY"]=tostring(t.ordernum), } res=sendTransaction(transaction) end end end end function main() toLog(log,"==========main: START") while is_run do if isConnected() == 1 then ss = getInfoParam("SERVERTIME") if string.len(ss) >= 5 then hh = mysplit(ss,":") str=hh[1]..hh[2] h = tonumber(str) if (h>=1000 and h<1400) or (h>=1405 and h<1845) or (h>=1905 and h<2350) then if first then for ti = 50,2,-1 do trade_signal(ti) end if buy and not sell then message(seccode.." Current state: green and buy",1) end if sell and not buy then message(seccode.." Current state: red and sell",1) end if buy and sell then message(seccode.." ERROR: green and red",1) end if not buy and not sell then message(seccode.." WARNING: nothing",1) end first = false end prev_candle = getPrevCandle(chart,0) if not isEqual(prev_candle.datetime,prev_datetime) then current_value = trade_signal(1) if current_value ~= 0 then optn = "B" if current_value==1 then optn = "S" end curvol=0 no=getNumberOf("FUTURES_CLIENT_HOLDING") if no>0 then for i=0,no-1,1 do im=getItem("FUTURES_CLIENT_HOLDING", i) if im.sec_code==seccode then curvol=im.totalnet end end end trvol = -current_value*lots_in_trade-curvol if trvol ~= 0 then killorders("SPBFUT",seccode) killstoporders("SPBFUT",seccode) f = io.open(getScriptPath().."\\sbrf2_pos.txt","r") sbrf2_pos=f:read("*n") f:close() f = io.open(getScriptPath().."\\sbrf3_pos.txt","r") sbrf3_pos=f:read("*n") f:close() pr,n,l = getCandlesByIndex ("futsber", 0, getNumCandles("futsber")-1, 1) local trans = { ["ACTION"] = "NEW_ORDER", ["CLASSCODE"] = "SPBFUT", ["SECCODE"] = seccode, ["ACCOUNT"] = accnt, ["OPERATION"] = optn, ["PRICE"] = toPrice(seccode,pr[0].close+current_value*better), ["QUANTITY"] = tostring(math.abs(curvol-sbrf2_pos-sbrf3_pos)), ["TRANS_ID"] = tostring(getTradeDate().month*100+getTradeDate().day+id) } id = id+1 --res = sendTransaction(trans) message(seccode.." Send : " .. res, 2) toLog(log,"Send: ".. res) for btr=0,200,5 do local trans = { ["ACTION"] = "NEW_STOP_ORDER", ["CLASSCODE"] = "SPBFUT", ["SECCODE"] = seccode, ["ACCOUNT"] = accnt, ["OPERATION"] = optn, ["PRICE"] = toPrice(seccode,pr[0].close-current_value*btr), ["STOPPRICE"] = toPrice(seccode,pr[0].close-current_value*(btr+better)), ["QUANTITY"] = tostring(6), ["TRANS_ID"] = tostring(getTradeDate().month*100+getTradeDate().day+id), ["EXPIRY_DATE"] = "GTC" } id = id+1 --res = sendTransaction(trans) message(seccode.." Send : " .. res, 2) toLog(log,"Send: ".. res) end if current_value == 1 then message(seccode..' RED: buy->sell',1) toLog(log,"RED signal") else message(seccode..' GREEN: sell->buy',1) toLog(log,"GREEN signal") end else if current_value == 1 then message(seccode..' RED: buy->sell',1) toLog(log,"RED signal, but nothing to do") else message(seccode..' GREEN: sell->buy',1) toLog(log,"GREEN signal, but nothing to do") end end else if buy and not sell then toLog(log,"Nothing to do. Current state: green and buy",1) end if sell and not buy then toLog(log,"Nothing to do. Current state: red and sell",1) end if buy and sell then toLog(log,"Nothing to do. ERROR: green and red",1) end if not buy and not sell then toLog(log,"Nothing to do. WARNING: nothing",1) end end prev_datetime = prev_candle.datetime end end end end sleep(5*1000) end toLog(log,"==========main: FINISH") end
По следам этого поста скрипт на qlua, называется «Светофор».
Суть скрипта- отслеживать дистанцию до «дна», которое представляет собой лои 2008 года+накопленная инфляция.
Подсветка строк:
зеленым- цена ниже уровня инфляции
желтым — до дна менее 50%
красным — до дна более 80%
В чем не смог разобраться:
как получить лой 2008 года по акции (вбито вручную)
как получить полное название компаний (вбито вручную)
как сортировать таблицу (ctrl+клик не помогает)
кто знает — подскажите!
Как это выглядит в Квике:
Бэктест на проливе 2014 года:
Код:
-- Обьявляем переменные sIsRun=true; sDate=0; sDno=0; sDistance=0; --Инфляция 2009-2016 sInflation=88.77; -- Массив с названием компаний aTickerName= {"Сбербанк", "Газпром", "Лукойл", "ГМКНорНик", "Система", "Аэрофлот", "Роснефть", "Транснф", "ФСК ЕС", "РусГидро", "СеверСталь", "Новатек", "Магнит", "Татнефть", "Сургнфтз-п", "М.видео", "ИнтерРАО", "НЛМК", "ММК", "Россети", "Ростел", "МТС", "Уркалий"} -- Массив с тикерами aTickerList = {"SBER", "GAZP", "LKOH", "GMKN", "AFKS", "AFLT", "ROSN", "TRNFP", "FEES", "HYDR", "CHMF", "NVTK", "MGNT", "TATN", "SNGSP", "MVID", "IRAO", "NLMK", "MAGN", "RSTI", "RTKM", "MTSS", "URKA"}; -- Массив с лоями 2008 года aTickerLow2008={14, 86, 740, 1228, 4.5, 20, 94, 6728, 0.054, 0.4, 80, 50, 312, 32.63, 5.16, 24, 0.54, 20, 4.5, 0.6, 14, 100, 25}; function main() -- Создает таблицу CreateTable(); -- Основной цикл while sIsRun do -- Дата и время sDate=getInfoParam('TRADEDATE').." "..getInfoParam('SERVERTIME'); -- Перебираем компании: k -порядковый номер, v - название тикера for k,v in pairs(aTickerList) do -- Крайняя цена sBID=tonumber(getParamEx("TQBR", v, "LAST").param_value); -- Расчетное дно sDno=math.floor(((aTickerLow2008[k]*(sInflation+100))/100)*100)/100; -- Сколько до дна % sDistance=math.floor((100-((sDno*100)/sBID))*100)/100; -- Вставляем данные в табличку SetCell(t_id, k, 0, tostring(sDate)); SetCell(t_id, k, 1, tostring(aTickerName[k])); SetCell(t_id, k, 2, tostring(v)); SetCell(t_id, k, 3, tostring(sBID)); SetCell(t_id, k, 4, tostring(sDno)); SetCell(t_id, k, 5, tostring(sDistance)); -- Раскрашиваем желтым if sDistance<50 then Yellow(k); end; -- Раскрашиваем красным if sDistance>80 then Red(k); end; -- Раскрашиваем зеленым if sDistance<0 then Green(k); end; end; -- Спим sleep(50000); 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, "Ticker", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 3, "BID", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 4, "Расчетное дно", true, QTABLE_INT_TYPE, 15); AddColumn(t_id, 5, "Сколько до дна (%)", true, QTABLE_INT_TYPE, 15); -- Создаем t = CreateWindow(t_id); -- Даем заголовок SetWindowCaption(t_id, "Компании"); -- Добавляет строку for k,v in pairs(aTickerList) do InsertRow(t_id, k); end end; --- Функции по раскраске ячеек таблицы function Red(col) for i=0, 5 do SetColor(t_id, col, i, RGB(255,168,164), RGB(0,0,0), RGB(255,168,164), RGB(0,0,0)); end; end; function Green(col) for i=0, 5 do SetColor(t_id, col, i, RGB(157,241,163), RGB(0,0,0), RGB(157,241,163), RGB(0,0,0)); end; end; function Yellow(col) for i=0, 5 do SetColor(t_id, col, i, RGB(249,247,172), RGB(0,0,0), RGB(249,247,172), RGB(0,0,0)); end; end; -- Функция вызывается когда пользователь останавливает скрипт function OnStop() sIsRun = false; end;
ссылка на скрипт
P.S.: не является рекомендацией к покупке/продаже акций, использование программы на ваш страх и риск.
Кросспост rffx.ru