Владислав (Все сообщения пользователя)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Цитата
Nikolay написал:
Если нет ответа транзакции (т.е. ответа шлюза биржи), то, скорее всего, транзакция не прошла дальше сервера брокера. А значит есть ответ и ошибка самого метода sendTranscation. Где тоже необходимо проверять - ушла ли транзакция на биржу.
При попытке отправки транзакции в неторговое время, sendTranscation возвращает ошибку: Ошибка снятия заявки:  Указанная транзакция по указанному классу не найдена: "SPBFUT".

Нашел старые логи по которым видно, что c 08:50 до 08:59 идет аукцион открытия.
Код
[28.01.2025 08:50:33]: status: торгуется
[28.01.2025 08:59:42]: status: приостановлена
[29.01.2025 08:50:40]: status: торгуется
[29.01.2025 08:59:28]: status: приостановлена
[30.01.2025 08:50:38]: status: торгуется
[30.01.2025 08:59:32]: status: приостановлена
[31.01.2025 08:50:36]: status: торгуется
[31.01.2025 08:59:34]: status: приостановлена
[03.02.2025 08:50:38]: status: торгуется
[03.02.2025 08:59:35]: status: приостановлена
[04.02.2025 08:50:41]: status: торгуется
[04.02.2025 08:50:41]: trading_status: открытие
[04.02.2025 08:50:41]: trading_phase: аукцион открытия
[04.02.2025 08:59:09]: status: приостановлена
[04.02.2025 08:59:09]: trading_status: закрыта
[04.02.2025 08:59:11]: trading_phase: закрыта
[05.02.2025 08:50:35]: status: торгуется
[05.02.2025 08:50:35]: trading_status: открытие
[05.02.2025 08:50:35]: trading_phase: аукцион открытия
[05.02.2025 08:59:45]: status: приостановлена
[05.02.2025 08:59:45]: trading_status: закрыта
[05.02.2025 08:59:49]: trading_phase: закрыта

Моя ситуация возникла вчера в 08:59:21, тогда еще был аукцион открытия, поэтому sendTranscation не выдал ошибку.

Поэтому мой вопрос остается открытым)
Цитата
Владислав написал:
Как роботу понять что произошла ошибка снятия конкретной заявки, если колбеки не вызываются?
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Код
function KillOrder (sec_info, order_num)
   local transaction = {
      ["TRANS_ID"]      = '1', 
      ["ACTION"]      = "KILL_ORDER",
      ["CLASSCODE"]      = sec_info.class_code,
      ["ORDER_KEY"]      = tostring(order_num)
   }
   local result = sendTransaction(transaction)
   if result == '' then return order_num end
   for key, val in pairs(transaction) do result = result..'\n'..key.."  =  "..tostring(val) end
   error("\nОшибка снятия заявки: "..result)
end
Проверка осуществляется, ошибки нет, робот продолжил работу.
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Я не предлагаю использовать OnTransReply для проверки состояния сессии.
OnTransReply вызывается в том числе когда мы выставляем заявку и получаем сообщения:
"Сейчас эта сессия не идет"
"Идет пром. клиринг, нельзя совершать торговые операции"
"Инструмент недопустим в аукционе открытия"
"Торги по этому финансовому инструменту сейчас не проводятся"
"Превышен лимит отправки транзакций для данного логина"
...
И робот видит этот вызов и что он произошел на конкретную транзакцию и дальше обрабатывает эту ошибку.

Сейчас речь идет о том, что при попытке снять заявку вызов OnTransReply не произошел и робот ждет ответ на снятие, но в ответ - ничего. Только сообщение в таблице сообщений которое он не видит.
И нам остается проверять состояние сессии и делать предположение о том, что заявка не снята потому-что попытка снятия отклонена с ошибкой "Сейчас эта сессия не идет."
А если вызов OnTransReply происходил еще и при снятии, то в робота не пришлось бы включать предположения, он мог бы обработать конкретную ситуацию.
Цитата
Nikolay написал:
Подавать их необходимо когда торги по инструменту проводятся.
Цитата
Владислав написал:
Мы можем проверять состояние сессий перед отправкой транзакции, но даже так мы будем натыкаться на ошибки транзакций в первые секунды неторгового времени.
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Цитата
paluke написал:
А sendTransaction ничего не возвращает?
Не возвращает
Цитата
Ziveleos написал:
А зачем Вы отправляете транзакцию, если сессия в это время закрыта?
Транзакция отправляется автоматически в ответ на срабатывание заявки.
Заявка сработала в 08:59:21, на что робот среагировал и снял оставшуюся заявку, после чего получил ошибку, которая отобразилась в таблице сообщений.
Цитата
Ziveleos написал:
Если нет OnTransReply и  сессия закрыта, какой вывод должен сделать робот?
Вывод робот делает, но это как-то костыльно. А если это не ошибка, а долгая задержка ответа или косяки на сервере. Хотелось бы получать конкретный ответ, тем более, учитывая что в таблицу сообщений он приходит.

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

