Избранное трейдера DvF
Приветствую всех!
Сам я не программист, но решил написать скрипт, который будет выводить табличку по доходности синтетических облигаций (покупка акций/продажа фьючерса). Идея в получении дохода от контанго. Скрипт работает и табличка выводится, но через некоторое время появляется ошибка о недостатке памяти.
Подскажите, что я сделал не так?

<code>-- ©2022 by Aleksey Manin
-- Таблица расчета доходности синтетической облигации
-- Какие инструменты(тикеры) отслеживаем. Таблица пар тикер - площадка
tickers = {GAZP = {GAZP = "TQBR", GZZ2 = "SPBFUT"},
SBER = {SBER = "TQBR", SRZ2 = "SPBFUT"},
PLZL = {PLZL = "TQBR", PZZ2 = "SPBFUT"},
GMKN = {GMKN = "TQBR", GKZ2 = "SPBFUT"},
LKOH = {LKOH = "TQBR", LKZ2 = "SPBFUT"},
AFLT = {AFLT = "TQBR", AFZ2 = "SPBFUT"},
NVTK = {NVTK = "TQBR", NKZ2 = "SPBFUT"},
YNDX = {YNDX = "TQBR", YNZ2 = "SPBFUT"},
--MOEX = {MOEX = "TQBR", MXZ2 = "SPBFUT"},
ALRS = {ALRS = "TQBR", ALZ2 = "SPBFUT"},
VTBR = {VTBR = "TQBR", VBZ2 = "SPBFUT"},
SNGS = {SNGS = "TQBR", SNZ2 = "SPBFUT"},
MGNT = {MGNT = "TQBR", MNZ2 = "SPBFUT"},
NLMK = {NLMK = "TQBR", NMZ2 = "SPBFUT"},
MTSS = {MTSS = "TQBR", MTZ2 = "SPBFUT"},
ROSN = {ROSN = "TQBR", RNZ2 = "SPBFUT"}}
rows = {} -- Список строк в таблице по количеству тикеров
oblig_t = AllocTable() -- Указатель на саму таблицу
stopped = false -- Остановка скрипта
-- Функция вызывается перед вызовом main
function OnInit(path)
AddColumn(oblig_t, 0, "Ticker_BA", true, QTABLE_STRING_TYPE, 8) -- "Ticker"- название первого столбца в таблице
AddColumn(oblig_t, 1, "Lot_BA", true, QTABLE_INT_TYPE, 8) --
AddColumn(oblig_t, 2, "Ask_BA", true, QTABLE_DOUBLE_TYPE, 10) --
AddColumn(oblig_t, 3, "Ticker_F", true, QTABLE_STRING_TYPE, 10) --
AddColumn(oblig_t, 4, "Lot_F", true, QTABLE_INT_TYPE, 8) --
AddColumn(oblig_t, 5, "Bid_F", true, QTABLE_DOUBLE_TYPE, 10) --
AddColumn(oblig_t, 6, "Day_EXP", true, QTABLE_INT_TYPE, 10) --
AddColumn(oblig_t, 7, "Date_EXP", true, QTABLE_DATE_TYPE, 15) --
AddColumn(oblig_t, 8, "Dohod%", true, QTABLE_DOUBLE_TYPE, 10) --
AddColumn(oblig_t, 9, "Dohod", true, QTABLE_DOUBLE_TYPE, 10) --
CreateWindow(oblig_t) -- Создание окна таблицы
SetWindowCaption(oblig_t, "Синтетическая облигация") -- Даем название таблице
for ticker, two in pairs(tickers) do -- Перебираем пары БА-Фьючерс
rows[ticker] = InsertRow(oblig_t, -1) -- Заносим тикер в список строк
end
end
function Run()
for ticker, two in pairs(tickers) do -- Перебираем пары БА-Фьючерс
ask_ba = 0.0
bid_f = 0.0
lot_f = 0
for ticker_two, board in pairs(two) do -- Перебираем Тикеры внутри пары БА-Фьючерс
if ticker == ticker_two then -- Если Тикер БА
SetCell(oblig_t, rows[ticker], 0, ticker_two) -- Заполняем ячейке Тикера БА
SetCell(oblig_t, rows[ticker], 1, -- Заполняем лот БА
string.format("%u", getParamEx (board, ticker_two, "LOTSIZE").param_value))
ask_ba = getParamEx (board, ticker_two, "OFFER").param_value
SetCell(oblig_t, rows[ticker], 2, string.format("%.2f", ask_ba)) -- Аск БА
else -- Если Тикер фьючерса
SetCell(oblig_t, rows[ticker], 3, ticker_two) -- Заполняем ячейку Тикера фьючерса
lot_f = getParamEx (board, ticker_two, "LOTSIZE").param_value
SetCell(oblig_t, rows[ticker], 4, string.format("%u", lot_f))
bid_f = getParamEx (board, ticker_two, "BID").param_value
SetCell(oblig_t, rows[ticker], 5, string.format("%u", bid_f))
day_exp = getParamEx (board, ticker_two, "DAYS_TO_MAT_DATE").param_value
SetCell(oblig_t, rows[ticker], 6, string.format("%u", day_exp))
SetCell(oblig_t, rows[ticker], 7,
string.format("%u", getParamEx (board, ticker_two, "MAT_DATE").param_value))
--message('Дата:'..getParamEx (board, ticker_two, "MAT_DATE").param_type)
end
end
sum_ba = ask_ba * lot_f
--message('Тикер:'..ticker..' lot_f:'..lot_f..' sum_ba:'..sum_ba)
sum_year = (bid_f - sum_ba) / day_exp * 365
percent = sum_year * 100 / sum_ba
SetCell(oblig_t, rows[ticker], 8, string.format("%.2f", percent))
SetCell(oblig_t, rows[ticker], 9, string.format("%.2f", bid_f - sum_ba))
end
end
-- Функция вызывается перед остановкой скрипта
function OnStop(signal) stopped = true end
-- Функция вызывается перед закрытием квика
function OnClose() stopped = true end;
-- Основная функция выполнения скрипта
function main()
while not stopped do
Run()
sleep(10)
end
end</code>'========= Перемещение заявки
FUNC MORDER(FTRID,FON,FONQ,FONP)
NEW_GLOBAL("TRANS_PARAMS", "")
NEW_GLOBAL("TRANS_RESULT", "")
TRANS_PARAMS = ""
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "TRANS_ID",FTRID)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "ACTION", "MOVE_ORDERS")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "MODE",0)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "CLASSCODE", "SPBFUT")
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "SECCODE", INSTRUMENT)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "ACCOUNT", ACCOUNT)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "FIRST_ORDER_NUMBER",FON)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "FIRST_ORDER_NEW_QUANTITY",FONQ)
TRANS_PARAMS = SET_VALUE (TRANS_PARAMS, "FIRST_ORDER_NEW_PRICE",FONP)
TRANS_RESULT = SEND_TRANSACTION (300, TRANS_PARAMS)
RESULT=GET_VALUE(TRANS_RESULT, "DESCRIPTION")
MESSAGE (RESULT,1)
END FUNC
'========= Операция перестановки
IF MPRICE < LOW
MORDER(MTRANS_ID,MNUMBER,MBALANCE,LOW+STEP)
END IF
'======================================
'MTRANS_ID - номер заявки на бирже
'MNUMBER - номер заявки в таблицах
'MBALANCE - объем
'LOW - минимум свечи
'STEP - отступ для лимитки
'MPRICE - последняя цена

