limit_kind в таблице depo_limit

Страницы: 1
RSS
limit_kind в таблице depo_limit
 
Сегодня на тестовом контуре в таблице depo_limit получил такое:

limit_kind = 20250116

Это что? Ясно что дата. Но с какой такой... Я не слышал о новом режиме торгов в виде даты. Есть Т0, Т+1, Т+2, TOD, TOM и новое Т365, отображаемое в терминале Тх.
 
Nikolay, добрый день.


Это результат перехода тестового сервера на ведение позиций по календарным датам. limit_kind = 20250116 это тоже, что и limit_kind = 0.
 
Цитата
Andrey Golik написал:
Nikolay, добрый день.


Это результат перехода тестового сервера на ведение позиций по календарным датам. limit_kind = 20250116 это тоже, что и limit_kind = 0.
Сообщение в терминале увидел. Вот оно, чтобы было понятно остальным:

Здравствуйте.С 16 января сервер QUIK Junior переведен на современную схему ведения позиций - по календарным датам. Если ранее каждой позиции соответствовал код расчетов (T0, T1, T2), то теперь - конкретная дата.
Например, если сегодня 16.01.2025, значит код расчета T0 соответствует дате расчета 16.01.2025, код T1 - 17.01.2025 и так далее. Ожидается, что в будущем на эту схему перейдет большинство брокерских компаний. Кроме того, теперь расчеты по всем инструментам на сервере происходят по схеме T+1, что соответствует режиму реальных торгов на Московской Бирже.
В связи с этим в таблицах с позициями по инструментам и деньгам следует заменить параметр "Срок расчетов" на "Дата расчетов". В таблице "Состояние счета" вместо кодов расчета теперь подставляется конкретная дата.


Правда это, конечно, несколько неожиданно, не говоря уже о каких-то формальных документах. Спрашивается а как теперь для инструментов, торгуемых в разных режимах определять позицию. До этого можно было найти максимальный limit_kind и по нему фильтровать записи. И он не изменялся. Теперь же схема работы становится печальной - каждый день этот параметр будет изменяться, т.е. необходимо заново его обновлять, и это если брокеры не придумают чего-то еще. На сайте биржи да и в транслируемых данных есть показатель режима торгов для инструмента. Никаких расчётных величин нет. Зачем это, какую проблему решает это нововведение? Представляю, что ждет работающие скрипты при переходе брокеров на этот режим.
 
И сразу возникает вопрос: как будут работать методы, где есть входной параметр limit_kind?
 
Nikolay, добрый день.

Цитата
как будут работать методы, где есть входной параметр limit_kind?
При работе в схеме с календарными датами в limit_kind необходимо передать дату расчетов, на которую необходимо получить позицию (NUMBER в формате YYYYMMDD).

Цитата
как теперь для инструментов, торгуемых в разных режимах определять позицию
Предлагаем воспользоваться следующими функциями - функции могут принимать на ввод в параметре limit_kind конкретную дату расчетов, либо значение "Tx".
Если передана дата, функция вернет позицию на указанную дату, если такая имеется - в противном случае возвращается позиция, установленная на ближайшую предшествующую указанной дату, либо 0, если позицию по такому условию не удалось найти.
Если передано значение "Tx", функция вернет плановую позицию (с максимальной датой рачетов).

Скрытый текст
 
Цитата
либо значение "Tx"
Это уже новая информация. Какая минимальная версия терминала, поддерживающая данную функциональность?
 
Nikolay,

Схема ведения позиций по календарным датам поддерживается Рабочим местом QUIK версии 10.2.0 и выше, соответственно, приведенный код будет работать начиная с этой версии.
При подключении к серверу QUIK-Junior рекомендуем использовать терминал актуальной версии 11.4.1.
 