На данный момент вопрос в том, как роботу получить ответ Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет." который отображается в таблице сообщений. Если никак, то нужно реализовать в QUIK такую возможность т.к.  OnTransReply вызывается в ответ на выставление и было бы логично вызывать его в ответ на снятие.  
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Это не решение. Я отправляю транзакцию и хочу получить на нее ответ, чтобы продолжить работу. Пока ответа нет, робот не может выставлять новые заявки. Где роботу взять этот ответ?
Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
 
Добрый день!
При попытке снять заявку возникла ошибка: Ошибка снятия заявки. [GW][3] "Сейчас эта сессия не идет."
При этом ни OnOrder, ни OnTransReply небыли вызваны.
Как роботу понять что произошла ошибка снятия конкретной заявки, если колбеки не вызываются?
Ошибка при совершении операции "Скорректированное значение НПР1 -65572.12 (RUB) меньше 0"
 
Столкнулся с той-же проблемой. Решил получением необходимых полей из кармана транзакций.
Создать окно - Все типы окон - Карман транзакций - ETF - Вод заявки - Добавить все - Да
В кармане - ПКМ - Положить в карман - ETF - Ввод заявки - Выполнить - Вводим значения - Да
В кармане нажимаем на транзакцию ПКМ - Сохранить в tri-файл - Сохраняем
Открываем файл в редакторе кода и копируем поля в вашу функцию отправки транзакции.

В моем случае так:
Код
function SendOrder (sec_info, quantity, price)
    local transaction = {
        ["TRANS_ID"]                        = getTransId(),
        ["Торговый счет"]                   = sec_info.account,
        ["CLASSCODE"]                       = sec_info.class_code,
        ["Режим"]                           = sec_info.class_code,
        ["Инструмент"]                      = sec_info.sec_code,
        ["Примечание"]                      = sec_info.client_code,
        ["Цена"]                            = tostring(rounding(price, sec_info.scale)),
        ["Лоты"]                            = tostring(rounding(math.abs(quantity))),
        ["К/П"]                             = quantity > 0 and "Купля" or "Продажа",
        ["ACTION"]                          = "Ввод заявки",
        ["Тип"]                             = "Лимитная",
        ["Тип по цене"]                     = "По разным ценам",
        ["Тип по остатку"]                  = "Поставить в очередь",
        ["Тип ввода значения цены"]         = "По цене",
        ["Назначение заявки"]               = "По умолчанию",
        ["Тип события активации заявки"]    = "Обычная заявка",
        ["Объем заявки"]                    = "0.0",
    }
    local result = sendTransaction(transaction)
    if result == '' then
        return tonumber(transaction.TRANS_ID)
    end
    for key, val in pairs(transaction) do result = result..'\n'..key.."  =  "..tostring(val) end
    error("\nОшибка транзакции: "..result..'\n'..debug.traceback())
end

Хотя до это момента, был клиент который тоже заказывал для ETF и у него работало с таким набором полей: "TRANS_ID", "CLASSCODE", "SECCODE", "ACCOUNT", "OPERATION", "QUANTITY", "PRICE", "ACTION", "CLIENT_CODE"
FUTSPREAD сделки за планкой
 
Цитата
uuh написал:
Не то что слышал, а лично видел.  При этом система мне так же не давала ставить заявки за планкой. Но кто-то их туда точно ставил и сделки за планкой проходили.
Я заметил, что если до клиринга выставить заявку, а после клиринга планка сместится, то наша заявка может остаться за планкой. Таким образом контрагент может свести нашу заявку с заявками из стаканов фьючерса, при том, что она будет за планкой.  
FUTSPREAD сделки за планкой
 
