Отправка данных из Текущей таблицы параметров в C# посредством DLL

Автор записи: Дмитрий (Admin)
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 9, среднее: 4,89 из 5)
Загрузка...

СнимокСкрипт в начале, при запуске, отправляет в C# посредством библиотеки функций (DLL) всю информацию из Текущей таблицы параметров по всем бумагам из классов: TQBR (акции), SPBFUT (фьючерсы), SPBOPT (опционы), данный фильтр расположен в функции SendAllParamStrings(). Так же, в начале каждой строки параметров передается текущее время ОС в миллисекундах, благодаря чему, на стороне C# вычисляется время задержки передачи данных. После отправки бумаг этих классов, скрипт отправляет новые данные по мере их поступления, используя функцию обратного вызова OnParam().

 Поступающие данные проходят через "стек"(массив): новая строка параметров по инструменту добавляется в конец "стека", а для отправки берутся строки из начала "стека", после чего удаляются, таким образом данные не теряются. Фильтр отправляемых классов и бумаг, можно настроить в данной функции. По умолчанию, отправляются 2 бумаги: SBER и RIU5.
ВАЖНО!!! Если Вы добавите в фильтр функции OnParam() много бумаг для передачи, задержка сильно увеличится. Для примера: если отправлять все бумаги классов: TQBR (акции), SPBFUT (фьючерсы) и SPBOPT (опционы), то время задержки может достигать 10 секунд и более, в зависимости от интенсивности торгов.

Скрипт QLua(Lua)

В библиотеке DLL реализовано 3 функции взаимодействия с Lua:
1) CheckGotPARAMS() - Проверяет получил-ли C# последнюю строку параметров по инструменту (или еще не было отправлено ни одной строки), возвращает true, либо false.
2) SendPARAMS() - Получает от QLua(Lua) строку инструмента из Текущей Таблицы Параметров и отправляет ее в C#.
3) GetMilliseconds() - Возвращает текущее время работы ОС в миллисекундах.

Код DLL

Для работы данного примера создайте приложение Windows Forms на C#, если Вы не знаете как это сделать, посмотрите здесь. Разместите на форме одно текстовое поле, которое должно называться textBox1, установите его свойство "Multiline" в значение "TRUE", растяните его на всю форму и замените код файла "Form1.cs" на приведенный ниже, не забудьте функции Form1_FormClosing и Form1_Shown назначить соответствующим событиям формы и переименуйте namespace в коде так же, как называется Ваш проект (в примере namespace Test).

Код C#

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Добавить комментарий

