Закончим писать робота, который мы начали на предыдущих уроках. Напомню, что мы пишем робота-спредера. Он будет выставлять заявки на покупку и на продажу, если в стакане достаточно большой спред. На данный момент наша заготовка робота может корректно определять крайние цены в стакане с учетом уже выставленных заявок. Настало время написать модуль, который будет торговать.
Qlua для чайников. Часть 1Qlua для чайников. Часть 2. ЦиклыQlua для чайников. Часть 3. Работа со стаканомQlua для чайников. Часть 4. Анализ информации из стакана и работа с заявкамиQlua для чайников. Часть 5. Работа с таблица Quik. Поиск заявок. Искусство отладкиКакие функции должен выполнять этот модуль торговли? Сейчас я перечислю их:
- Проверять размер спреда, если он больше заданной величины, то это сигнал на совершение сделки.
- Выставлять заявки, если есть сигнал.
- Следить затем, чтобы не было выставлено лишних заявок – если заявка выставлена но еще не сработала, то новую заявку не выставляем.
- Переставлять заявки, если изменились крайние цены в стакане.
- Следить за количеством инструмента – если, например, мы выставили заявку на покупку и на продажу, одна из них сработала или частично сработала, а потом изменились цены, то при перевыставлении заявок надо учесть этот факт.
Что бы робот следил за тем, сколько инструментов мы купили/продали, нам необходимо научится получать количество инструмента на балансе. Стоит заметить, что если мы решили привязаться к количеству акций на балансе, то мы предполагаем, что другие роботы по этому инструменту на этом счете не торгуют и вручную этим инструментом мы тоже не торгуем. В противном случае нам придется по-другому отслеживать количество проданных или купленных акций. Как вариант обрабатывать событие OnTrade (совершение сделки), как это сделано в роботе на RSI (
http://robostroy.ru/community/article.aspx?id=765).Но в нашем случае мы будет отслеживать через количество акций на балансе (чтобы изучить данную тему). При написании собственных роботов, можете выбрать тот способ, который сочтете нужным.Итак, начнем. Сначала разработаем функцию, предназначенную для получения остатка по ценной бумаге. Стоит заметить, что для срочного и фондового рыков способы получения остатков отличаются. Сегодня мы изучим способ для фондового рынка.На фондовом рынке остатки по акциям можно получить из таблицы DEPO_LIMITS – остатки по бумагам. С таблицами мы уже работали на уроке 5 (
http://robostroy.ru/community/article.aspx?id=788). Тут точно так же, только другое имя таблицы. Таким образом, подпрограмма поиска лимита включает в себя две функции find_limit – сама функция поиска и fn_limit – вспомогательная функция, которая отвечает за осуществление отбора при поиске. Вот эти функции:
--Поисковая функция лимитаfunction fn_limit(sec_code, limit_kind, currentbal) if sec_code==p_seccode and limit_kind==2 then return true else return false endend--Процедура поиска лимитаfunction find_limit() local NO=getNumberOf(«DEPO_LIMITS») t_limits = SearchItems(«DEPO_LIMITS», 0, NO-1, fn_limit, «sec_code, limit_kind, currentbal») if t_limits ~= nil then t_limit_item=getItem(«DEPO_LIMITS», t_limits[1]) return t_limit_item[«currentbal»] end return 0end |
У вас может возникнуть вопрос – а что же такое limit_kind?.. А это тип лимита. Сейчас на фондовом рынке акции торгуются по принципу T2 – все расчет сдвинуты на два дня. Акции, которые вы купили сегодня, поступают на остаток Т2. На следующий день они окажутся на Т1 и еще на следующий на Т0. Тип остатка Т0 – это то, что у вас есть сейчас. Т1 – что будет завтра, а Т2 – что будет послезавтра.Если вы торгуете интрадей, то целесообразно анализировать остатки типа Т2, так как при покупке акций у вас они зачислиться именно туда. Оттуда же и списываются при продаже. Правда, финансовый результат от подобных операций будет доступен только через два дня, когда он попадет на Т0.Проверить эту функцию можно просто выводя остатки в логе или через message. Вот как к ней можно обращаться:
p_file:write(os.date().." limit: "..find_limit().."\n") |
Теперь займемсявыставлением заявок. Из урока 1 (
http://robostroy.ru/community/article.aspx?id=773) вы уже знаете, как это делать. Можно просто скопировать оттуда код и отредактировать, как вам надо. В частности, в поля CLASSCODE, SECCODE, ACCOUNT, CLIENT_CODE поставить параметры. Другой вопрос, что ставить в поля OPERATION, QUANTITY, PRICE? Эти поля необходимо сначала вычислить. Поэтому, для выставления заявки целесообразно создать отдельную функцию, например, trade:
function trade(a_oper, a_count, a_price) t = { [«CLASSCODE»]=p_classcode", [«SECCODE»]=p_seccode, [«ACTION»]=«NEW_ORDER», [«ACCOUNT»]=p_account, [«CLIENT_CODE»]=p_client_code, [«TYPE»]=«L», [«OPERATION»]=a_oper, [«QUANTITY»]=tostring(a_count), [«PRICE»]=tostring(a_price), [«TRANS_ID»]=«1» } res=sendTransaction(t) message(res,1)end |
Обратите внимание, что мы добавили парочку параметров, так что их нужно прописать в самом начале программы (там, где у нас другие параметры):
p_account=«L01-00000F00» --Клиентский счет(новый параметр)p_client_code=«52720» — Код клиента(новый параметр) |
Разумеется, значение параметров нужно поставить свои.Для того чтобы написать код выставления заявки, нам опять же, потребуются дополнительные параметры: количество лот, которым мы торгуем, размер лота (потому что в заявке мы задаем количество в лотах, а остатки программа нам возвращает в акциях), ну, и разумеется, минимальный спред. Разметите эти параметры также в начале программы:
p_count=5 — скольки лотами торгуемp_min_spread=0.000010 --минимальный сперд, при котором мы торугемp_lost_size=100000 --размер лота |
А вот и сам код:
--а вот тут мы совершаем сделку if tonumber(v_offer)-tonumber(v_bid)>=p_min_spread then count=tonumber(find_limit())/tonumber(p_lost_size) p_file:write(os.date().." count="..count.."\n") count_buy=p_count-count count_sell=p_count+count if count_buy~=0 and buy_order=="" then trade(«B», count_buy, v_bid) end if count_sell~=0 and sell_order=="" then trade(«S», count_sell, v_offer) end end |
Вставите его в конце OnQuote, но перед концом первого условия (перед оператором end).Поясню код. Сначала мы считаем спред (наш потенциальный доход). Если он больше или равен минимальному значению, совершаем сделку. Если меньше – от сделки отказываемся. Затем вычисляем, сколько нам надо докупить или допродать. Допустим, мы решили торговать пятью лотами. Если на остатке ничего нет, то нам надо купить и продать по 5 лотов. На такое количество выставляем заявки. Если у нас одна из заявок, например, на покупку, частично сработала, купив 1 лот, то нам осталось докупить 4. Если у нас будут выставляться заявки, то программа вычтет это количество из того количества, которым мы торгуем. Если мы в шорте, то мы вычитаем отрицательное число – минус на минус дает плюс, нам надо купить больше, что бы закрыть шорт. В случае шорта мы напротив, остаток прибавляем.Что будет, если этот участок кода буде выполнятся повторно? В этом случае у нас номер выставленных заявок, как на покупку, так и на продажу, будет храниться в памяти компьютера. То есть в переменных buy_order и sell_order будет какое-то значение, отличное от пустого. Условие не выполнился и заявка повторно не станет выставляться. За это отвечают те участки программы, которые мы долго и упорно писали на предыдущих уроках.Если мы заявку удалим, или она у нас полностью исполниться, то переменные buy_order и sell_order примут пустое значение. Этот код мы так же написали на прошлых уроках. Таким образом, программа сможет выставить новую заявку, если только количество лот, на которое надо выставить заявку, не равно нулю. А нулю оно будет равно в том случае, если мы докупили или допродали до полного объема. Например, купили 5 лот, значит, на покупку больше заявка не может быть выставлена. А на продажу может – нам надо продать 10 лот. Если мы продали один лот и у нас осталось 4 – то мы можем докупиться до пяти лот – компьютер при следующем выполнении кода (когда появятся изменения в стакане) сможет выставить заявку на покупку 1 лота.Может так оказаться, что по той бумаге, которой мы торгуем, нельзя шортить. Тогда программа выдаст вот такое сообщение:
И программа выставит только заявку в лонг. Причем она будет пытаться выставить заявку в шорт при каждом изменении стакана. Можно внести в программу флаг, показывающий, что по данной акции нельзя шортить. Это будет новый параметр — переменная, который надо добавить в начало программы. Назовем его p_can_short:
Можно переписать индикатор и стратегию на другом языке, под который есть инфраструктура для тестирования, как вариант. Например, в том же TSLab пишете индикатор и стратегию на C# (хотя лично мне работа с тамошним редактором кода показалась неудобной) и тестируете.