Здравствуйте. Несколько раз встречал информацию, что на календарных спредах, роботы выставляли заявки за планкой.  
Я пробовал выставлять вручную и через lua, итог один "Цена сделки вне лимита", при этом видно, что за планкой проходят сделки.
Буду благодарен, если подскажете почему так происходит или где можно найти об этом информацию ?
И если работаете с данным классом инструментов, то какая у Вас логика работы с планкой ?
Как создать свою форму (окно) и разместить на ней элементы формы (чекбокс, список, кнопка, поле для ввода и тд), Создание новых элементов интерфейса
 
Цитата
swerg написал:
А вы какой версией терминала пользуетесь? У вас точно Lua5. 1 в терминале?
Lua 5.1 в терминале нет, только 5.4.1 и 5.3.5. Получается, что использование iuplua в новых версиях терминала невозможно ?  
Как создать свою форму (окно) и разместить на ней элементы формы (чекбокс, список, кнопка, поле для ввода и тд), Создание новых элементов интерфейса
 
Прошу прощенья, архив скачивал не 32 битный, а 64. При скачивании 32 битного, появлялась ошибка D:\DEVELOPMENT\Exchange\Роботы\iup\iuptest.lua:1: %1 не является приложением Win32.
Как создать свою форму (окно) и разместить на ней элементы формы (чекбокс, список, кнопка, поле для ввода и тд), Создание новых элементов интерфейса
 
Здравствуйте. Подскажите пожалуйста, что делать с данной ошибкой ?
С сайта https://sourceforge.net/projects/iup/files/3.18/Tools%20Executables/Lua51/ скачал архив iup-3.18-Lua51_Win32_bin.zip. Из этого архива, в папку с квиком скопировал файлы iup.dll и iuplua51.dll.
Создал скрипт с кодом:

Скрытый текст

При запуске скрипта в терминале возникает ошибка: ACCESS VIOLATION at address 00007FFDB6692850
Что делать ?
Принципы написания скриптов, Разделять или объединять?
 
Цитата
Владимир написал:
Про несколько скриптов я и вообще говорить не хочу - это алгоритмический идиотизм
Вы различные стратегии в одном скрипте реализуете ?
Принципы написания скриптов, Разделять или объединять?
 
Владимир, nikolz,  
Благодарю за советы. На примере кода представленного Антоном выше, сделал тесты скорости получения ответа на транзакцию. По итогу думаю, что в рамках нескольких скриптов действительно смысла с заморочками нет. Тем более если скрипт работает с различными таблицами в QUIK. В моем случае, после отправки транзакции, происходит расчет прибыли от совершенной сделки, запись этой сделки в файл и т.п. Для того, что бы исключить возможные несостыковки, связанные с длительностью поступления данных в таблицу сделок и таблицу поз. по. кл. счетам, скрипт делает паузу в 1000мс. При такой реализации программы, смысла в заморочках точно нет.
Но если речь идет о большом количестве скриптов, в которых все завязано на коллбеках, смысл думаю что есть.

Код для тестирования скорости:
Скрытый текст

Результаты тестирования:
Скрытый текст
Принципы написания скриптов, Разделять или объединять?
 
Цитата
nikolz написал:
Существующая структура QLUA имеет существенный недостаток.
Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах.
В итоге получается дублирование одних и тех же действий многократно.
Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются,
а скрипты могут запускать функции друг у друга и получать данные из других скриптов..
-------------------------
В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
Цитата
nikolz написал:
Тот механизм, о котором я написал, позволяет очень просто делать много роботов  по различным алгоритмом для одного инструмента.
Колбеки не дублируются в скриптах  
Каждый колбек существует в своем скрипте и вызывается всего один раз квиком для получения данных вне зависимости от числа роботов.
Роботы получают требуемые данные от этого скрипта. т е потоки синхронизируются и обмениваются данными , а также чтобы не дублировать код, могут запускать функции других скриптов через механизм колбеков между скриптами.
Сравнительно просто в этом варианте отдавать данные совершенно независимым процессам.
Здравствуйте. Подскажите пожалуйста, как реализовать подобный механизм ?
Повторное выставление меток на график при смене инструмента
 
Здравствуйте. Прикрепляю видео с демонстрацией данной ошибки в терминалах версии 9.2.3.15 и 8.13.1.16.
https://youtu.be/Glkn021STHM
Повторное выставление меток на график при смене инструмента
 
Скрипт тестировался в "боевом" терминале версии 9.2.3.15
и в демо терминале версии 8.13.1.16
И там и там была данная ошибка
Повторное выставление меток на график при смене инструмента
 
Здравствуйте.
Написал индикатор, добавляющий на график метку с номером последней свечи.
После добавления индикатора на график, изменении его свойств в настройках графика и смене тайм-фрейма ошибок не происходит. Но при смене инструмента (график привязан к таблице "Текущие торги"), на графике появляется дополнительная мистическая метка. Функция AddLabel не возвращает номер этой метки, ее нельзя удалить вручную (перетаскивать по графику можно) и с помощью функции DelLabel, но при этом она удаляется функцией DelAllLabels.

Добавляем индикатор на график и меняем инструмент. На графике появится новая метка и поверх нее еще одна мистическая. Мистическую перетаскиваем в сторону, заходим в настройки индикатора, меняем параметр "Отступ от максимума" (или просто меняем тайм-фрейм) и видим, что мистическая метка остается на месте а вторая изменяется.

По умолчанию, для удаления меток при их перерисовке, индикатор использует функцию DelLabel. Но, если в поле параметра "Удаление всех меток" поставить значение "да [да/нет]", то индикатор будет использовать функцию DelAllLabels и в таком случае, при изменении настроек индикатора или смене тайм-фрейма, мистическая метка будет удаляться.

Если я правильно понял, то данная проблема уже обсуждалась и была решена (topic3532)


Код
-- [[ Индикатор добавляет на график метку с номером последней свечи ]]--

-- Заметки:
-- GetLabelParams возвращает таблицу с названиями параметров в нижнем регистре, тогда как эти параметры в функции AddLabel задаются в верхнем регистре.
-- GetLabelParams возвращает значения всех параметров в строковом виде, несмотря на то, что часть параметров типа number.
-- getDataSourceInfo().class_code работает только после вызова OnChangeSettings()
-- getNumCandles() и getParamEx() работают только после вызова OnCalculate()

Settings = {}
Settings.Name                   = "- IndexCandleFF"
Settings["Отступ от максимума"]    = 100
Settings["Идентификатор графика"]    = "one_graph"
Settings["Удаление всех меток"]    = "нет [да/нет]"

TableLabel       = {}
index_old       = 0    -- Функция OnCalculate вызывается несколько раз для каждой свечи. index_old нужен для того, что бы не захламлять таблицу TableLabel.
flag_error       = true   -- В случае ошибки параметров в настройках индикатора, предотвращает повторный вывод сообщения об ошибке и добавление меток на график.
flag_first      = true  -- Предотвращаем повторный вызов OnChangeSettings.
flag_init      = false -- Флаг для корректной работы getParamEx и getNumCandles

del_labels      = string.match(Settings["Удаление всех меток"], "(.*) .*")
interval       = 0

function isChartExist (chart_name) -- Возвращает true, если график с идентификатором "Идентификатор графика" существует, иначе false
   if chart_name == nil or chart_name == '' then return false end
   local n = getNumCandles (chart_name)
   if n == nil or n < 1 then return false end
   return true
end

function place_label(index)
   PrintDbgStr("place_label")
   local positionY = H(index) + Settings["Отступ от максимума"]
   local DateTime = T(index)

   local Y = DateTime.year
   local M = DateTime.month  if #tostring(M) == 1 then M = '0'..M end
   local D = DateTime.day    if #tostring(D) == 1 then D = '0'..D end
   local HO = DateTime.hour  if #tostring(HO) == 1 then HO = '0'..HO end
   local MI = DateTime.min   if #tostring(MI) == 1 then MI = '0'..MI end
   local SE = DateTime.sec   if #tostring(SE) == 1 then SE = '0'..SE end

   label_params = {}
   -- label_params.IMAGE_PATH         = getScriptPath() .. "\\1.bmp"
   label_params.YVALUE              = positionY         -- Значение параметра на оси Y, к которому будет привязана метка
   label_params.DATE                = Y..M..D             -- Дата в формате «ГГГГММДД», к которой привязана метка
   label_params.TIME                = HO..MI..SE        -- Время в формате «ЧЧММСС», к которому будет привязана метка
   label_params.TRANSPARENCY        = 0                 -- Прозрачность метки в процентах. Значение должно быть в промежутке [0; 100]. Применяется только для картинки.
   label_params.FONT_FACE_NAME      = "Arial"           -- Название шрифта (например «Arial»)
   label_params.FONT_HEIGHT         = 8                 -- Размер шрифта
   label_params.TEXT                = tostring(index)   -- Если подпись не требуется то оставить строку пустой ""
   label_params.HINT                = "Index candle"   -- Текст всплывающей подсказки
   
   label_params.R                       = 0      -- Красная компонента цвета в формате RGB. Число в интервале [0;255]        
   label_params.G                       = 0      -- Зеленая компонента цвета в формате RGB. Число в интервале [0;255]        
   label_params.B                       = 0      -- Синяя компонента цвета в формате RGB. Число в интервале [0;255]        
   label_params.TRANSPARENT_BACKGROUND  = 1 
    
   table.insert(TableLabel, AddLabel(Settings["Идентификатор графика"], label_params)) -- Добавляем метку и запоминаем ее ID
