Иногда бывает необходимым проанализировать не отдельную бумагу, а рынок в целом.
Кто-то смотрит для этого индексы, кто-то различные сантименты, а мне удобнее проводить анализ по динамике всех бумаг (сколько на дату эмитентов в совокупности растет, сколько бумаг выше своих месячных, квартальных или годовых значений и пр.). Каждый по своему может это использовать далее (как общий фильтр принятия решения для входа в сделку, для составления своих индексов, для анализа динамики своего портфеля – особенно если счетов несколько у разных брокеров и пр.).
Получить котировки на конкретную дату можно через сайт Московской Биржи (https://www.moex.com/ru/marketdata/#/mode=groups&group=4&collection=3&boardgroup=57&data_type=history&date=2023-06-27&category=main), но это не очень удобно т.к. требуется либо парсить (для чего нужен уже нетривиальный уровень в программировании), либо вручную выдергивать эту страницу, например в excel (тем, кто попробует выгрузить всё по кнопкам скачать Excel / CSV биржа предложит воспользоваться платной подпиской для получения данных).
20220915,090000,61420,61497,61406,61464,241
20220915,090100,61460,61476,61420,61451,160
20220915,090200,61444,61489,61436,61479,185
Осмелюсь предположить, что эти строки ты заливаешь в массив с помощью string.match. Это готовый парсер строки с разделителем. Работает достаточно шустро. Я на нем сидел пару лет.
Когда данных не много, такой метод загрузки не напрягает. Но когда за день 20-30 раз загружаешь сотни тысяч или миллион строк, то потери времени становятся невыносимыми.
Стал искать способ ускорить этот процесс. И он таки нашелся. Выяснил следующее:
Если строки в файле истории сконвертировать в такой вид (делается 1 раз):
table.insert(MyTable,{«20220915»,«090000»,61420,61497,61406,61464,241})
table.insert(MyTable,{«20220915»,«090100»,61460,61476,61420,61451,160})
table.insert(MyTable,{«20220915»,«090200»,61444,61489,61436,61479,185})
Settings =
{
Name = «DHLM»,
line =
{
{
Name = «High»,
Color = RGB(0,200,64),
Type = TYPET_BAR,
Width = 1
},
{
Name = «Low»,
Color = RGB(200,0,64),
Type = TYPET_BAR,
Width = 1
},
{
Name = «Median»,
Color = RGB(0,64,200),
Type = TYPET_BAR,
Width = 1
}
}
}
local hlm = {}
local math_max = math.max
local math_min = math.minfunction Init()
return #Settings.line
end
function OnCalculate(index)
local dt = T(index)if O(index) then
if dt.day ~= hlm.day or
dt.month ~= hlm.month or
dt.year ~= hlm.year then
hlm.year = dt.year
hlm.day = dt.day
hlm.month = dt.month
hlm.high = H(index)
hlm.low = L(index)
else
hlm.high = math_max(hlm.high,H(index))
hlm.low = math_min(hlm.low,L(index))
hlm.median = (hlm.high + hlm.low)/2
end
end
return hlm.high,hlm.low,hlm.median
end
function round(number, znaq) -- функция округления числа num до знаков znaq local num = tonumber(number) local idp = tonumber(znaq) if num then local mult = 10 ^ (idp or 0) if num >= 0 then return math.floor(num * mult + 0.5) / mult else return math.ceil(num * mult - 0.5) / mult end else return num end end
function DaysToDie(class_code, sec_code) -- Получаем количество дней до погашения инструмента,<br />-- class_code - для фьючерсов SPBFUT<br />-- sec_code - код инструмента SiZ2, BRZ2, CRZ2 и т.д. -- если < 4, просим заменить инструмент -- для работы необходима ф-ция round (округляем до целого числа) -- is_run - глобальный флаг работы робота - false = отключаемся. --- local daysToDie = 0 -- количество дней до погашения инструмента ----- получаем количество дней до погашения, если < 4, рекомендуем перейти на новый инструмент ---------- daysToDie = round(getParamEx(class_code, sec_code, "DAYS_TO_MAT_DATE").param_value, 0) if daysToDie <= 4 and daysToDie > 0 then message("Количество дней до погашения инструмента " .. SEC_CODE .. " равно " .. tostring(daysToDie) .. ". Необходимо заменить инструмент в настройках робота") elseif daysToDie == 0 or daysToDie == nil then message("Инструмент больше не торгуется") is_run = false end return daysToDie end
function main() local Trades = {} local comission = 0 SearchItems('trades', 0, getNumberOf('trades')-1, function (class_code, trade_num, flags, exchange_comission) if class_code == 'SPBFUT' or class_code == 'SPBOPT' then -- Учитываем только сделки на срочной секции comission = comission + exchange_comission local t = {flags & 0x4, exchange_comission} if Trades[class_code] then Trades[class_code][trade_num] = t else Trades[class_code] = {[trade_num] = t} end end return false end, 'class_code,trade_num,flags,exchange_comission') local total = 0 local maker = 0 local taker = 0 local comission2 = 0 SearchItems('all_trades', 0, getNumberOf('all_trades')-1, function (class_code, trade_num, flags, sec_code) if Trades[class_code] then local t = Trades[class_code][trade_num] if t then total = total + 1 if flags & 0x1 ~= 0 then if t[1] == 0 then maker = maker + 1 else taker = taker + 1 comission2 = comission2 + t[2] end elseif flags & 0x2 ~= 0 then if t[1] == 0 then taker = taker + 1 comission2 = comission2 + t[2] else maker = maker + 1 end else comission2 = comission2 + t[2] end end end return false end, 'class_code,trade_num,flags,sec_code') message(string.format('total: %u\nmaker: %u\ntaker: %u\n\ncomission\nсейчас: %.2f\nскальпинг: %.2f\nстанет: %.2f', total, maker, taker, comission, comission / 2, comission2 * 3)) end