Transaq
СБО "Transaq" => Подсистема ATF => Topic started by: ddd323 on Декабря 13, 2012, 08:29:43 pm
-
Финам. Фортс. Фьюч на сбер SBRF-12.12
HFT сервер. версия терминала 304.12 (UID послал в личку Heller'у)
Заявка высталялась из onNewCandle на свече 14.03 сегодня (13.12.12) так:
var OrdrHash = new_object("hash"); OrdrHash["quantity"] = 1; OrdrHash["operation"] = OP_BUY; trade_action::transactMultiple(OrdrHash);
Денег на счете достаточно.
Получил в onATFOrderErr следующее:
SBRF-12.12 (sbrf1): Некорректный ордер: (10032) Цена сделки вне лимита Покупка SRZ2
Где проблема: глюк терминала? биржа с диапазонами цен намудрила? финам с настройками сервера? 13-е число?
-
Это точно не глюк терминала и точно Финам тут не виноват.
Проблема находится на стыке системы TRANSAQ и Биржи.
Дело в том, что торговая система FORTS не поддерживает "рыночных" заявок как таковых. Поэтому трейдинговые системы, в том числе и TRANSAQ, получив от клиента "рыночную" заявку, подают её на Биржу как лимитированную заявку по действующей сегодня максимально допустимой (минимально допустимой) цене. Эти максимальные и минимальные цены, или как их называют "планки", TRANSAQ узнаёт от самой Биржи, через шлюз. Так вот, теоретически могут быть промежутки времени, когда Биржа, в силу каких-либо причин уже изменила коридор цен (провела промклиринг или отреагировала на какие-то новости), и уже контролирует заявки по новым ценовым "планкам", а TRANSAQ на момент обработки полученной от клиента заявки ещё не получил или не успел обработать и принять к сведению уведомления Биржи о изменении действующих ценовых планок.
Это наиболее вероятное материалистическое объяснение феномена.
По мере возможности мы попробуем запросить в Финаме логи системы за 13 декабря и изучить обстоятельства вашего случая.
-
Да, спасибо, посмотрите обстоятельства моего случая.
Но вообще не дело. Проблемы клиентам так сказать на ровном месте. Может коль такие ситуации со стороны биржы возможны, стоит какую-нибудь функцию приделать, которая будет отслеживать и перевыставлять?
Или хотя бы дайте нам клиентам возможность с этим работать. Я когда то предлагал, добавьте в АТФ какую-нибудь минимальную библиотечку для работы со строками. Поиск там/str.contains(), да вырезание mid(n,m). А то пока, единственное что можно сделать - тупо перевыставлять последнюю заявку при появлении любой ошибки в onATFOrderErr(var str), либо самому писать что-то а-ля 1) сохранение в файл 2) посимвольное доставание (из просто строки же это вроде не сделаешь) 3) сравнение с алфавитом 4) обратное собирание слов, и т.п.
Кстати, вы в контексте перехода с onATFOrder/Trade на onOrder/Trade механизм/логику работы функции onATFOrderErr(var str) меняли начиная с ATF1.16? Или она по-прежнему, в т.ч. и после ATF 1.20 будет в соответствии с названием выдавать ошибки по заявкам конкретного скрипта? (Вообще это было бы странно: нужную для onATFOrder фильтрацию поддерживать не можете/хотите, а нужную для onATFOrderErr можете, хотите и будете...)
А если таки логику работы onATFOrderErr тоже поменяли, почему новую функцию с новым названием не сделали?
-
Насчет ATF - учтем. По поводу остального вам чуть позже другие разработчики ответят.
-
По данному случаю: в логах видно, что как только новые "планки" были получены от Биржи, именно они и стали использоваться при выставлении рыночных заявок.
-
Heller, а насчет onATFOrderErr прокомментируйте пожалуйста.
Klimov, а через какое время новые планки стали использоваться - доли секунды, секунды, десятки секунд?
-
13го декабря новые планки пришли в 14:03:51,
(Т.е. через 51 сек после выставления)
Обычно это случается где-то в промежутке от 14:01 до 14:02
Видимо, была какая-то задержка на Бирже
-
Heller, прокомментируйте плиз вопросы про OnATFOrderErr из моего второго поста
-
onATFOrderErr никак не изменит свое поведение - он работает корректно и пока мы не планируем ничего с ним сделать.
-
Хм, интересно, может, я неправильно представляю как она сейчас работает. Тогда на примере.
1. Допустим у меня 2 скрипта работают на 2-х графиках по одной бумаге (фьючерсу). Скрипт №1 выставил заявку, которая не исполнилась из-за ошибки. Внимание, вопрос: я получу вызов onARFOrderErr()
А) в обоих скриптах (так как функция и раньше, несмотря на название, была скорее аналогом onOrder, а не onATFOrder)
В) только в скрипте №1 (т.к. функция соответствует своему названию)
???
2. Более сложная история, на которой onATFOrder раньше переставал работать с соответствии со своим названием, а именно - переход через ночь/перезагрузку терминала. Итак вечером Скрипт №1 выставил условный стоп (при достижении такой то цены закрыть позицию по рынку). (Вечерняя сессия закончилась, сервер выключился, терминал потерял связь с сервером. Утром терминал по сути загрузился с нуля, перезагрузив конфигурацию экрана.) В первую же милисекунду торгов стоп сработал, но допустим (хотя через ночь такое вряд ли возможно) биржа опять опоздала на несколько секунд с разрешенными диапазонами цен, и фьючерсная заявка "по рынку" была отвергнута биржей, и я должен получить описание ошибки в onARFOrderErr. Внимание, вопрос: я получу вызов onARFOrderErr()
А) в обоих скриптах (так как функция и раньше, несмотря на название, была скорее аналогом onOrder, а не onATFOrder)
В) только в скрипте №1 (т.к. функция соответствует своему названию и идеально работает, несмотря на перезагрузку терминала)
С) ни в одном из скриптов (т.к., например, функция соответствует своему названию, а название аналогично onATF/ClientOrder, но функции onClientOrderErr нет)
???
-
Heller, ответьте пожалуйста на вопросы из моего предыдущегь сообщения
-
По первому вопросу ответ B, по второму вопросу ответ C. Он работает да, так же как onATFOrder. Мы конечно посмотрим как это возможно модифицировать, так как действительно при каких-то обстоятельствах сообщения об ошибках могут не доходить (хотя в этом случае все равно сработает onOrder и в нем будет установлен статус, описывающих суть ошибки).
-
А вот с этого места поподробнее. В каком месте я все равно получу статус, описывающий суть ошибки?
Вы хотите сказать, что произошли еще какие-то изменения при переходе с onATFOrder на onOrder: новые статусы появились или новые поля в возвращаемом хэше заявок (в хелпе по ATF про это ни слова)?
Просто в вышеописанном случае 13.12.2012 ATF в атф 1.16 ни onATFOrder, ни onClientOrder по соответствующей отвергнутой сервером заявке даже не вызвались. Хотя теоретически вернуть OS_DENIED (Отклонена брокером) они могли бы...
А про модификацию - модифицируйте, конечно - полное молчание скрипта - это плохо. Полагаю, раз вы не смогли ничего хитроумного сделать с функцией onATFOrder, чтобы ее сохранить - разумно повторить с onATFOrderErr тот же путь.
В терминах аналогии с предыдущим вопросом onATFOrder работает так: 1B, 2C (так же как Вы сказали работает сейчас onATFOrderErr. В итоге решили перейти на onOrder, который будет работать по принципу 1А, 2А. Соответственно, вероятно придется переходить с onATFOrderErr на 2А (что всяко лучше чем 2С), но безусловно хотелось бы сохранить 1B (ибо это лучше 1А)
-
Нет, изменений никаких больше не происходило. Я имел ввиду, что ошибку можно понять по статусу заявки, хотя в этом случае да, не будет описания текстового. Просто говорить об onATFOrderErr() довольно сложно из-за того, что ошибка может произойти в очень разных местах и обрабатываться она соответственно может по-разному.
Вообще функция onATFOrderErr() вызывается на данный момент лишь в двух случаях:
1) Если заявка немедленно отклоняется сервером Transaq (вызов при этом произойдёт все равно асинхронно).
2) Если заявка отклонена биржей и при этом Transaq помнит из какого скрипта она выставлялась (то есть не было перезагрузок, переходов через сессию и т. п.)
Тут конечно с ней неудобно работать в таком виде, мы всё же переделаем её в ATF 1.18.
-
я собственно про статус и спрашивал: в моем случае (13 декабря ) onOrder вызовется или нет (аналогично onATFOrder который не вызвался)?
-
onOrder вызовется, если сервер Transaq вначале примет заявку, а затем что-то с ней пойдет не так. Если же заявка будет сразу же отклонена, то onOrder не будет вызван, но гарантированно позовётся onATFOrderErr.
-
Ну если концепция такая, то текущая работа сервера в моем случае ей не соответствует. Ведь, если я правильно понимаю результаты раскопок по глюку, с которого стартовала эта тема: терминал послал рыночную заявку, сервер подставил в нее, известную ему на тот момент планку цены и !послал заявку на биржу. Но планка оказалась устаревшей и сервер биржи отказал. В этой ситуации сервер тразака должен был вернуть в статусе какой-нить статус связанный с отказом биржи, а он получается даже заявку с trid не создал, раз onATFOrder не вызвался.
-
P.S. плюсом onATFOrderErr является более подробное чем в статусе заявки описание ошибки. Но допустим при работе нескольких скриптов на одной бумаге сущемтвенно более ценной является возможность привязать ошибку к конкретному скрипту/попытке послать заявку - в этом случае лучше получать вызов onOrder с соотв. статусом.- тогда хоть как-то можно будет узнать (с использованием будущего поля комментарий или более извратно анализируя другие поля хэша заявки), чья заявка не прошла при одновременном их посыле двумя скриптами (здесь onATFOrderErr будет бесполезен, т.к. например в терминах выщеупоминаемых примеров не может обеспечить 2В).
-
В общем в ATF 1.18 обработка ошибок будет расширена следующим образом:
1) В onATFOrderErr будет добавлен еще один необязательный параметр - идентификатор заявки (правда это значение будет не всегда - если сервер немедленно заявку отклонит, то идентификатора никакого присвоено не будет; будет передано значение 0).
2) В струтуре заявки и стоп-заявки будет добавлено поле message - сообщение от сервера Transaq или биржи, если оно есть (это далеко не всегда так), с описанием ошибки.
-
Работа на ATF 1.18 закончена, работа с заявками и сделками переделана теперь следующим образом:
1. Операции trade_action:: а так же функции снятия заявок теперь работают в синхронном режиме и сразу возвращают либо номер транзакции, либо значение 0, и тогда ошибку можно считать функцией getLastErrorMessage(). Примерно это может выглядеть так:
var trnid = trade_action::buy(1, ::lots);
if (not trnid) {
signal::output("Заявка не выставлена: " + getLastErrorMessage());
}
if (not cancelAllOrders()) {
signal::output("Не удалось снять заявки: " + getLastErrorMessage);
}
И в случае с message:
function onOrder(var id) {
var order = getOrder(id);
if (order["message"]) {
signal::output("Ошибка выставления заявки: " + order["message"]);
}
}
Событие onATFOrderErr теперь вообще более не существует.
-
А в Интре когда будет обновление ATF до версии 1.18?
-
Ну Вы быстрые ребята! Исправляя неудобство с обработкой ошибок глобально поменяли идеологию работы с заявками :o Вы же где-то на форуме писали, что собираетесь делать по выбору пользователя - синхронная (для тех кому скорость не важна) или асинхронная обработка... Теперь пока trnid/ошибку не получишь от сервера дальнейшее выполнение кода (вызов калков) останавливается (при быстрых движениях на рынке их пройдет несколько сотен и цена уйдет заметно в то время пока скрипт никак не может это обрабатывать) - правильно я понимаю? Надеюсь только в текущем скрипте?
А код старый теперь срочно переписывать придется или можно по прежнему просто вызывать функцию ничему не присваивая ее результат?
-
Понимаю ваши опасения, попробую объяснить почему мы пошли на такой шаг.
Идея с асинхронным выставлением заявок, как мы выяснили, была не особо оправдана. Если интересны детали, то раньше алгоритм выставления заявок из ATF выглядел так:
1. Transaq посылает запрос к серверу, в котором получает порцию обновлений по всем необходимым ему данным (заявки, сделки, стаканы, статистика и прочее что использует клиент в данный момент).
2. Сразу после получения ответа от сервера синхронно и последовательно все эти данные раздаются во все открытые окна, в том числе в окна графиков и находящиеся там скрипты ATF.
3. Если пользователь выставляет заявку из скрипта ATF, то она не выставляется сразу, а откладывается в очередь.
4. Только после того как будут обработаны все данные во всех окнах, происходит последовательная отправка всех заявок на сервер Transaq.
5. Когда все заявки будут отправлены, Transaq отправляет серверу запрос на новые обновления и процесс начинается сначала.
Единственное, что сейчас поменялось - мы выкинули очередь и отправляем теперь заявки немедленно как того затребовал клиент. Задержки появиться сейчас действительно могут, но это будут лишь задержки интерфейсные - пока из скрипта ATF заявка не будет отправлена на сервер, не начнут обрабатываться новые данные в других окнах. Однако если говорить о скорости выставления заявок, то это на самом деле никак не влияет - всё равно пока не будет отправлена одна заявка, не могут начать отправляться другие заявки.
Ну то есть изначальное решение с асинхронной отправкой заявок на сервер казалось хорошим, но оно таким казалось лишь из-за того, что я ATF писал на высоком уровне, не вникая как это всё будет работать на уровне взаимодействия клиента и сервера. В ходе расследования ошибок, которые возникали с выставлением заявок и в основном при подробном анализе как работает onATFOrderErr на уровне взаимодействия клиент-сервер, стало понятно, что асинхронный подход на самом деле никак не помогает вообще, а лишь создаёт иллюзию какой-то эффективности.
onATFOrderErr был выкинут по причине того, что он всё равно работал из рук вон плохо и был неудовлетворителен: если вникать совсем в детали, то он закладывался на уже несколько версий как выкинутый механизм разграничения заявок и сделок робота и пользователя и тащил за собой кучу ненужного старого кода. При этом по факту полноценно использовать его было нельзя - при выставлении сразу многих заявок было невозможно понять в асинхронном режиме какая именно заявка не прошла, плюс, как выяснилось, о целом ряде ошибок onATFOrderErr вообще мог не сообщать. Закладываться на правильность его работы было явно опасно для клиентов, однако из примеров тех скриптов, которые присылали пользователи и которые я имел возможность посмотреть, стало понятно, что в таком виде этим событием всё равно никто не пользуется.
Собственно что касается изменения идеологии и обратной совместимости, то единственное действительно существенное изменение, которое может быть заметно для клиента - это отсутствие функции onATFOrderErr. Единственное, что придётся заменить в коде, чтобы вернуть старое поведение - это сделать замену
trade_action::...
на
if (not trade_action::...) {onATFOrderErr(getLastErrorMessage());}
и дописать в начало функции onOrder(var id) строчки
var order = getOrder(id);
if (order["message"]) {onATFOrderErr(order["message"]);}
Ну то есть если вы действительно интенсивно использовали функцию onATFOrderErr, то вам придётся немного изменить старый код, однако незначительно. Зато теперь при необходимости можно гораздо более эффективно контролировать возникающие ошибки и сразу иметь идентификатор выставляемых заявок и вообще использовать все эти новшества довольно удобным образом.
Присваивать результат выполнения trade_action::... куда-либо не обязательно - это по желанию только.
-
Спасибо большое за подробные разъяснения. Т.е. получается, что и раньше на шаге 4 - пока не получен ответ от сервера (или ок/trnid, или ошибка) по первой отправленной заявке, вторая заявка из очереди даже не отправлялась на сервер?
-
Да, именно так.
-
Понятно, спасибо. Действительно, получение trnid сразу - позволяет упростить очень многие вещи в коде, в частности, например, теперь можно легко, даже не используя поле brokerref, игнорировать в onOrder/onTrade чужие (не данного скрипта) заявки/сделки при работе нескольких скриптов по одной бумаге. (По крайней мере это относится к рыночным заявкам, для которых можно пренебречь вероятностью смены trnid на сервере за время их исполнения)
P.S. Раньше никто onATFOrderErr эффективно не использовал и в будущем поле message не будет, т.к. это почти невозможно делать без функций работы со строками. Может это и к brokerref относится, если кто-то будет туда текст писать, пытаясь максимально сохранить структуру кода из WealthLab например.
-
Я честно говоря плохо понимаю что вы имеете ввиду, когда говорите "без функций работы со строками". ATF имеет функции substr, strlen и конкатенацию, с помощью которых в общем-то можно реализовать всё что угодно (пусть и синтаксически это вероятно будет не очень удобно, но всё необходимое можно вынести в отдельные функции). Какие конкретно функции вам требуются ещё для удобной работы?
-
Да, каюсь. Извините. Просто существование/появление substr я и не заметил. Действительно с этим набором можно все что угодно сделать, но для удобства неплохо бы иметь еще функцию поиска подстроки в строке. От двух аргументов - чтобы возвращала номер позиции начала подстроки или ноль, если подстрока в строке не найдена (тогда эту функцию можно будет и в if'ах использовать как аналог str.Contains())
Может не обязательно даже в атф, а в виде кода в раздел примеры. Конечно это несложный цикл, но с учетом того, что break появится лишь в 1.18, и того что возможно не всем его будет легко написать - полезно было бы иметь оптимальный по быстродействию код от разработчиков
-
Ок, в 1.19 сделаем.
-
А в чем смысл возвращать в strfind(str1, str2) "-1", если не найдено? Ведь "-1" не воспринимается как false... Лучше возвращать 0, хоть это может и менее традиционно. 0-й позиции все равно не существует, и можно будет без лишних действий и весьма интуитивно использовать в виде if(strfind(str1, str2)) в смысле if(str1.Contains(str2)).
-
Позиции в строке отсчитываются с нулевой. То есть:
strfind("abc", "a") == 0
strfind("abc", "b") == 1
strfind("abc", "x") == -1
Возврат -1 функцией поиска подстроки - стандартная практика в большинстве языков программирования (например, в C++ это strstr, в Python - str.find).
Правда, как выяснилось не так давно, в старых версиях strfind некорректно работает, в последней сборке уже должно быть это исправлено.
-
Понятно. Ладно, от того, кто к результату добавит +1 - вы внутри или я в коде - скорость выполнения, думаю,не изменится.
Кстати, спасибо, Вы в 1.19 еще много новых текстовых полезностей добавили.
-
Мне тут в прошлую пятницу чудовищно повезло. У меня стоп-сигнал возник на последнем тике/калке торговой сессии. Соответственно заявка (по рынку), которой я закрывал позицию не прошла. Но, к сожалению, никакого сообщения об ошибке я не получил, хотя у меня финамовская 1.18 (305.07 rev.51), где уже должна была быть реализована новая идеология работы с ошибками и сделано у меня как рекомендовано в сообщениях 19 и 22 этой темы. Торговал фьюч SBRF-9.13.
На всякий случай схематично мой код:
...
function onATFOrderErr(var str)
{
file_ATFlog.writeLn(getFormattedDateTime(getServerTime())+" trades="+trades+" Ошибка выставления заявки: "+str);
}
...
function calc()
{
...
if(условие стопа)
{
...
var OrdrHash = new_object("hash");
OrdrHash["quantity"] = amount; OrdrHash["operation"] = OP_SELL; OrdrHash["brokerref"] = ROBOT_ID;
var ordr_trnid = trade_action::transactMultiple(OrdrHash);
if (not ordr_trnid) {onATFOrderErr(getLastErrorMessage());
...
file_ATFlog.writeLn(getFormattedDateTime(getServerTime())+"; "+trades+"; Условие стопа выполнено. Подана заявка на закрытие позиции");
...
}
}
...
Ну то есть сообщение в логе "23:50:03 14.06.13; 137; Условие стопа выполнено. Подана заявка на закрытие позиции" присутствует, а до него (а также и после него) никакого сообщения об ошибке от function onATFOrderErr(var str), даже пустого - нет, то есть эта функция не вызывалась. Т.е. ненулевой trnid получается был присвоен??? Но в окне заявок в терминале этой заявки нет. OnOrder тоже судя по логу вплоть до момента потери соединения с сервером брокера не вызывался. (В нем у меня тоже кстати стоит: if(order["message"]){onATFOrderErr(order["message"]);})
-
2 ddd323
В похожей ситуации мне вернуло ошибку (10003) Сейчас эта сессия не идет.
Сообщение было получено из функции onStopOrder(var id) поле hStopOrder["message"]
Статус стоп-заявки SS_REJECTED.
Я НЕ использую onATFOrderErr(var str)
Цена на последних секундах перед вечерним клирингом дошла до sl_activationprice. В стоп-заявке используется sl_guardtime.
Версия Транзака и брокер те же.
Надеюсь, Вам поможет эта информация...
-
Спасибо, как практическая идея что стоп-заявки работают надежнее обычных - может и поможет. Но штатная onATFOrderErr в 1.18 уже не должна работать. А ошибку из поля message и мой код через самостоятельную передачу текста в onATFOtderErr должен был записать в лог. Но у меня onOrder в отличие от Вашего onStopOrder не вызвался. Вот я и призываю разработчиков и Heller'a в частности искать ошибки в коде или архитектуре или объяснить мне ЧЯДНТ.
bugem, у Вас какая версия клиента?
-
bugem, у Вас какая версия клиента?
Ver. 5.05.305.07, rev.51, ATF 1.18
-
Кажется, начинаю догадываться.
Heller, trade_action в случае ошибки честный 0 возвращает или как сейчас в атф часто слелано NULL/полную пустоту?
Если пустоту, то все понятно. Любые логические операции над ней включая отрицание дают ложь, т.е. not ordr_trnid тоже ложь и поэтому onATFOrderErr не вызвался.
-
ddd323, извините что за Heller'а отвечаю. Но вот это то:
if(order["message"])
{
onATFOrderErr(order["message"]);
}
Вам должно было вернуть описание ошибки. Значит сервер не посчитал данную ситуацию ошибочной.
-
Так мне Heller никогда не ответит ;)
Все правильно говорите, и у меня в коде даже есть точно такой же фрагмент. Но этот механизм информирования об ошибках работает, когда заявка уже обрела свой id и дошла до сервера (например, давно дошла, как в вашем случае со стоп-заявкой). Моя проблема лежит очевидно на другой фазе - на этапе попадания заявки на сервер. Т.к. у меня заявка до сервера не дошла и у меня onOrder (внутри которого и стоит приведенный Вами фрагмент кода) по ней не вызывался.
Т.е. у меня не сработал - другой механизм информирования об ошибках, а именно:
if (not ordr_trnid) {onATFOrderErr(getLastErrorMessage());
Собственно, поэтому я и прошу Heller'a прокомментировать мою ситуацию, а теперь еще и мою гипотезу (что причина это возврат функцией trade_action в случае ошибки, не нуля, а "NULL". А. к сожалению, вопреки ожиданиям сейчас в атф "not NULL" = FALSE)
-
Подозреваю, что
var ordr_trnid = trade_action::transactMultiple(OrdrHash);
ordr_trnid в таком варианте и должен возвращать NULL, т.к. заявка не дошла до сервера. В документации, в примере с описанием trnid код выглядит несколько иначе
var trnid = 0;
trnid = trade_action::transactMultiple(OrdrHash);
if(!trnid) {signal::outputMultiple(getLastErrorMessage());}
Как видите 0 присваивается не сервером, а непосредственно в коде.
Хотя, где то в форуме Heller объяснял что a = 0 = "" = NULL = false все однозначно должно в if(not a) возвращать ИСТИНА
Я trnid транзакций записываю в логи, как раз что бы потом можно было разобраться
Есть еще один нюанс. Условная заявка рождает лимитированную (по наступлению условия) и выставляется в стакан (если цена рыночная, то по цене противоположной планки). НО! если это произошло вне сессии, она в стакан не попадает, а отклоняется биржей. А вот возвращает ли биржа какое нибудь сообщение, сказать затрудняюсь, вообще по уму должна.
-
Если бы if(not NULL) возвращало бы "истина", то у меня в записалась бы ошибка в лог, а в документацию было бы бессмысленным вставлять предварительное присваивание настоящего нуля: var trnid = 0;
(Странно, кстати, в этой концепции еще то, что настоящий ноль не затирается NULLом в случае ошибки в коде из документации)
-
А есть ли в ATF вообще значение NULL?! Это уже вопрос к Heller'у...
т.к. вот такой пример
var a;
var b = 1;
if(!a)
{
var c;
c = 1 + a;
b = b * a;
signal::outputMultiple("a = " + a + "; b = " + b + "; c = " + c);
}
выдает нам
a = 0; b = 0; c = 1
a = 0; b = 0; c = 1
a = 0; b = 0; c = 1
a = 0; b = 0; c = 1
-
некий "NULL"/пустая ссылка в атф точно есть. Экспериментальный факт. Просто в неинициализированных переменных с вероятностью 99% лежит обычный честный ноль (обычная ссылка на некую область памяти). Это тоже экспериментальный факт - Ваш пример тому подтверждение.
-
Мне сложно ответить почему не вывелось сообщение об ошибке - честно говоря не знаю. То что транзакция была принята сервером Transaq - это железный факт, иначе действительно не было бы возвращено trnid. Что могло случиться дальше не очень понятно - я попробую выяснить это у других разработчиков и если что-то станет ясно, то дам ответ (ATF лишь отдаёт сообщение об ошибке, полученное от внешнего интерфейса, поэтому я могу просто не знать какие-то детали этого механизма).
Что касается типа NULL, то да, оно есть, но фактически оно эквивалентно нулю или false или пустой строке. В таких частных случаях многое зависит от конкретной операции, которую выполняет пользователь над переменной - где-то они и отличаться, но дать конкретную жесткую классификацию тут сложно. Это такой пограничный случай, который логически во всех случаях по большому счету имеет один и тот же смысл, хотя, конечно, какие-то тонкие примеры на различия наверняка можно привести. Другое дело, что мне не может придти в голову практический смысл этого. На такие тонкие вещи я бы ни в коем случае не стал бы закладываться.
Торговые операции всегда возвращают число - если номер не присвоен, то это честный ноль.
-
Heller, а что в моем посте #32 заставило Вас думать, что trnid был возвращен? Если он был возвращен, почему тогда onOrder по этой заявке не был вызван?
-
Heller, а что в моем посте #32 заставило Вас думать, что trnid был возвращен? Если он был возвращен, почему тогда onOrder по этой заявке не был вызван?
Строчка
if (not ordr_trnid) {onATFOrderErr(getLastErrorMessage());
должна была бы сработать, если бы ordr_trnid был равен чему-то, отличному от нуля.
-
Хм. Ну то есть Вы абсолютно уверены, что trade_action в случае ошибки возаращает честный 0. И Вам легче поверить, что по заявке, которой сервером был присвоен id, дошедший до терминала и возвращенный из trade_action, не был вызван onOrder и она не отобразилась в окне заявок терминала? :o
Ну допустим терминал жестоко подвис строго в нужную секунду, но на следующий день при запуске (или через несколько секунд после "отвиса"**) он же должен был по идее подгрузив заявки предыдущего вечера показать эту неисполненную с присвоеным trnid. Но не показал...
* а после этого возвращения, судя по логу, было выполнено еще как минимум десяток строк кода
** Тотального зависа терминала не было, т.к. судя по логам моей надтерминальной обвязки, которая пишет состояние окон заявок и сделок терминала в конце дня в 23.52 терминал не был зависшим, реагировал на нажатие мыши, менял окна, писал данные из окон к буфер обмена и пр.)
-
Да, есть полная уверенность, что если id присваивается сервером, то он отдаётся. Все trade_action-ы - это синхронные запросы к серверу, выполнение кода не пойдёт дальше, пока от сервера не будет получен ответ.
Пока не очень понятно почему именно onOrder не сработал - я думаю как временное решение для большеё надежности можно попробовать на подобные случаи сохранять куда-либо значение trnid и потом проверять уже статус заявки через getOrder. Но это на случай каких-то подобных неполадок.
-
Попробую в ближайшее время повторить эту ситуацию (подачи заявки после окончания сессии) с личным присутствием и логированием получше.
А пока другой глюк в ту же тему.
Скрипт называется "tradeaction"
static ordr_trnid=1;
function onNewCandle()
{
signal::outputMultiple("Начало процедуры onNewCandle. ordr_trnid="+ordr_trnid);
var OrdrHash = new_object("hash");
OrdrHash["quantity"] = 1;
OrdrHash["operation"] = OP_BUY;
OrdrHash["price"] = 0; // подаем заявку с заведомо неверной ценой
ordr_trnid = trade_action::transact(OrdrHash);
signal::outputMultiple("ordr_trnid="+ordr_trnid);
if (ordr_trnid)
{
signal::outputMultiple("ordr_trnid=TRUE");
}
else
{signal::outputMultiple("ordr_trnid=FALSE");}
signal::outputMultiple("Конец процедуры onNewCandle");
}
На новой свече получаем окно "Ошибка приложения Транзак" с предложением прислать вам лог и дамп. В логе пусто (т.е. по факту ошибки ничего не дописалось). Дамп - если надо пришлю. (Но по идее вы и сами его сумеете получить на своем терминале.)
В окне вывода АТФ получаем:
Начало процедуры onNewCandle. ordr_trnid=3
tradeaction: Указана не верная цена
Но скрипт в принципе продолжает работать. На каждой новой свече в "окно вывода АТФ" допишется
"Начало процедуры onNewCandle. ordr_trnid=3" (и только это, т.е. без "tradeaction: Указана не верная цена"), а также будет создан новый дамп и новое аналогичное окно "Ошибка приложения Транзак".
Ну то есть вылетаем из trade_action, да так, что ничего оттуда не возвращается, а оставшиеся операнды в onNewCandle не исполняются. Но сам скрипт продолжает жить и реагировать на события типа новой свечи.
P.S. Получил все это на Интре. (1.18)
-
Heller, чего скажете то про этот новый баг? Удалось воспроизвести у себя?
-
Да, есть ошибка, правлю.