end

function Init ()
   PrintDbgStr("Init")
   flag_init = false
   return 1
end

function OnDestroy () 
   PrintDbgStr("OnDestroy")

   if del_labels == "да" then 
      DelAllLabels(Settings["Идентификатор графика"])
   else
       -- for label_id = 1, #TableLabel do
       --    DelLabel(Settings["Идентификатор графика"], TableLabel[label_id])
       -- end

      for label_id = 1, 100000 do                                       -- 100000 - максимально возможное количество меток на графике.
         local L = GetLabelParams(Settings["Идентификатор графика"], label_id)   -- table or nil
         if L ~= nil then  
            if L.hint == "Index candle" then 
               DelLabel(Settings["Идентификатор графика"], label_id)
            end             
         end
      end
   end
   index_old = 0
end

function OnChangeSettings()
   -- Функция вызывается при редактировании свойств индикатора после нажатия кнопок «Применить» или «OK».
   PrintDbgStr("OnChangeSettings")

   if flag_init then  -- При переходе на другой тайм-фрейм, сначала вызывается функция Init, затем OnChangeSettings затем OnCalculate, но для работы функций getParamEx и getNumCandles необходимо, что бы сначала была вызвана OnCalculate, поэтому, сначала игнорируем автоматический вызов OnChangeSettings, а затем после того как вызовется OnCalculate, вызываем ее сами.
      PrintDbgStr("OnChangeSettings_Body")
      del_labels = string.match(Settings["Удаление всех меток"], "(.*) .*")

      --[ Исключение ошибок в настройках графика ]--
      if not isChartExist(Settings["Идентификатор графика"]) then 
         if flag_error then
            message("Ошибка значения в поле: \"Идентификатор графика\"")
            flag_error = false
         end
      elseif del_labels ~= "да" and del_labels ~= "нет" then 
         if flag_error then
            message("Ошибка значения в поле: \"Удаление всех меток\"")
            flag_error = false
         end
      else flag_error = true
      end

      --[ Удаление меток с графика ]--
      if flag_error then 
         OnDestroy()
      end

      --[ Задаем отступ для метки ]--
      local sec_code = getDataSourceInfo().sec_code
      local class_code = getDataSourceInfo().class_code
      local step = getParamEx(class_code, sec_code, "SEC_PRICE_STEP").param_image         -- Минимальный шаг цены
      local scale = tonumber(getParamEx(class_code, sec_code, "SEC_SCALE").param_image)   -- Точность цены.

      if scale == nil then 
         error("local ER: Для корректной работы индикатора необходимо установить соединение с сервером !")
      else
         if scale > 0 then 
            step = tonumber("0."..step:match(",(.*)")) -- Заменяем запятую на точку и преобразуем строковый формат в числовой.
         end
         Settings["Отступ от максимума"] = step * Settings["Отступ от максимума"]
      end

      flag_first = false -- Предотвращаем повторный вызов OnChangeSettings.
      interval = getDataSourceInfo().interval
   end 
end


function OnCalculate (index)
   -- Если изменился тайм-фрейм. При изменении тайм-фрейма необходимо удалить старые метки. 
   if interval ~= getDataSourceInfo().interval then
      flag_init = true 
      PrintDbgStr("interval")
      OnDestroy()
      interval = getDataSourceInfo().interval 
   end

   if index > index_old then 
      if flag_first then 
         PrintDbgStr("flag_first") 
         OnChangeSettings() 
      end
            
      --[ Добавление меток на график ]--
      if flag_error then
         if index == Size() then 
            place_label(index)
         end
      end
      index_old = index 
   end
   return 
end
Страницы: 1
Наверх