Отправка данных из Текущей таблицы параметров в C# посредством DLL: 67 комментариев

  1. Отличная статья!
    Появилось два вопроса.
    1. Из листинга для луа не понял, где указывается, к какой таблице мы обращаемся. Как мне подцепить данные из таблицы всех сделок (а не текущих параметров, как в примере)?
    2. Как сделать так, чтобы скрипт смотрел содержимое строки в приложении C# (там в окно будет вводиться тикер) и отсылал только данные для этого тикера?

    1. Спасибо!
      1.В листинге используется функция обратного вызова OnParam(), которая вызывается при поступлении новых данных в Текущую таблицу параметров, потом функцией getParamEx() эти значения из Тек. таб. пар. выбираются для отправки. Для работы с данными Таблицы всех сделок используйте функцию обратного вызова OnAllTrade(). Ознакомьтесь со статьей https://quikluacsharp.ru/qlua-osnovy/funktsii-obratnogo-vyzova-vstroennye-v-qlua/, там есть примеры.
      2.Можете использовать принцип, описанный в данной статье https://quikluacsharp.ru/qlua-c-cpp-csharp/kak-otpravit-komandu-v-quik-iz-prilozheniya-c/, только вместо команды отправляйте тикер. А потом в функции OnAllTrade() проверяйте, по этому тикеру пришла сделка, если да, то отправляете.

      1. Привет! Спасибо за ответ!
        У меня появились следующие траблы.
        1. Самое главное - при попытке запуска скрипта Луа вылетает ошибка "System error 14001"
        2. В 2008-ю студию код С# залить не получилось, выдавал несколько ошибок по "MemoryMappedFiles", поставил 2010.
        3. В 2010 студии выпала куча разнообразных ошибок, в резкльтате пришел к тому, что в файле проекта Program.cs нужно добавить строку "using Test" и все сразу становится норм.
        Что делать с системной ошибкой 14001?
        То что у меня с кодом c# - это особенность 2010 студии? Я все правильно сделал?

          1. Здравствуйте, Иван! Данная ошибка говорит о том, что есть несовместимость настроек проекта с ОС. Нужно копаться в свойствах проекта. Какой именно проект у Вас не хочет работать на VS2010 ?

          2. Вы, кстати, уверены, что VS 2013 Community не встанет на XP ? И вариант поставить Win7 Вы вообще не рассматриваете? Возможно еще версия .Net Framework, на которую настроен проект не имеется на вашем компьютере, тогда нужно ее установить.

              1. Видимо DLL виновница, при подгрузке в скрипт просит то, чего нет. Вы ее, кстати, на своем компьютере компилировали, или готовую взяли?

                1. Компилил на своем, в VS2008. Я конечно, подозревал, что из-за нее может быть, но подумал, что раз скомпилилось удачно, то все норм.
                  А где готовая, что-то я просмотрел?

                  1. По проекту из данной статьи готовой DLL не выложено, если Вы этот пример тестируете. Попробуйте сделать новый проект с простейшей DLL для QLua, как в этой статье https://quikluacsharp.ru/qlua-c-cpp-csharp/konnektor-dll-quik-qlua-lua-c/, если Вы еще не пробовали этого делать, чтобы исключить возможные ошибки, и постарайтесь сначала ее настроить, чтоб она работала без ошибок, поймете в чем нюанс для Вашей системы, а потом просто добавите в нее нужный функционал. У меня, к сожалению, нет XP в наличии, чтобы потестировать возможные ошибки, хотя VS2010 специально сейчас установил.

                    1. Установил Lua for Windows
                      Проект "Привет из С/С++" отрабатывается без лишних слов.
                      А когда дело доходит до этой dll, выдает ошибку при запуске скрипта "error loading module 'QluaCSharpConnector' from file '.\QluaCSharpConnector.dll':
                      Не найдена указанная процедура."
                      Пробовал в скрипте оставлять только одну строчку require("QluaCSharpConnector") - та же ошибка, значит, дело в dll.
                      Пробовал запускать скрипт lua без квика через Lua for Windows, он выдает ошибку "Точка входа в процедуру GetTickCount64 не найдена в библиотеке DLL KERNEL32.dll"
                      Я в печали..

                    2. Пробовал на компе с Win7 аналогичная ситуация.
                      Кстати, не могу понять, на Win7 VS2013 нельзя что ли поставить?

                    3. Здравствуйте, Иван! У Вас, видимо, ОС 32-х битная, а функция GetTickCount64() для 64-х битных систем, используйте функцию GetTickCount().

                    4. Привет! Давай на "ты")
                      Функцию исправил, теперь скрипт запускается, ура)
                      Как можно теперь отладить это все? А то у меня в экзешнике на C# ничего не появляется.

                    5. Привет, давай 🙂 Начну новую цепочку комментариев, то WordPress только 10 вложенных уровней позволяет максимум.

  2. Почему-то при компиляции получаю ошибку
    Error 1 The type or namespace name 'Form1' could not be found (are you missing a using directive or an assembly reference?) C:\my\StockSharp\textbox\textbox\Program.cs 19 33
    ругается на строку
    Application.Run(new Form1());

    1. Нужно либо в Program.cs пространство имен "Test" назвать (namespace Test), либо в основном файле (по умолчанию Form1.cs) пространство имен назвать так же, как в Program.cs. Приложение должно работать в одном пространстве имен, в общем. По умолчанию, оно называется так же, как Вы называете проект, а когда Вы скопировали и вставили код, соответственно, если Вы назвали проект отлично от "Test", то названия не совпали.

  3. Добрый день.
    1)Так как не совсем получилось передать ТТП без фильтра по тикерам, пытаюсь что-то сделать из внешнего текстового файла (с luaxml в том числе пробовал). Думаю это удобнее, чем лезть в текст программы.
    Есть вот такой код
    array_string_Tickers={}
    local file_name=getScriptPath().."\\".."setting_ini.txt"
    local i=0

    function OnInit()
    for line in io.lines(file_name) do
    array_string_Tickers[i]=line
    message(tostring(array_string_Tickers[i],1))
    end
    end
    который из текстового файла вытягивает строку с тикерами. Как вытянуть из строки отдельные тикеры? И возможно ли?
    Нашел вот такую функцию
    function split(str,sep)
    local fields = {}
    str:gsub(string.format("([^%s]+)", sep or "%s"), function(c) fields[#fields+1] = c end)
    return fields
    end
    Использование:
    a = split('x1 x2 x3 x4 x5')
    message(a[4],1)
    Но привязать к текстовому файлу "мозгов" не хватило). Плоховато знаю Lua).
    2) с#, с++ - есть ли возможность сделать так, чтобы n-е количество экземпляров приложения (собранного на WinForms) могли обращаться к одной выделенной именованной памяти (например к данным ТТП). Либо надо делать на каждый экземпляр свой поток данных?

    1. Добрый день!
      1) Поясните пожалуйста фразу:"не совсем получилось передать ТТП без фильтра по тикерам"
      2) К именованной памяти может обращаться хоть сколько экземпляров приложения, главное, чтобы они не мешали друг другу, нужно делать какой-то контроль монопольного доступа к памяти, чтобы разные приложения не могли писать в одну и ту же память одновременно, например, самое простое, выделить для этого еще одну память и через нее как-то контролировать доступ.

      1. 1)Таблица передается без вопросов. Я имел ввиду необходимость ввода тикеров стр.263- 264 скрипта lua. Их то я пытаюсь засунуть из текстового файла
        2) Спасибо за ответ. Я пробовал подключать 2 приложения. Первое подключенное приложение практически монопольно занимало канал. Второе изредко пробивалось. Так как с памятью никогда не работал, думал есть свойства у MemoryMappedFile, позволяющее контролировать состояние памяти (занято другим процессом для записи или свободно). Допустим у FileStream такие свойства есть. Думал может быть подобное и MemoryMappedFile есть.

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

  4. Добрый вечер! Идею Вы поняли правильно. А насчёт реализации, есть несколько вариантов.
    1. Посмотреть уже готовые реализации circular(или round) buffer на github-e на языке Lua
    2. Посмотреть уже готовые реализации circular buffer написанные на С++(что-то мне кажется что это будет самый быстрый вариант :), сам хотел сделать два варианта и сравнить что быстрее, в Lua создать буфер или уже в dll )
    3. Воспользоваться готовым решением из известной библиотеки Boost C++, там есть несколько готовых и протестированных надежных вариантов.
    4. Придумать своё решение и хорошо его проверить!
    У меня получилось как-то так:
    -- Инициализация
    local buffer = {} -- таблица буфер для временного хранения
    local start_buf_pointer = 0
    local end_buf_pointer = 0
    local size_buf = 1000 (пример)
    local total_in = 0
    local total_out = 0

    --Добавление в буфер
    end_buf_pointer = (end_buf_pointer%size_buff)+1
    buffer[end_buf_pointer] = "то что нам нужно записать в буфер!"
    total_in= total_in+1

    --Условие сохранения в main-e
    while is_run do
    if (end_buf_pointer ~= start_buf_pointer)then
    -- Удаляем из буфера
    Store()
    end
    if start_buf_pointer-end_buf_pointer==10 then
    message(" В буфере осталось всего 10 свободных элементов, возможно перезаписывание и потеря не сохранённых данных, увеличить размер буфера в настройках!!! ", 1)
    end
    end

    -- Удаляем из буфера
    local n = total_in - total_out-1
    for i=0, n do
    local index = (start_buf_pointer+i)%size_buf+1
    t = buffer[index]
    buffer[index] = 0
    if t~=nil then
    -- передаем наше "t" в dll и далее .....
    end
    total_out=total_out+1
    end
    start_buf_pointer= ((start_buf_pointer+n)%size_buff)+1

    Может где ошибся, или можно проще, но вроде полёт нормальный. Проверил потестировал, дальше не стал ничего менять. Хотя сравнительный тест с реализацией в Boost С++ было бы совсем здорово. Что-бы не изобретать велосипед 🙂

    1. Спасибо за советы, с Boost обязательно познакомлюсь. В планах давно уже есть полностью все из Lua вынести в DLL, чтобы не напрягать терминал и не переписывать скрипты под каждую задачу. Вот как сайт перенесу на C#, так сразу займусь реализацией универсального решения, в котором все будет из приложения C# настраиваться, хочу даже автоматическую генерацию кода сделать под определенные задачи прямо с сайта, т.к. все будет на .NET, то вполне решаемая думаю задача, главное, чтобы хостинг выдержал:) Ну и всевозможные сервисы вспомогательные думаю сделать можно будет. А на счет изобретения велосипедов, я без этого не могу, мне нужно самому все сделать, так и понимание лучше, да и вдруг они что-то не додумали:)

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

    1. Alex_r, спасибо Вам большое за "наводку", сейчас протестирую и думаю, что заменю код везде, где используется стек на данную технологию! Буду очень признателен Вам в будущем за подобного рода замечания!

        1. Alex_r, здравствуйте! Прирост скорости действительно ощущается, изменил здесь и в скрипте отправки стакана стеки! Посмотрите, я правильно технологию применил?)

  6. Точно не скажу сейчас. Но картина следующая. Тест строил на сохранении всех сделок это где-то (700 000) сделок за день за один раз. Запускаю сохранение и через OnQuote() буфер начинает заполняться по 25 000 - 30 000 (table.insert()) сделок в сек. Параллельно из буфера забираю сделки (table.remove()) помойму около 600 - 700 в сек, но буфер быстро увеличивается в размере. Секунд через 10 начинаются тормоза, а потом и сам квик начинает работать с подвисаниями. Потом полный ступор, quik занимает 100% процессорного времени. Время исчисляется минутами. Далее заменил конструкцию буфера на «circular buffer» и всё залетало без тормозов. Буфер правда увеличивается, но стабильно по 11 000 сделок в сек успевает сохраниться. И ещё в последней версии руководства по qlua от quik разработчиков есть потокобезопасные(table.sinsert() table.sremove() ) тест также не прошли 🙂

  7. Спасибо за большую проделанную работу. Хотел добавить, что у меня были выявлены проблемы с производительностью и проблему решил заменой конструкции (table.insert(.... , ....); и table.remove(... , ...)) на "circular buffer" и проблема ушла 🙂 В тесте примерно получается 11000 запросов в dll с сек. и без тормозов и уменьшения нагрузки на процессор.