Цитата
Anton Belonogov написал:
Предлагаем воспользоваться следующими функциями - функции могут принимать на ввод в параметре limit_kind конкретную дату расчетов, либо значение "Tx".
А справку не нужно поправить? В ней limit_kind указан как NUMBER. Какой еще "Tx"?
getBuySellInfoEx теперь тоже будет возвращать не пойми что? Тоже поправьте в справке.

А в целом кто так делает? По сути  limit_kind это теперь новый параметр содержащий не вид лимита а дату, соответственно никакой обратной совместимости, это приведет к полной неработоспособности всех ранее написанных программ.
 
Станислав, добрый день.

Мы привели пример функций для работы с позициями в календарных датах, основанных на getMoneyEx и getDepoEx.
Исходные функции (getMoneyEx и getDepoEx), а также другие функции QLua остались без изменений.
 
Какое значение limit_kind принимает getPortfolioInfoEx?
 
Станислав, добрый день.

При использовании схемы с календарными датами срок расчетов портфеля соответствует плановой позиции - в этом случае в getPortfolioInfoEx передается limit_kind = 365.
 
В данной схеме обнаружена она проблема, затрудняющая её использование. В таблице money_limit поле limit_kind может изменится в процессе работы. Например, считываем данные по инструменту, по которому нет позиции, получаем текущую дату. Открываем позицию и в поле limit_kind уже дата +1. Не очень понятно как предлагается работать, если данные параметр будут постоянно изменяться. Если только просто не прибавлять всегда 1, т.к. заявляется, что вернётся ближайшее значение.
 
Хотя нет, это ваша реализация так работает. Прямой фильтр по money_limits требует точного соответствия. Это, конечно, просто великолепно вносить изменения ломающие обратную совместимость в ключевые механизмы по работе с инструментами.
 
Nikolay, добрый день.

Речь идет об использовании функций, которые мы приводили выше, или о запуске какого-то другого кода?
 
Речь о поведении данных в таблице money_limits поле limit_kind. Вы предложили реализацию через перебор данных и поиск максимального. Такой подход возможен, да. Но возникает вопрос - почему вносимые изменения потребовали использования такого подхода.

limit_kind - это режим торгов инструмента, он задан в его спецификации и не изменится в течении торговой сессии. Наоборот, это достаточно постоянный параметр. То что дата расчётов в связи с выходными может быть дальше, не означает, что необходимо теперь переходить на хранение даты. То что в течении торговой сессии произошли с сделки с инструментом, не означает, что его режим торгов изменится. Он как был Т+1, так и остался. Просто позиция будет той же завтра, если нет сделок, не более. Сейчас же происходит замечательная вещь - нет сделок, получаем режим торгов Т+0 (текущая дата), совершили сделки, получаем Т+1 (следующая дата). Т.е. можно было бы добавить дату расчётов в таблицу, чтобы знать когда произойдут взаиморасчёты, но базовый фильтр limit_kind почему был изменён - совершенно не ясно. Это не дата расчётов. С этим можно было жить как раньше, если бы он не изменялся в течении торгов, но и это не так. Теперь действительно необходимо постоянно сканировать на поиск максимального значения.
 
Цитата
Nikolay написал:
limit_kind - это режим торгов инструмента
  Присоединяюсь: Дата расчета это не режим торгов.
 
Nikolay, добрый день.

Цитата
limit_kind - это режим торгов инструмента, он задан в его спецификации и не изменится в течении торговой сессии.
limit_kind - это параметр позиции на сервере QUIK, а не параметр инструмента в Торговой системе.

Торговые режимы остаются прежними, изменяется только ведение позиций на сервере, что позволяет для каждой позиции видеть даты предстоящих расчетов.
 
Цитата
Anton Belonogov написал:
limit_kind - это параметр позиции на сервере QUIK, а не параметр инструмента в Торговой системе.Торговые режимы остаются прежними, изменяется только ведение позиций на сервере, что позволяет для каждой позиции видеть даты предстоящих расчетов.
 Почему бы не оставить в покое limit_kind (как было)? В чем была проблема завести новое поле "Дату предстоящих торгов"?
 
