В программе Lbot3D появилась реализация вычисления скользящего экстремума в конкретной стратегии при наличии позиции. Слово «конкретной» звучит потому, что этот самый экстремум можно использовать в других стратегиях из портфеля стратегий. Согласен, это нужно не всем. Скорее так: мало кому он нужен. Тем не менее, продолжу.
Допустим мы придумали стратегию на некотором активе, рассчитанную на тренд:
Покупаем на четверть портфеля. Если цена пошла против нас (пусть на 1%)- стопимся, но если в нашу сторону +1%, то в предположении, что мы тренде, выставим лимитированную заявку на покупку второй четверти на 0.5% ниже достигнутого экстремума: откат вероятен, и после того, как на откате вытряхнут часть пассажиров, (самых пугливых, самых недостойных :)), наш портфель зацепит еще несколько лотов и едем дальше, «на север». Но если первая четверть бумаг размещена в нашем портфеле на «долгосрок», то вторая четверть будет сразу же выставлена на продажу с профитом, например, в 1%.
В своей торговле применяю комбинации рыночных и лимитированных заявок, (методику описывал ранее, "Настоящая торговая стратегия." и "US500: Объемы больше, спреды уже!" ). Временами количество одновременно работающих стратегий зашкаливало за сотню и на некоторые из них не хватало денег под выставление заявок, они отключались, иногда ломая логику работы связанных с ней стратегий. В QUIK в таблице «Состояние счета» считается цифра — «Свободно» — свободные средства под заявки, но сходу вытащить ее из Lua у меня не получилось. И пришлось вписать расчет этой величины в робота.
Сегодня предлагаю вашему вниманию доработанный скрипт Fn044.lua (https://yadi.sk/d/O-6JzZdXkOxyow)
в котором реализован расчет свободных средств для заявок на ФОРТС с учетом имеющихся контрактов и заявок.
Один в один вывести не получилось, как смог.
As is, и все такое!
--переменные keyRateCB = 7.5 classCode = "TQOB" function CreateTable() t_id = AllocTable() AddColumn(t_id, 0, "Бумага", true, QTABLE_STRING_TYPE, 15) AddColumn(t_id, 1, "Цена", true, QTABLE_DOUBLE_TYPE, 15) AddColumn(t_id, 2, "Доходность, %", true, QTABLE_DOUBLE_TYPE, 15) AddColumn(t_id, 3, "Дюрация, лет", true, QTABLE_DOUBLE_TYPE, 15) AddColumn(t_id, 4, "Купон, %", true, QTABLE_DOUBLE_TYPE, 15) AddColumn(t_id, 5, "Премия к ЦБ, бп", true, QTABLE_INT_TYPE, 15) AddColumn(t_id, 6, "Погашение", true, QTABLE_STRING_TYPE, 15) t = CreateWindow(t_id) SetWindowCaption(t_id, "ОФЗ") end function string.split(str, sep) local fields = {} str:gsub(string.format("([^%s]+)", sep), function(f_c) fields[#fields + 1] = f_c end) return fields end function getParamNumber(code, param) return tonumber(getParamEx(classCode, code, param).param_value) end function formatData(prm) return string.format("%02d.%02d.%04d", prm%100, (prm%10000)/100, prm/10000) end CreateTable() arr = {} sec_list = getClassSecurities(classCode) sec_listTable = string.split(sec_list, ',') j = 0 for i = 1, #sec_listTable do secCode = sec_listTable[i] securityInfo = getSecurityInfo(classCode, secCode) short_name = securityInfo.short_name if short_name:find("ОФЗ 26") ~= nil then j = j + 1 r = {} r["short_name"] = short_name r["price"] = getParamNumber(securityInfo.code, "PREVPRICE") r["yield"] = getParamNumber(securityInfo.code, "YIELD") r["duration"] = getParamNumber(securityInfo.code, "DURATION")/365 couponvalue = getParamNumber(securityInfo.code, "COUPONVALUE") couponperiod = getParamNumber(securityInfo.code, "COUPONPERIOD") r["coupon"] = ((365/couponperiod) * couponvalue)/10 r["bonus"] = (r["yield"] - keyRateCB)*100 r["mat_date"] = getParamNumber(securityInfo.code, "MAT_DATE") table.insert(arr, j, r) end end table.sort(arr, function(a,b) return a["duration"] < b["duration"] end) for j = 1, #arr do row = InsertRow(t_id, -1) SetCell(t_id, row, 0, arr[j]["short_name"]) price = arr[j]["price"] SetCell(t_id, row, 1, string.format("%.2f", price), price) yield = arr[j]["yield"] SetCell(t_id, row, 2, string.format("%.2f", yield), yield) duration = arr[j]["duration"] SetCell(t_id, row, 3, string.format("%.2f", duration), duration) coupon = arr[j]["coupon"] SetCell(t_id, row, 4, string.format("%.2f", coupon), coupon) bonus = arr[j]["bonus"] SetCell(t_id, row, 5, string.format("%.0f", bonus), bonus) mat_date = arr[j]["mat_date"] SetCell(t_id, row, 6, formatData(mat_date), mat_date) end
-- fn044set.lua расчет стоимости фьючерсных контрактов в портфеле относительно депозита -- © smart-lab.ru/profile/xxm 08.10.2018 -- торговый счет (из таблицы «Позиции по клиентским счетам (фьючерсы)») account = 'SPBFUT0003f' --положение окна с таблицей. Левый верхний угол в координаты left,top и размеры в width и height. xy = {} xy.left, xy.top, xy.width,xy.height = 0, 232, 722, nil --ширина столбцов таблицы t_width = {12, 6, 10, 8, 10, 10, 9, 7, 6, 11, 10, 11} -- месяц и год исполнения, 2 символа, https://www.moex.com/s205 MonthYear = "Z8" -- код базового актива, 2 символа -- если 4 символа, то переменная "MonthYear" не учитывается SecCodes={ {"MM"}, --контракт на индекс МосБиржи {"Si"}, --руб/доллар FORTS {"SR"}, --Sber FORTS {"LK"}, --контракт на Лукойл {"GZ"}, --контракт на Газпром {"BRX8"}, --контракт на нефть Брент, месяц и год - "X8" {"ED"}, --контракт на ED {"RN"}, --контракт на Роснефть {"GD"}, -- Gold } --Если xy.height == nil, то вычислить ее. --Для разных мониторов коэффициенты (17, 45 и 868 - подобраны эмпирически) будут разными. local height = xy.height or ((#SecCodes + 1)*17 + 45) if height > 868 then height = 868 end xy.height = height
["EXPIRY_DATE"] = "GTC"Собственно, два вопроса: