Блог им. finstrateg

Открытый Универсальный Робот – Основа робота

Продолжаем разработку универсального робота!

Выкладываю код 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 и робот сможет по ним прогонять алгоритм. Далее надо разрабатывать функции, которые будут вычислять торговый сигнал и обрабатывать его – торговать, а также подсчитывать профит (хаха…) при тестировании на истории.

Подумал, что к пересечению скользящих средних нужно еще что-нибудь добавить – какие будут предложения – какие сигналы/индикаторы еще использовать в стратегии для примера?

★28
30 комментариев
Один там накупил уже роботов) матерится теперь
avatar
Байкал, прибыльного робота можно сделать только самому или с помощью программера по своему алгоритму, продавать прибыльного робота не будут. Если робота продают, то зарабатывает он меньше, чем стоит )))
avatar
finstrateg, да я не про ваш топик а про другой был здесь днем сегодня как парень купил робота)
avatar
Байкал, роботы серьезна зарабатывают?
avatar
На самом деле Вы изобретаете велосипед. Пользуюсь конструктором торговых роботов 3CBot http://www.saturn-capital.info/#!blank/zpgpl
Знания программирования не нужны, проще, чем тслаб.
В робот можно загнать до 50-ти различных систем на разных тикерах для диверсификации.
avatar
Андрей Рубанов, согласен — это по большей части велосипед, но это мой велосипед и к нему я смогу добавить то, что не является велосипедом, а не ставить галочки в предложенных полях и сливать как все ))) например, в тслабе невозможно было сделать индикатор, который мне был нужен, вероятно программеры его смогли бы сделать, но это слив идеи… а конструктор еще и платный — нет уж, я с некоторых пор стал очень разборчивым, вот если бы автор мог заработать с помощью этого конструктора, то либо раздавал его бесплатно, либо, что скорее всего, никому его не показывал )))
avatar
пересечение скользяшек это не сигнал, это то что Вы видите и принимаете решение на покупку продажу, пересечение — это лишь стечение обстоятельсв)))
или http://ensed.org/
Bobaho, это не наш метод )))
avatar
в любом случае Вы стоите на правильном пути, хотя и тернистом, если хочешь сделать что то хорошо — сделай это сам! Предложенные ссылки просто сокращают Ваш путь. 
Bobaho, согласен, коротким путем я уже ходил )))
avatar
робот? хуёбот!
avatar
спасибо, выкладывай больше примеров и посложнее)
avatar
Чужой, тяжелый алгоритм получается, примеры посложней могут утонуть в сложности алгоритма.
вообще, я за пол часа с закрытыми глазами (ну почти) вобью в квик рабочего бота  на двух машках. Это если стоит задача запилить что-то для торговли… Но здесь, как я понял идёт упражнение в программировании… Но тоже вопрос неоднозначный, стоит ли организовывать различные потоки, обрабатывать события в колбеках, структурировать данные и перекидывать их из одной функции в другую… Всё это, на мой взгляд, ухудшает работу… учитывая ещё то, что большинство процедур требуют обращения к серверу, а это часть работы ботом никак не контролируется и можно только надеется на корректный ответ в приемлемое время… Для себя решил всё упрощать… Колбеки вообще — зло. Их использование влечёт многократное увеличение кода для обеспечения хоть какой то корректной работы… поэтому в торговые функции их вообще включать не стоит… может для анализа или обработки какого то форсмажора… В идеале мой робот должен войти и выйти две функции по двум условиям ))) но и это стремлюсь упростить . 
)
avatar
Nemo_2000, полезная информация — колбэки еще не знаю использовать или нет — а как без них контролировать заявки? из функции в функцию в основном перекидываются таблицы, а они перекидываются по ссылке — данные остаются на месте, в принципе их вообще можно не перекидывать, так как таблицы глобальные, но для наглядности решил писать, чтобы не запутаться, может потом постираю все передачи явные…
avatar
finstrateg, я пыталсямиспользовать онтрейд, онордер… чуть не поседел… не знаешь вообще сколько и в какой момент они влезут к тебе и всё испортят )))
Пытался использовать такую функцию, которая только один раз обрабатывает событие по трейду, всё остальное игнорирует..

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

и это даже работало и хорошо работало, но только на демке, на сервере разработчиков ) на реале у брокера функция врубалась в самые неожиданные моменды, что доставляло мне много радости ))) (ведь на реале) .

Поэтому я эти колбеки больше не использую, и не видел ни одного примера их удачного использования. Все реакции бота основаны на изменение баланса, чистой позиции по инструменту. так проще, но конечно медленнее, но у меня в сбере отложка иногда по пчть секунд исполняется, поэтому задержки в пределах секунды для такого режима торговли вообще несущественны..

avatar
Nemo_2000, о сложностях с колбэками читал, уже делал несколько попыток разобраться с ними и обмозговывал, как прикрутить их к роботу, понял одно — код они скорее усложняют, а не упрощают, надо очень грамотно обработать всякие ситуации связанные с их использованием

использовать баланс и позицию по инструменту не очень хочется, так как на них и другие роботы влиять могут
avatar
finstrateg, заявки можно контролировать по последствиям, если они встали и если они исполнились, меняются лимиты по деньгам и по бумагам. 
Проблема возникает, если заявку послал —  и ни ответа, ни привета. Разобраться, в чем была проблема, достаточно сложно. Если была ошибка в заявке, колбек поможет. А если проблема на линии связи, у брокера или на бирже — фиииг знает, что делать.
avatar
SergeyJu, я иногда руками заявку посылаю и потом не знаю что делать ))))) робот же в таких ситуациях должен по возможности все закрыть и прекратить все действия до прихода мозга ))), нужно только его «обучить» выявлять такие ситуации
avatar
сможешь написать наа луа!?.. переписать.без файла лога надежней. через лог файл 2 робота работать будут с разными значениями.всё собьётся.для каждого свой файл данных тэикстэ.
 вот код на купиэль

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

 этот автостоп на qpl сначала ставит стоп. потом запись в переменную значения стопа и с каждым изменением стоп сдвигается или на месте.переменная прибавляет шаг.
есть другой способ.
френк френков, я qpl не знаю, так что мне этот код ни о чем… переходи на qlua )))
avatar
finstrateg, это лучший код.он короче.сначала ставит стоп.потом шаг и передвигает.
вот код робота на рси. к нему стоп скользящий. и толку. здесь стоп большой. и нужен файл лога.

--Параметры: 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

 

 

finstrateg, что переходить? ты пишешь блог. что умеешь.  не умеешь это!
френк френков, ты так коротко выражаешь свои мысли, что я не понял, что ты хочешь и зачем привел этот код )))
avatar
 пока 2 способа. в луа синтаксис привёл. но робот не работает. надо нил обрабатывать. не ноль так нил
 finstrateg, что переходить? ты пишешь блог. что умеешь.  не умеешь это!

теги блога finstrateg

....все тэги



UPDONW
Новый дизайн