Цитата
TGB написал:
"Дату предстоящих торгов"
  Читать: "Дату предстоящих расчетов"
 
TGB, добрый день.

В зависимости от установленной на сервере схемы позиции учитываются либо по срокам расчетов (T0, T1), либо по датам.
Это взаимоисключающие параметры, сервер транслирует на терминалы только один из них, поэтому смысла в дополнительном параметре для QLua нет.
 
Цитата
Anton Belonogov написал:
TGB, добрый день.

В зависимости от установленной на сервере схемы позиции учитываются либо по срокам расчетов (T0, T1), либо по датам.
Это взаимоисключающие параметры, сервер транслирует на терминалы только один из них, поэтому смысла в дополнительном параметре для QLua нет.
А как писать код, чтобы он работал на разных брокерах? У меня 3 брокера и если они будут использовать разные схемы мне писать обработку для каждого брокера???
За что вы так не любите своих пользователей???  
 
И как узнать какую схему использует какой брокер? Есть признак хотя бы???
 
Было бы прекрасно, если бы вы привели пример кода, как посмотреть открытые позиции по каждому инструменту на дату Т0, Т1, Т2 с учетом того, что брокеры могут использовать различные схемы.  
 
Андрей, добрый день.

Цитата
Андрей написал:
как узнать какую схему использует какой брокер?
Это можно узнать по limit_kind на позициях: если включена схема ведения позиций по календарным датам, limit_kind будет иметь вид YYYYMMDD, в противном случае, при использовании старой схемы - 0, 1, 2, 365.

Цитата
Андрей написал:
У меня 3 брокера и если они будут использовать разные схемы мне писать обработку для каждого брокера?
Верно.

Мы не можем предусмотреть все сценарии использования QLua, и у нас нет примеров для каждого возможного алгоритма.
По этой причине на Учебном сервере QUIK-Junior было включено ведение позиций в календарных датах, чтобы пользователи могли протестировать работу в новом режиме и подготовиться к аналогичным изменениям, если они произойдут на сервере брокера.

Рекомендуем протестировать Ваши скрипты на сервере QUIK-Junior - получить доступ можно по ссылке.
 
Цитата
Anton Belonogov написал:
Это взаимоисключающие параметры, сервер транслирует на терминалы только один из них, поэтому смысла в дополнительном параметре для QLua нет.
  Не согласен. Разве  "Дата предстоящих расчетов" рассчитывается без учета "Режима торгов"?
Пожалуйста, объясните какие проблемы возникают у брокера и пользователя, если дополнительно к тому как было (limit_kind - "Режим торгов") транслировалось бы поле (возможно пустое) "Дата предстоящих расчетов"? Может быть разработчик не стал создавать новое поле с целью большой экономии памяти :smile: ?
 
Цитата

Рекомендуем протестировать Ваши скрипты на сервере QUIK-Junior - получить доступ можно  по ссылке .
Скрипт написал, тестирую, но тут опять незадача...Почему в демократии QUIK запрещен short акций? Всех!  
 
* в демо версии  
 
TGB, добрый день.

Цитата
Пожалуйста, объясните какие проблемы возникают у брокера и пользователя, если дополнительно к тому как было (limit_kind - "Режим торгов") транслировалось бы поле (возможно пустое) "Дата предстоящих расчетов"?
Повторим, в разрезе позиций на сервере эти параметры - взаимоисключающие, для позиции может быть установлен только один из них.
Такова особенность архитектуры системы QUIK, более развернутый комментарий мы не можем предоставить.
 
Андрей, добрый день.

На сервере QUIK-Junior доступно осуществление операций шорт по некоторым акциям, в том числе SBER - см. таблицу "Купить/Продать" (открывается двойным нажатием по строке в таблице "Клиентский портфель"), поле "Продажа".

Если при попытке продать какой-либо инструмент из этого списка Вы получаете ошибку, просим прислать ее скриншот.
 
Цитата
Андрей написал:
Цитата
Андрей, если не сложно, поделитесь скриптом, а то уже кучу времени убил на правки и высказал кучу матов в адрес разрабов, а толку пока нет.
Спасибо!
Скрипт написал, тестирую, но тут опять незадача...Почему в демократии QUIK запрещен short акций? Всех!  
 
приходится делать работу за разрабов - это конечно уродство, когда вот так вносятся правки без какой-либо поддержки и указаний как с этим работать. Как минимум - это неуважение к своим клиентам.

Код тестирования:

-- Глобальные переменные для определения схемы работы
IS_NEW_DATE_SCHEME = nil  -- Флаг новой схемы с датами
CURRENT_TRADE_DATE = nil  -- Текущая дата торгов
TEST_RESULTS = {}         -- Таблица для хранения результатов тестирования

-- Константы (должны быть настроены под конкретного брокера)
STOCK_ACCOUNT = "NL001***"  -- счет для акций
CLIENT_CODE = "10***"           -- код клиента
FIRM_ID = "NC00***"        -- код фирмы

-- Функция записи в лог-файл
function WriteToLog(message)
   local log_file = io.open(getScriptPath().."\\quik_scheme_test.txt", "a")
   if log_file then
       local timestamp = os.date("%Y-%m-%d %H:%M:%S")
       log_file:write(timestamp .. " - " .. message .. "\n")
       log_file:close()
   else
       message("Ошибка открытия файла для записи!")
   end
end

-- Функция определения типа схемы (новая с датами или старая)
function detect_scheme_type()
   WriteToLog("=== Начало определения типа схемы ===")
   
   local num = getNumberOf('money_limits')
   WriteToLog("Найдено записей в money_limits: " .. tostring(num))
   
   if num > 0 then
       for i = 0, num - 1 do
           local limit = getItem('money_limits', i)
           WriteToLog(string.format("Запись %d: limit_kind = %s, firmid = %s, client_code = %s",
               i, tostring(limit.limit_kind), tostring(limit.firmid), tostring(limit.client_code)))
           
           if limit.limit_kind > 365 then  -- Если значение больше 365, это новая схема с датами
               IS_NEW_DATE_SCHEME = true
               CURRENT_TRADE_DATE = tonumber(os.date("%Y%m%d"))
               WriteToLog("Обнаружена НОВАЯ схема с датами. limit_kind = " .. tostring(limit.limit_kind))
               WriteToLog("Текущая дата: " .. tostring(CURRENT_TRADE_DATE))
               return
           end
       end
   end
   
   IS_NEW_DATE_SCHEME = false
   WriteToLog("Обнаружена СТАРАЯ схема с T0, T1, T2")
end

-- Функция получения даты для T0, T1, T2
function get_settlement_date(offset)
   if not IS_NEW_DATE_SCHEME then
       WriteToLog("get_settlement_date: старая схема, возвращаем offset = " .. tostring(offset))
       return offset
   end
   
   local trade_date = CURRENT_TRADE_DATE
   if not trade_date then
       trade_date = tonumber(os.date("%Y%m%d"))
   end
   
   local result_date = trade_date + offset
   WriteToLog(string.format("get_settlement_date: новая схема, offset=%d, результат=%d", offset, result_date))
   return result_date
end

-- Функция поиска позиции с учетом схемы
function find_limit_position(limits_table, criteria)
   WriteToLog("Поиск в таблице: " .. limits_table)
   WriteToLog("Критерии поиска: " .. tostring(criteria.firmid) .. ", " .. tostring(criteria.client_code))
   
   local num = getNumberOf(limits_table)
   WriteToLog("Количество записей в таблице: " .. tostring(num))
   
   if num <= 0 then
       WriteToLog("Таблица пуста")
       return nil
   end
   
   if IS_NEW_DATE_SCHEME then
       WriteToLog("Поиск в НОВОЙ схеме (по максимальной дате)")
       local best_match = nil
       local max_date = 0
       
       for i = 0, num - 1 do
           local item = getItem(limits_table, i)
           local matches = true
           
           for key, value in pairs(criteria) do
               if key ~= 'limit_kind' and item[key] ~= value then
                   matches = false
                   break
               end
           end
           
           if matches then
               WriteToLog(string.format("Найдена подходящая запись: limit_kind=%d, currentbal=%s",
                   item.limit_kind, tostring(item.currentbal)))
               if item.limit_kind > max_date then
                   max_date = item.limit_kind
                   best_match = item
               end
           end
       end
       
       if best_match then
           WriteToLog("Выбрана запись с максимальной датой: " .. tostring(max_date))
       else
           WriteToLog("Подходящих записей не найдено")
       end
       
       return best_match
   else
       WriteToLog("Поиск в СТАРОЙ схеме (точное соответствие)")
       for i = 0, num - 1 do
           local item = getItem(limits_table, i)
           local matches = true
           
           for key, value in pairs(criteria) do
               if item[key] ~= value then
                   matches = false
                   break
               end
           end
           
           if matches then
               WriteToLog("Найдена точная запись: limit_kind=" .. tostring(item.limit_kind))
               return item
           end
       end
   end
   
   WriteToLog("Запись не найдена")
   return nil
end

-- Обновленная функция получения доступных средств
function GetFreeMoney()
   WriteToLog("=== Вызов GetFreeMoney() ===")
   WriteToLog("CLASS_CODE: " .. tostring(CLASS_CODE))
   
   -- Определяем схему при первом вызове
   if IS_NEW_DATE_SCHEME == nil then
       detect_scheme_type()
   end
   
   if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then
       WriteToLog("Обработка срочного рынка")
       local num = getNumberOf('futures_client_limits')
       WriteToLog("Записей в futures_client_limits: " .. tostring(num))
       
       if num > 0 then
           for i = 0, num - 1 do
               local limit = getItem('futures_client_limits', i)
               if limit.firmid == FIRM_ID and limit.trdaccid == STOCK_ACCOUNT and limit.limit_type == 0 then
                   WriteToLog("Найдены средства срочного рынка: " .. tostring(limit.cbplplanned))
                   return limit.cbplplanned
               end
           end
       end
   elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' or CLASS_CODE == 'CETS' then
       WriteToLog("Обработка фондового рынка")
       local criteria = {
           currcode = 'SUR',
           firmid = FIRM_ID,
           client_code = CLIENT_CODE
       }
       
       if IS_NEW_DATE_SCHEME then
           WriteToLog("Поиск в НОВОЙ схеме")
           criteria.limit_kind = 0
           local limit = find_limit_position('money_limits', criteria)
           if limit then
               WriteToLog("Найдены средства: " .. tostring(limit.currentbal))
               return limit.currentbal
           end
       else
           WriteToLog("Поиск в СТАРОЙ схеме")
           criteria.limit_kind = 0
           local limit = find_limit_position('money_limits', criteria)
           if limit then
               WriteToLog("Найдены средства: " .. tostring(limit.currentbal))
               return limit.currentbal
           end
       end
   else
       WriteToLog("Неизвестный CLASS_CODE: " .. tostring(CLASS_CODE))
   end
   
   WriteToLog("Средства не найдены, возвращаем 0")
   return 0
end

-- Функция тестирования различных CLASS_CODE
function TestDifferentMarkets()
   WriteToLog("\n=== Тестирование различных рынков ===")
   
   -- Тестируем фондовый рынок
   CLASS_CODE = 'TQBR'
   local stock_money = GetFreeMoney()
   table.insert(TEST_RESULTS, {market = "Фондовый рынок (TQBR)", money = stock_money})
   
   -- Тестируем срочный рынок
   CLASS_CODE = 'SPBFUT'
   local futures_money = GetFreeMoney()
   table.insert(TEST_RESULTS, {market = "Срочный рынок (SPBFUT)", money = futures_money})
   
   -- Тестируем валютный рынок
   CLASS_CODE = 'CETS'
   local currency_money = GetFreeMoney()
   table.insert(TEST_RESULTS, {market = "Валютный рынок (CETS)", money = currency_money})
