Продолжаем разработку универсального робота!
Выкладываю код OUR-0.3, который в настоящий момент еще далеко не полный – это только основа, скачать можно здесь https://yadi.sk/d/l3uic67yruCxa
Код прокомментирован подробно, но дам дополнительное описание общего плана, чтобы логику работы робота можно было представить.
Итак, по порядку:
Робот состоит из двух файлов: OUR.lua содержит основные функции (OnInit, main, коолбэки – пока только один OnStop), FunOUR.lua содержит вспомогательные функции – все остальные. Дополнительно приложен файл с информацией и файл с образцом котировок.
Функция OnInit
1 Первоначально котировки с сервера поступают в источник – таблицу с барами TBar (там все заполняется автоматически при подключении источника).
2 Далее робот делает различные вычисления, результаты которых он помещает в таблицу с данными TDat (также туда копируются параметры баров из TBar), эту таблицу нужно заполнять самому, ключи таблицы на свое усмотрение, но конечно часть ключей в алгоритм уже заложены, это «key»,«O»,«H»,«L»,«C»,«V»,«T» от них идут все вычисления. TDat – это таблица, содержащая таблицы по каждому бару, ключ соответствует номеру бара в источнике. Структура такого типа:
TDat = { [1321] = {"O","H","L","C","SMAf","SMAs"…}, [1322] = {"O","H","L","C","SMAf","SMAs"…}, … }
Робот на каждом шаге смотрит индекс последнего бара в таблице TBar и проверяет проведены для него вычисления в таблице TDat или нет, в зависимости от этого делает необходимые вычисления.
3 Задаваемые значения (типа периодов индикаторов, настроек робота и т.п.) помещаются в таблицу значений TVal. Ниже вызывается фунция funVal, которая дополняет таблицу значений – сделал, чтобы задавать значения, касающиеся моей личной стратегии – так удобней, в открытой версии функция пуста).
4 Таблица TSrv – содержит время сервера в трех форматах, в коде все описано. Таблица TStm содержит параметры сигналов времени – последовательно разбиваете сутки на периоды (начиная от 00:00:00), в которые указываете, что можно делать роботу, сигналы расписаны в файле с информацией (можно добавлять дополнительно строки, но надо чтобы время шло последовательно – разнобой пока не обрабатывается). Время и дата в роботе представляется в 3-х видах: обычная текстовая строка (стараюсь в имени переменной добавлять префикс St), таблица формата DateTime (стараюсь в имени переменной добавлять префикс DT), целое число формата Posix – количество секунд прошедшее с какой-то даты (стараюсь в имени переменной добавлять префикс Px). Префиксы кажется есть везде, кроме Bar:T(i) (здесь DateTime по умолчанию создает квик) и Dat[i].T (здесь не стал менять традицию и использую обозначение T, но формат Posix).
5 Таблица TSec содержит параметры инструмента, вероятно в ней же будут помещаться параметры позиций, так как они относятся к инструменту.
6 Во вспомогательных функциях имена указанных таблиц представляются без буквы «T», ну и по тексту могу где-то «T» не указывать. Имена вспомогательных функций начинаются с символов Fun…
Функция main
1 Сначала подключаем источник данных, потом делаем проверки, далее идет основной цикл робота, который «крутится» с заданной задержкой.
2 Внутри цикла робот определяет количество баров в источнике данных TVal.N и вызывает две функции – одна осуществляет расчет на истории FunCompleted (рассчитывает каждый бар до текущего незавершенного бара), другая осуществляет расчет только для текущего бара FunCurrent. В этих функциях никакой код менять не надо, но они вызывают другие 4 функции (FunNewBar1, FunNewBar2, FunOldBar1, FunOldBar2) в которые и нужно вносить необходимый вам код.
3 Указанные функции выполняют следующее (после окончания паузы конечно):
FunNewBar1 – выполняется один раз при появлении нового незавершенного текущего бара (например, если торговля будет вестись от цены открытия бара, то расчеты надо делать в этой функции).
FunNewBar2 – выполняется каждый раз при снятии с паузы для незавершенного текущего бара (если необходимо что-то контролировать постоянно – с максимальной скоростью, например стакан, то это надо делать в этой функции).
FunOldBar1 – выполняется всего один раз при запуске робота для вычисления предистории (при вычислениях часто идет обращение к вычислениям на предыдущих барах, поэтому при начале вычислений на первых барах истории надо задать значения к которым будет обращаться робот — предистория, обычно хотя бы нули, чтобы у робота алгоритм сошелся, здесь это и задается). Количество баров предистории задается параметром TVal.Hpre – обычно это как минимум 1 бар.
FunOldBar2 – выполняется один раз для каждого бара на истории и для только что завершенного текущего бара. Когда текущий бар завершается, то он становится историей и для него один раз вызывается эта функция. Количество баров истории, для которых надо все рассчитать задается параметром TVal.H – обычно это количество, необходимое для того, чтобы все сигналы стратегии адекватно определились. Если торговать по завершенным барам, то основной алгоритм надо расположить в этой функции – это кстати будет и наш случай наверное, будем осуществлять анализ по закрытым барам (но это еще обсудим).
В функциях параметр i – это номер бара для которого проводится вычисление – бар для которого вызвана функция. Функции для каждого бара, если выполняются условия требующие вызова и описанные выше, вызываются автоматически, при написании кода не надо беспокоиться о вызове, надо просто оперировать индексом бара i для которого вызвана функция.
4 Еще есть параметр TVal.Hplus – он задает количество баров на которые растягивается «хвост» индикаторов – нужно чтобы эти бары были в источнике данных. Сумма TVal.H + TVal.Hplus + TVal.Hpre – это то минимально необходимое количество баров, которое требуется для запуска робота.
5 Таким образом, весь процесс задания стратегии в роботе будет происходить в указанных в п.3 четырех функциях, в них надо вычислить необходимые параметры (сигналы) и вызвать торговые функции с этими сигналами. Если для вычисления понадобится какая-то особенная функция, то её надо написать и добавить в код робота, после чего вызывать в указанных четырех функциях.
Сигналы
Первичный сигнал пересечения скользящих средних использующий 8 бит вычисляется в переменной Dat[i].beepFS, его биты описывал в этой статье http://smart-lab.ru/blog/325075.php .
Сигнал Dat[i].beepFS пересчитывается в сигнал Dat[i].beepTr использующий 4 бита (это будет сигнал тренда) этот сигнал попроще – определяет только направления низ и верх, а равенство исключает, для нашего случая заморачиваться на равенстве линий нет смысла:
(1000) = состояние в (0100) - событие в (0010) - событие н (0001) = состояние н
Далее
1 По индикаторам. Я сторонник, чтобы используемые индикаторы вычислялись в роботе, поэтому значения быстрой и медленной скользящих средних вычисляются отдельной функцией FunSMA, которая записывает значения SMAf и SMAs в массив Dat для бара с индексом i. При желании конечно можно брать значения индикаторов с графиков, но это более муторно – появляется привязка к графику и для этого все равно понадобится какая-нибудь функция.
2 По быстродействию. Планирую отрабатывать робота на минутных таймфреймах с паузой не менее 1 секунды, думаю для терминала квик достаточно раз в секунду анализировать ситуацию, если нужна скорость, то это уже не квик ))), для таймфреймов побольше наверное проблем не должно быть.
3 Контроль. После запуска и остановки робота в папке создается файлик в который сбрасывается содержимое таблицы TDat – это чтобы можно было анализировать, что у него там внутри происходит. Каждый раз создаются новый файл – к имени добавляется время.
4 Остальное описание можно посмотреть в коде, если что не понятно, спрашивайте.
5 Для запуска робота надо выполнить в квике файл OUR.lua (квик к серверу можно и не подключать, конечно, надо обратить внимание на настройки робота – например, на инструмент, котировки которого должны быть в наличии), все файлы должны находиться в одной папке. Как запускать – можно посмотреть здесь http://smart-lab.ru/blog/325678.php .
Последние дни занимался функцией, которая будет парсить котировки, чтобы сделать возможность тестирования стратегий на истории. Затем эти котировки будут заливаться в таблицу TBar и робот сможет по ним прогонять алгоритм. Далее надо разрабатывать функции, которые будут вычислять торговый сигнал и обрабатывать его – торговать, а также подсчитывать профит (хаха…) при тестировании на истории.
Подумал, что к пересечению скользящих средних нужно еще что-нибудь добавить – какие будут предложения – какие сигналы/индикаторы еще использовать в стратегии для примера?
Знания программирования не нужны, проще, чем тслаб.
В робот можно загнать до 50-ти различных систем на разных тикерах для диверсификации.
)
Пытался использовать такую функцию, которая только один раз обрабатывает событие по трейду, всё остальное игнорирует..
nction OnTrade(Trade)
if Flag_OnTrade == true then
--message(tostring(os.time(Trade.datetime)).." "..tostring(T),1)
— TT = os.date("*t",T)
— message(tostring(Trade.datetime.min)..":"..tostring(Trade.datetime.sec).." "..tostring(TT.min)..":"..tostring(TT.sec),1)
end
if Trade.trade_num == TradeNum or Flag_OnTrade == false or T >= os.time(Trade.datetime) then
return
end
--message(«TradeNum = »..tostring(Trade.trade_num),1)
Flag_OnTrade = false
TradeNum = Trade.trade_num
NEW_STOP_ORDER(p_classcode, p_seccode, p_account, Position)
end
и это даже работало и хорошо работало, но только на демке, на сервере разработчиков ) на реале у брокера функция врубалась в самые неожиданные моменды, что доставляло мне много радости ))) (ведь на реале) .
Поэтому я эти колбеки больше не использую, и не видел ни одного примера их удачного использования. Все реакции бота основаны на изменение баланса, чистой позиции по инструменту. так проще, но конечно медленнее, но у меня в сбере отложка иногда по пчть секунд исполняется, поэтому задержки в пределах секунды для такого режима торговли вообще несущественны..
использовать баланс и позицию по инструменту не очень хочется, так как на них и другие роботы влиять могут
Проблема возникает, если заявку послал — и ни ответа, ни привета. Разобраться, в чем была проблема, достаточно сложно. Если была ошибка в заявке, колбек поможет. А если проблема на линии связи, у брокера или на бирже — фиииг знает, что делать.
PORTFOLIO_EX(15)(треллинг)(MMM6); DESCRIPTION (15)(треллинг) (MMM6); CLIENTS_LIST ALL_CLIENTS; FIRMS_LIST ALL_FIRMS;
USE_CASE_SENSITIVE_CONSTANTS;
PROGRAM
ACCOUNT = "...." MARKET = «SPBFUT» TICKER = «MMM6»
NEW_GLOBAL(«TRANS_ID», 0)
STOP_FACTOR = 5 SPREAD_FACTOR =15
NEW_GLOBAL(«LAST_ORDER», 0)
IF LAST_ORDER == 0 BALANCE = GET_BALANCE(MARKET, TICKER)+0 IF BALANCE != 0 LAST_ORDER = NEW_STOP_ORDER(MARKET, TICKER, ACCOUNT, BALANCE)+0 END IF END IF
TOTAL = GET_NUMBER_OF(«STOP_ORDERS») FOR INDEX FROM 0 TO (TOTAL-1) RINDEX = TOTAL — INDEX ORDER = GET_ITEM(«STOP_ORDERS», RINDEX) IF (GET_VALUE(ORDER, «NUMBER»)+0) == LAST_ORDER STATUS = GET_VALUE(ORDER, «STATUS») IF STATUS == «ACTIVE» HAVE_CHANGE = 0 QUANTITY = GET_VALUE(ORDER, «QUANTITY»)+0 BALANCE = GET_BALANCE(MARKET, TICKER) IF QUANTITY !=ABS(BALANCE) HAVE_CHANGE =1 LOG(«Количество изменилось: » & BALANCE) ELSE PRICES = CREATE_MAP() PRICES = SET_STOPPRICE(PRICES, MARKET, TICKER, QUANTITY) SPRICE = GET_VALUE(PRICES, «STOPPRICE»)+0 OPRICE = GET_VALUE(ORDER, «CONDITION_PRICE»)+0 IF GET_VALUE(ORDER, «OPERATION») == «BUY» IF SPRICE < OPRICE LOG(«Цена стопа продажи уменьшилась: » & SPRICE) HAVE_CHANGE =1 END IF IF SPRICE > OPRICE LOG(«Цена стопа продажи увеличилась: » & SPRICE) END IF ELSE IF SPRICE < OPRICE LOG(«Цена стопа покупки уменьшилась: » & SPRICE) END IF IF SPRICE > OPRICE LOG(«Цена стопа покупки увеличилась: » & SPRICE) HAVE_CHANGE =1 END IF
END IF END IF IF HAVE_CHANGE == 1 KILL_STOP_ORDER(MARKET, TICKER, ACCOUNT, LAST_ORDER) END IF ELSE LAST_ORDER = 0 END IF END IF END FOR
FUNC KILL_STOP_ORDER(_MARKET, _TICKER, _ACCOUNT, _NUMBER) T = CREATE_MAP() TRANS_ID = TRANS_ID + 1 T = SET_VALUE(T, «TRANS_ID», TRANS_ID) T = SET_VALUE(T, «ACTION», «KILL_STOP_ORDER») T = SET_VALUE(T, «STOP_ORDER_KEY», _NUMBER) T = SET_VALUE(T, «CLASSCODE», _MARKET) T = SET_VALUE(T, «SECCODE», _TICKER) T = SET_VALUE(T, «ACCOUNT», ACCOUNT) R = SEND_TRANSACTION(30, T) RESULT = GET_VALUE(R, «RESULT»)+0 LOG(GET_VALUE(R, «DESCRIPTION»)) END FUNC
FUNC NEW_STOP_ORDER(_MARKET, _TICKER, _ACCOUNT, _SIZE) T = CREATE_MAP() TRANS_ID = TRANS_ID + 1 T = SET_VALUE(T, «TRANS_ID», TRANS_ID) T = SET_VALUE(T, «ACTION», «NEW_STOP_ORDER») T = SET_VALUE(T, «CLASSCODE», _MARKET) T = SET_VALUE(T, «SECCODE», _TICKER) T = SET_VALUE(T, «ACCOUNT», ACCOUNT) T = SET_STOPPRICE(T, _MARKET, _TICKER, _SIZE) IF BALANCE > 0 T = SET_VALUE(T, «OPERATION», «S») ELSE T = SET_VALUE(T, «OPERATION», «B») END IF T = SET_VALUE(T, «QUANTITY», ABS(_SIZE)) R = SEND_TRANSACTION(30, T) LOG(GET_VALUE(R, «DESCRIPTION»)) RESULT = GET_VALUE(R, «ORDER_NUMBER») END FUNC
FUNC LOG(_MSG) ROW = CREATE_MAP() DT = GET_DATETIME() ROW = SET_VALUE(ROW, «DT», GET_VALUE(DT, «DATETIME»)) ROW = SET_VALUE(ROW, «MSG», _MSG) ADD_ITEM(1, ROW) END FUNC
FUNC GET_BALANCE(_MARKET, _TICKER) RESULT = 0 _TOTAL = GET_NUMBER_OF(«FUTURES_CLIENT_HOLDINGS») FOR _INDEX FROM 1 TO _TOTAL DEPO = GET_ITEM(«FUTURES_CLIENT_HOLDINGS», _INDEX) IF GET_VALUE(DEPO, «SECCODE») == TICKER IF GET_VALUE(DEPO, «TRDACCID») == ACCOUNT RESULT = GET_VALUE(DEPO, «TOTAL_NET»)+0 BREAK END IF END IF END FOR END FUNC
FUNC SET_STOPPRICE(_MAP, _MARKET, _TICKER, _SIZE) _PRICE = GET_PARAM(_MARKET, _TICKER, «LAST»)+0 _STEP = GET_VALUE(GET_PARAM_EX(_MARKET, _TICKER, «SEC_PRICE_STEP»), «PARAM_VALUE»)+0 IF BALANCE > 0 _STOPPRICE = _PRICE — (STOP_FACTOR)' * _STEP) _PRICE = _STOPPRICE — (SPREAD_FACTOR)' * _STEP) ELSE _STOPPRICE = _PRICE + (STOP_FACTOR)' * _STEP) _PRICE = _STOPPRICE + (SPREAD_FACTOR)' * _STEP) END IF _R = CREATE_MAP(_MAP) _R = SET_VALUE(_R, «PRICE», _PRICE) _R = SET_VALUE(_R, «STOPPRICE», _STOPPRICE) RESULT = _R END FUNC
FUNC ROUND_PRICE(_PRICE, _STEP) RESULT = APPLY_SCALE(_PRICE / _STEP, 0) * _STEP END FUNC
END_PROGRAM
PARAMETER DT; PARAMETER_TITLE Дата и Время; PARAMETER_DESCRIPTION Дата и Время; PARAMETER_TYPE STRING(30); END
PARAMETER MSG; PARAMETER_TITLE Сообщение; PARAMETER_DESCRIPTION Сообщение; PARAMETER_TYPE STRING(300); END
END_PORTFOLIO_EX
есть другой способ.
вот код робота на рси. к нему стоп скользящий. и толку. здесь стоп большой. и нужен файл лога.
--Параметры: p_classcode=«SPBFUT01» --Код класса p_seccode=«BRJ6» --Код инструмента p_account="...." --Код счета p_clientcode="...." --Клиенткий код p_count=1 --Размер позиции p_spread=0.15 --Проскальзывание p_sell_level_RSI=60 --уровень RSI, при котором продаем p_buy_level_RSI=40 --уровень RSI, при котором покупаем p_TRANS_ID=«2» --идентифкатор транзакций робота, нужен для того, что бы робот отличал свои транзакции от транзакций других роботов и ручных транзакций p_TRANS_ID_STOP=«3» --по работе со стоп ордерами p_stop_loss_level=0.15 --Уровень стоп лосса p_traling_stop_level=0.3 --Уровень стоп лосса, при котором мы «подтягиваем» стоп лосс p_file = io.open(«C:\\BRJ6\\userlog.txt», «w») — тут надо указать путь к файлу лога
--Служебные переменные is_run = true count = 0 in_trade = false --признак того, что мы в позиции order_num = "" --номер заявки по открытой сделке stop_loss_num = "" --номер стоп заявик по открытой сделке direction="" --последний тип операции last_price=0 --цена последней сделки по стратегии in_set_stop_loss = false --признак, что мы в данный момнет ожидаем результата выставления стоп лосса
function main() while is_run do sleep(200) robot() end end
function to_log(a_msg) p_file:write(os.date().." "..a_msg.."\n") end
function robot() local RSI=getNumCandles(«RSI») local N=getNumCandles(«Price») t,n,i=getCandlesByIndex(«Price», 0, N-1, 1) RSI_t,RSI_n,RSI_i=getCandlesByIndex(«RSI», 0, RSI-3, 2) --сигнла обрабатываем только если мы не в позиции if not(in_trade) then --сигнал на продажу (RSI пересекает уровень продажи сверху вниз) if RSI_t[0].close>p_sell_level_RSI and RSI_t[1].close<p_sell_level_RSI then Trade(«S»,count+p_count,t[0].close-p_spread) end --сигнал на покупку (RSI пересекает уровень покупки снизу вверх) if RSI_t[0].close<p_buy_level_RSI and RSI_t[1].close>p_buy_level_RSI then Trade(«B»,p_count-count,t[0].close+p_spread) end else --проверить состояние стопа, не надо ли его сдвигать или изменить количество stop_loss_control() end end
function fn(par1) if stop_loss_num=="" then return false end if tonumber(par1) — tonumber(stop_loss_num)==0 then return true else return false end end
function stop_loss_control()
local N=getNumCandles(«Price») if N==nil or N==0 then return end p_t,p_n,p_i=getCandlesByIndex(«Price», 0, N-1, 1) local NO=getNumberOf(«stop_orders») local is_stop_order=true if NO==nil or NO==0 then is_stop_order=false else t_so = SearchItems(«stop_orders», 0, NO-1, fn, «order_num») end --если стоп лосса нет, то возможно, его надо выставить if t_so==nil and is_stop_order then is_stop_order = false end if is_stop_order then if t_so[1]==nil then is_stop_order = false end end if not(is_stop_order) then if in_trade and count~=0 then if count>0 then send_stop_loss(«B»,count,last_price) else send_stop_loss(«S»,count,last_price) end end return end
to_log(«stop_loss_control найден стоп ордер count=»..count) t_so_item=getItem(«stop_orders», t_so[1]) delta_price=0; if count>0 then to_log(«count>0») delta_price=p_t[0].close-t_so_item.condition_price; l_direction=«B» else to_log(«count<=0») delta_price=t_so_item.condition_price-p_t[0].close l_direction=«S» end to_log(«delta_price=»..delta_price.." t_so[0].qty="..t_so_item.qty.." p_t[0].close="..p_t[0].close) if delta_price>=p_traling_stop_level or count~=t_so_item.qty then to_log(«Послылаем новую стоп заявку price=»..p_t[0].close.." количество "..count) send_stop_loss(l_direction,count,p_t[0].close) end end
function Trade(a_oper,a_count,a_price) if a_count>0 then --Сначала пошлем обычную заявку t = { [«CLASSCODE»]=p_classcode, [«SECCODE»]=p_seccode, [«ACTION»]=«NEW_ORDER», [«ACCOUNT»]=p_account, [«CLIENT_CODE»]=p_clientcode, [«TYPE»]=«L», [«OPERATION»]=a_oper, [«QUANTITY»]=tostring(a_count), [«PRICE»]=tostring(a_price), [«EXPIRY_DATE»]=«TODAY», [«TRANS_ID»]=p_TRANS_ID } res=sendTransaction(t) --заявку послали и сразу же мы оказались в позиции и будем в ней до тех пор, пока не закроется сделка --или пока не будет доказано обратное (мы узнаем, что сделка не прошла) in_trade=true direction=a_oper message(«Количество сделки »..tostring(a_count).." тип операции "..a_oper.." Цена "..a_price,1) end end
--Обработчик события сделки function OnTrade(trade) nord=trade[«order_num»] --номер заявки price=trade[«price»] --цена сделки to_log(«Совершена сделка: номер заявки »..tostring(nord).."; цена "..tostring(price)..": количество "..tostring(trade[«qty»])) if nord==order_num then qty=trade[«qty»] --Количество бумаг в последней сделке в лотах if direction==«B» then count=count+qty else count=count-qty end send_stop_loss(direction,count,price) last_price=price end end
--Обработчик события создания стоп заявки function OnStopOrder(stop_order) --бит 0 (0x1) Заявка активна, иначе не активна if stop_order[«order_num»]==stop_loss_num and bit.band(stop_order[«flags»],0x1)==0x1 then to_log(«сняли признак что мы в процессе выставления стоп оредра») in_set_stop_loss=false end --бит 0 (0x1) Заявка активна, иначе не активна, --бит 1 (0x2) Заявка снята. Если не установлен и значение бита 0 равно 0, то заявка исполнена --в этом случае мы считаем, что позция закрыта по стоп лоссу if stop_order[«order_num»]==stop_loss_num and bit.band(stop_order[«flags»],0x1)==0x0 and bit.band(stop_order[«flags»],0x2)==0x0 then in_set_stop_loss=false in_trade=false count=0 end end
--Удалить стоп лосс function delete_stop_loss(a_num) t = { [«CLASSCODE»]=p_classcode, [«SECCODE»]=p_seccode, [«ACTION»]=«KILL_STOP_ORDER», [«ACCOUNT»]=p_account, [«CLIENT_CODE»]=p_clientcode, [«TYPE»]=«L», [«OPERATION»]=l_oper, [«STOP_ORDER_KIND»]=«SIMPLE_STOP_ORDER», [«TRANS_ID»]=p_TRANS_ID_STOP, [«STOP_ORDER_KEY»]=tostring(a_num) } res=sendTransaction(t) message(«Удаляем стоп лосс: сообщение »..res.."; номер "..a_num,1) end
--Послать стоп заявку function send_stop_loss(a_direction,a_count,a_price)
to_log(«send_stop_loss in_set_stop_loss=»..tostring(in_set_stop_loss))
if not(in_set_stop_loss) then if stop_loss_num~="" then delete_stop_loss(stop_loss_num) end if a_direction==«B» then l_oper=«S» l_count=a_count dir=-1 else l_oper=«B» l_count=-a_count dir=1 end l_price=a_price+p_stop_loss_level*dir
if l_count>0 then to_log(«send_stop_loss Зашли сюда»,1) in_set_stop_loss=true --Пошлем стоп заявку t = { [«CLASSCODE»]=p_classcode, [«SECCODE»]=p_seccode, [«ACTION»]=«NEW_STOP_ORDER», [«ACCOUNT»]=p_account, [«CLIENT_CODE»]=p_clientcode, [«TYPE»]=«L», [«OPERATION»]=l_oper, [«QUANTITY»]=tostring(l_count), [«PRICE»]=tostring(l_price+p_spread*dir), [«EXPIRY_DATE»]=«TODAY», [«STOPPRICE»]=tostring(l_price), [«STOP_ORDER_KIND»]=«SIMPLE_STOP_ORDER», [«TRANS_ID»]=p_TRANS_ID_STOP } res=sendTransaction(t) message(res,1) to_log(«Выставли стоп заявку »..l_oper) end end
end
--обработка события транзакции function OnTransReply(trans_reply) id=tostring(trans_reply[«trans_id»]) --Пользовательский идентификатор транзакции to_log(«Обработка транзакции »..id) --если это наша транзакция, обработаем ее if id==p_TRANS_ID then nord=trans_reply[«order_num»] --Номер заявки to_log(«Обработка транзакции номер заявки »..nord) --если заявка выставилась — запоминаем ее номер, иначе считаем, что мы не в сделке if nord==nil or nord==0 or nord==«0» then message(«Заявка не выставилась »,1) in_trade=false else order_num=nord end end if id==p_TRANS_ID_STOP then message(«Сообщение транзакции стоп ордера »..trans_reply[«result_msg»],1) nord=trans_reply[«order_num»] --Номер заявки --если заявка выставилась — запоминаем ее номер, иначе считаем, что мы закончили выставлять стоп заявку if nord==nil then message(«Стоп заявка не выставилась »,1) in_set_stop_loss=false stop_loss_num="" else stop_loss_num=nord end end end
function OnStop(stop_flag) is_run=false stop_flag=1 p_file:close(); end