--[[
индикатор отрисовки наклонных уровней
Параметры:
delta - чувствиельность индикатора на волатильность в %
rep - количество повторений поиска конечного уровня
shif - сдвиг влево конечного бара
wt - признак наличия весового коэффициента =0 - без весового =1,2.. - свосовыми коф. чем ближе к концу тем больше
show=1,
--]]
Settings=
{
Name = "AT-obl_can", -- название индикатора
delta=2.0, -- параметр индикатора
rep=10,
shif=0,
wt=1,
--hl=1,
show=1,
line=
{
{
Name = "ln1",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255, 0, 0)
},
{
Name = "ln2",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255, 0, 0)
}
}
}
function Init()
vMin = 0
vMax = 0
vMinindex = 0
vMaxindex = 0
voldMinindex = 0
voldMaxindex = 0
return 2
end
function OnCalculate(index)
rep = Settings.rep
shif = Settings.shif
wt = Settings.wt
--hl = Settings.hl
sz = Size()-shif
if Settings.show == 1 then
if index <= sz then
if index <= 1 then
vMin = C(index)
vMax = C(index)
vMinindex = index
vMaxindex = index
voldMinindex = index
voldMaxindex = index
v = C(index)
else
if voldMaxindex >= voldMinindex then
if vMin~=nil and C(index)~=nil then
if C(index) > (1 + Settings.delta/100)*vMin then
vMin = C(index)
vMax = C(index)
vMaxindex = index
voldMinindex = vMinindex
vFrom = vMinindex
else
if vMin > C(index) then
vMin = C(index)
vMinindex = index
vFrom = voldMaxindex
else
vFrom = vMinindex
end
end
end
else
if voldMaxindex <= voldMinindex then
if vMax~=nil and C(index)~=nil then
if C(index) < (1 - Settings.delta/100)*vMax then
vMax = C(index)
vMin = C(index)
vMinindex = index
voldMaxindex = vMaxindex
vFrom = vMaxindex
else
if vMax < C(index) then
vMax = C(index)
vMaxindex = index
vFrom = voldMinindex
else
vFrom = vMaxindex
end
end
end
end
end
--if vFrom~=nil then
--[[
for i = vFrom, index do
k = (C(index)- C(vFrom))/(index- vFrom);
v = i*k + C(index) - index*k
SetValue(i, 1, v)
end --]]
--end
if index == sz then
for k = 1, 2 do
vf = 1
vs = 0
if k == 1 then
if vMinindex < vMaxindex then
vf = vMinindex
vs = vMaxindex
up = 0
elseif vMinindex > vMaxindex then
vs = vMinindex
vf = vMaxindex
up = 1
end
elseif k == 2 then
if voldMinindex < voldMaxindex then
vf = voldMinindex
vs = voldMaxindex
up = 0
elseif voldMinindex > voldMaxindex then
vs = voldMinindex
vf = voldMaxindex
up = 1
end
end
n = 0
xy = 0
x = 0
y = 0
xx = 0
m = 0
for i = vf, vs do
if C(i) ~= nil then
m = m +1
n = n + 1*(1+wt*m)
xy = xy + i*C(i)*(1+wt*m)
x = x + i*(1+wt*m)
y = y + C(i)*(1+wt*m)
xx = xx + i*i*(1+wt*m)
end
end
if (n*xx - x*x) ~= 0 and n ~= 0 then
a = (n*xy - x*y)/(n*xx - x*x)
b = (y - a*x)/n
for j = 1, rep do
n = 0
xy = 0
x = 0
y = 0
xx = 0
m = 0
for i = vf, vs do
if C(i) ~= nil then
v = a*i + b
clc = 0
if up == 1 and C(i) >= v then
clc = 1
end
if up == 0 and C(i) <= v then
clc = 1
end
if clc == 1 then
m = m + 1
n = n + 1*(1+wt*m)
--[[
if up == 1 and hl == 1 then
xy = xy + i*H(i)*(1+wt*m)
elseif up == 0 and hl == 1 then
xy = xy + i*L(i)*(1+wt*m)
else --]]
xy = xy + i*C(i)*(1+wt*m)
-- end
x = x + i*(1+wt*m)
--[[
if up == 1 and hl == 1 then
y = y + H(i)*(1+wt*m)
elseif up == 0 and hl == 1 then
y = y + L(i)*(1+wt*m)
else --]]
y = y + C(i)*(1+wt*m)
-- end
xx = xx + i*i*(1+wt*m)
end
end
end --[[--]]
if (n*xx - x*x) ~= 0 and n ~= 0 and n >= 2 then
a = (n*xy - x*y)/(n*xx - x*x)
b = (y - a*x)/n --[[ --]]
end
end
for i = vf, sz do
v = a*i + b
if up == 1 and v >= C(vs) or up == 0 and v <= C(vs) then
SetValue(i, k, v)
end
end
end
end
end
end
end
end
end
Settings=
{
Name = "AT-obl_can", -- название индикатора
delta=2.0, -- параметр индикатора
rep=5,
shif=0,
wt=1,
line=
{
{
Name = "ln1",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255, 0, 0)
},
{
Name = "ln2",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255, 0, 0)
}
}
}
function Init()
vMin = 0
vMax = 0
vMinindex = 0
vMaxindex = 0
voldMinindex = 0
voldMaxindex = 0
return 2
end
function OnCalculate(index)
rep = Settings.rep
shif = Settings.shif
wt = Settings.wt
sz = Size()-shif
if index <= sz then
if index <= 1 then
vMin = C(index)
vMax = C(index)
vMinindex = index
vMaxindex = index
voldMinindex = index
voldMaxindex = index
v = C(index)
else
if voldMaxindex >= voldMinindex then
--if vMin~=nil then
if C(index) > (1 + Settings.delta/100)*vMin then
vMin = C(index)
vMax = C(index)
vMaxindex = index
voldMinindex = vMinindex
vFrom = vMinindex
else
if vMin > C(index) then
vMin = C(index)
vMinindex = index
vFrom = voldMaxindex
else
vFrom = vMinindex
end
end
--end
else
if voldMaxindex <= voldMinindex then
--if vMax~=nil then
if C(index) < (1 - Settings.delta/100)*vMax then
vMax = C(index)
vMin = C(index)
vMinindex = index
voldMaxindex = vMaxindex
vFrom = vMaxindex
else
if vMax < C(index) then
vMax = C(index)
vMaxindex = index
vFrom = voldMinindex
else
vFrom = vMaxindex
end
end
--end
end
end
--if vFrom~=nil then
--[[
for i = vFrom, index do
k = (C(index)- C(vFrom))/(index- vFrom);
v = i*k + C(index) - index*k
SetValue(i, 1, v)
end --]]
--end
if index == sz then
for k = 1, 2 do
vf = 1
vs = 0
if k == 1 then
if vMinindex < vMaxindex then
vf = vMinindex
vs = vMaxindex
up = 0
elseif vMinindex > vMaxindex then
vs = vMinindex
vf = vMaxindex
up = 1
end
elseif k == 2 then
if voldMinindex < voldMaxindex then
vf = voldMinindex
vs = voldMaxindex
up = 0
elseif voldMinindex > voldMaxindex then
vs = voldMinindex
vf = voldMaxindex
up = 1
end
end
n = 0
xy = 0
x = 0
y = 0
xx = 0
m = 0
for i = vf, vs do
m = m +1
n = n + 1*(1+wt*m)
xy = xy + i*C(i)*(1+wt*m)
x = x + i*(1+wt*m)
y = y + C(i)*(1+wt*m)
xx = xx + i*i*(1+wt*m)
end
if (n*xx - x*x) ~= 0 and n ~= 0 then
a = (n*xy - x*y)/(n*xx - x*x)
b = (y - a*x)/n
for j = 1, rep do
n = 0
xy = 0
x = 0
y = 0
xx = 0
m = 0
for i = vf, vs do
v = a*i + b
clc = 0
if up == 1 and C(i) > v then
clc = 1
end
if up == 0 and C(i) < v then
clc = 1
end
if clc == 1 then
m = m + 1
n = n + 1*(1+wt*m)
xy = xy + i*C(i)*(1+wt*m)
x = x + i*(1+wt*m)
y = y + C(i)*(1+wt*m)
xx = xx + i*i*(1+wt*m)
end
end --[[--]]
if (n*xx - x*x) ~= 0 and n ~= 0 and n > 2 then
a = (n*xy - x*y)/(n*xx - x*x)
b = (y - a*x)/n --[[ --]]
end
end
for i = vf, sz do
v = a*i + b
if up == 1 and v >= C(vs) or up == 0 and v <= C(vs) then
SetValue(i, k, v)
end
end
end
end
end
end
end
endДаже цитируются «умные» книги о том, что спрос на путы больше из-за наличия хэджеров.
На самом деле все проще и иначе.

--[[
EMA template
--]]
Settings=
{
Name = "EMA", -- indicator name
ln=20, -- period
line=
{
{
Name = "EMA",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0,255)
}
}
}
function Init()
ema = {}
return 1
end
function OnCalculate(index)
ln = Settings.ln
if index-1 < 1 then
ema[index] = C(index)
else
ema[index] = (ema[index-1]*(ln-1) + C(index))/ln
end
return ema[index]
end