end

-- Функция анализа таблиц лимитов
function AnalyzeLimitTables()
   WriteToLog("\n=== Анализ таблиц лимитов ===")
   
   -- Анализ money_limits
   local money_limits_count = getNumberOf('money_limits')
   WriteToLog("money_limits записей: " .. tostring(money_limits_count))
   
   if money_limits_count > 0 then
       for i = 0, math.min(money_limits_count-1, 10) do  -- Ограничим вывод первыми 10 записями
           local limit = getItem('money_limits', i)
           WriteToLog(string.format("money_limits[%d]: firmid=%s, client_code=%s, limit_kind=%s, currentbal=%s",
               i, tostring(limit.firmid), tostring(limit.client_code),
               tostring(limit.limit_kind), tostring(limit.currentbal)))
       end
   end
   
   -- Анализ depo_limits
   local depo_limits_count = getNumberOf('depo_limits')
   WriteToLog("depo_limits записей: " .. tostring(depo_limits_count))
   
   if depo_limits_count > 0 then
       for i = 0, math.min(depo_limits_count-1, 5) do  -- Ограничим вывод первыми 5 записями
           local limit = getItem('depo_limits', i)
           WriteToLog(string.format("depo_limits[%d]: firmid=%s, client_code=%s, sec_code=%s, limit_kind=%s, currentbal=%s",
               i, tostring(limit.firmid), tostring(limit.client_code),
               tostring(limit.sec_code), tostring(limit.limit_kind), tostring(limit.currentbal)))
       end
   end
end

-- Основная функция
function main()
   WriteToLog("====== ЗАПУСК ТЕСТИРОВАНИЯ СХЕМЫ QUIK ======")
   WriteToLog("Версия скрипта: 1.0")
   WriteToLog("Дата тестирования: " .. os.date("%Y-%m-%d %H:%M:%S"))
   
   -- Инициализация
   detect_scheme_type()
   
   -- Анализ таблиц
   AnalyzeLimitTables()
   
   -- Тестирование различных рынков
   TestDifferentMarkets()
   
   -- Вывод результатов
   WriteToLog("\n=== ИТОГОВЫЕ РЕЗУЛЬТАТЫ ===")
   WriteToLog("Тип схемы: " .. (IS_NEW_DATE_SCHEME and "НОВАЯ (по датам)" or "СТАРАЯ (T0,T1,T2)"))
   
   for _, result in ipairs(TEST_RESULTS) do
       WriteToLog(string.format("%s: %s", result.market, tostring(result.money)))
   end
   
   WriteToLog("\n=== РЕКОМЕНДАЦИИ ===")
   if IS_NEW_DATE_SCHEME then
       WriteToLog("1. Используйте функции поиска по максимальной дате")
       WriteToLog("2. Обновите все скрипты для работы с новой схемой")
       WriteToLog("3. Тестируйте на QUIK Junior для адаптации")
   else
       WriteToLog("1. Брокер использует классическую схему")
       WriteToLog("2. Готовьтесь к возможному переходу на новую схему")
       WriteToLog("3. Протестируйте скрипты на QUIK Junior")
   end
   
   WriteToLog("====== ТЕСТИРОВАНИЕ ЗАВЕРШЕНО ======\n")
   
   message("Тестирование завершено. Результаты в файле quik_scheme_test.txt")
end

-- Очистка файла при каждом запуске
local init_file = io.open(getScriptPath().."\\quik_scheme_test.txt", "w")
if init_file then
   init_file:write("")
   init_file:close()
end

-- Запуск основной функции
main()
Страницы: 1
Читают тему
Наверх