Архив рубрики: Qlua + C/C++/C#

Пример реализации функции обратного вызова OnAllTrade внутри DLL

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dll
Таким образом можно любую встроенную в QLua функцию заменить функцией в DLL, в результате скрипт QLua может содержать только одну строку подключения библиотеки, а всю обработку можно вынести в DLL, а из нее в C#.

Код QLua(Lua)
1
2
3
4
5
6
7
8
9
10
11
12
13
require("QLuaCallbacks");
 
Run = true;
 
function main()
   while Run do
      sleep(1);
   end;
end;
 
function OnStop()
   Run = false;
end;
Код DLL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <windows.h>
#include <string>
 
//=== Необходимые для Lua константы ============================================================================//
#define LUA_LIB
#define LUA_BUILD_AS_DLL
 
//=== Заголовочные файлы LUA ===================================================================================//
extern "C" {
#include "Lua\lauxlib.h"
#include "Lua\lua.h"
}
 
//=== Стандартная точка входа для DLL ==========================================================================//
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  fdwReason, LPVOID lpReserved)
{
   return TRUE;
}
 
struct DateTime
{
   int mcs;  //Микросекунды
   int ms;  //Миллисекунды
   int sec;  //Секунды
   int min;  //Минуты
   int hour;  //Часы
   int day; //День
   int week_day;  //Номер дня недели
   int month;  //Месяц
   int year;  //Год
};
 
 
std::string  getFieldValue(lua_State *L, const char *key)
{
   std::string result;
   lua_pushstring(L, key); /* поместить ключ на стек */
   lua_gettable(L, -2); /* получить значение */
 
   result = lua_tostring(L, -1);
   lua_pop(L, 1);
 
   return result;
}
 
DateTime getDateTimeField(lua_State *L)
{
   DateTime datetime;
 
   lua_pushstring(L, "datetime"); /* поместить ключ на стек */
   lua_gettable(L, -2); /* получить таблицу datetime */
 
   lua_pushstring(L, "mcs");  //Микросекунды
   lua_gettable(L, -2);
   datetime.mcs = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "ms");  //Миллисекунды
   lua_gettable(L, -2);
   datetime.ms = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "sec");  //Секунды
   lua_gettable(L, -2);
   datetime.sec = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "min");  //Минуты
   lua_gettable(L, -2);
   datetime.min = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "hour");  //Часы
   lua_gettable(L, -2);
   datetime.hour = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "day"); //День
   lua_gettable(L, -2);
   datetime.day = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "week_day");  //Номер дня недели
   lua_gettable(L, -2);
   datetime.week_day = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "month");  //Месяц
   lua_gettable(L, -2);
   datetime.month = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pushstring(L, "year"); //Год
   lua_gettable(L, -2);
   datetime.year = lua_tonumber(L, -1);
   lua_pop(L, 1);
   lua_pop(L, 1);
 
   return datetime;
}
 
 
//=== Реализация функций обратного вызова ====================================================================//
static int forLua_OnAllTrade(lua_State *L) //
{
   // Проверяет, является-ли первый элемент стека массивом (таблицей Lua)
   if (lua_istable(L, 1))
   {
      std::string trade_num = getFieldValue(L, "trade_num");       // Номер сделки в торговой системе
      std::string flags = getFieldValue(L, "flags");           // Набор битовых флагов
      std::string price = getFieldValue(L, "price");           // Цена
      std::string qty = getFieldValue(L, "qty");             // Количество бумаг в последней сделке в лотах
      std::string value = getFieldValue(L, "value");           // Объем в денежных средствах
      std::string accruedint = getFieldValue(L, "accruedint");      // Накопленный купонный доход
      std::string yield = getFieldValue(L, "yield");           // Доходность
      std::string settlecode = getFieldValue(L, "settlecode");      // Код расчетов
      std::string reporate = getFieldValue(L, "reporate");        // Ставка РЕПО(%)
      std::string repovalue = getFieldValue(L, "repovalue");       // Сумма РЕПО
      std::string repo2value = getFieldValue(L, "repo2value");      // Объем выкупа РЕПО
      std::string repoterm = getFieldValue(L, "repoterm");        // Срок РЕПО в днях
      std::string sec_code = getFieldValue(L, "sec_code");        // Код бумаги заявки
      std::string class_code = getFieldValue(L, "class_code");      // Код класса
      DateTime    datetime = getDateTimeField(L);     // Дата и время
      std::string period = getFieldValue(L, "period");          // Период торговой сессии.Возможные значения : «0» – Открытие; «1» – Нормальный; «2» – Закрытие
 
      if (sec_code == "SBER")
      {
         std::string TradeInfo =
            "trade_num=" + trade_num + " " +
            "flags=" + flags + " " +
            "price=" + price + " " +
            "qty=" + qty + " " +
            "value=" + value + " " +
            "accruedint=" + accruedint + " " +
            "yield=" + yield + " " +
            "settlecode=" + settlecode + " " +
            "reporate=" + reporate + " " +
            "repovalue=" + repovalue + " " +
            "repo2value=" + repo2value + " " +
            "repoterm=" + repoterm + " " +
            "sec_code=" + sec_code + " " +
            "class_code=" + class_code + " " +
            "time=" + std::to_string(datetime.hour) + ":" +
            std::to_string(datetime.min) + ":" +
            std::to_string(datetime.sec) + "." +
            std::to_string(datetime.mcs) + " " +
            "trade_num=" + trade_num + " " +
            "period=" + period;
 
         //Выводит сообщение в терминале с информацией по сделке
         lua_getglobal(L, "message");
         lua_pushfstring(L, TradeInfo.c_str());
         lua_pcall(L, 1, 0, 0);
      }
 
   }
   return 0;
}
 
 
//=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
static struct luaL_reg ls_lib[] = {
   { NULL, NULL }
};
 
//=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
extern "C" LUALIB_API int luaopen_QLuaCallbacks(lua_State *L) {
   luaL_openlib(L, "QLuaCallbacks", ls_lib, 0);
 
   //Добавляет функцию в стек
   lua_pushcclosure(L, forLua_OnAllTrade, 0);
   //Регистрирует её как коллбэк на OnAllTrade
   lua_setglobal(L, "OnAllTrade");
 
   return 0;
}

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

Вызов функций QLua(Lua) из DLL, написанной на C/C++

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dllДля этого нужна обычная библиотека DLL, подключаемая к QLua, о том, как ее создать можете посмотреть здесь.

Пусть созданная Вами DLL называется "LuaCallback.dll", которая находится в корневом каталоге терминала QUIK.

Следующий пример 10 раз, с периодичностью в 1 секунду выведет сообщение с текстом "Привет из DLL" посредством вызова из DLL функции из Qlua скрипта MyLuaCallback():

Код скрипта QLua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require("LuaCallback"); -- Подключает библиотеку "LuaCallback.dll"
 
Run = true; -- Флаг поддержания работы скрипта
 
-- Основная функция скрипта, пока работает она, работает скрипт
function main()
   LuaCallback.StartCallback(); -- Запускает механизм вызова функции MyLuaCallback из DLL
   while Run do sleep(1000); end; -- Поддерживает работу скрипта
end;
 
-- Функция, вызываемая из DLL
function MyLuaCallback(Text)
   message(Text); -- Выводит сообщение, переданное в функцию из DLL
end;
 
-- Функция завершения работы скрипта
function OnStop()
   Run = false; -- Завершает цикл while, следовательно завершается main() и сам скрипт останавливается
end;
Код DLL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <windows.h> //Подключает все необходимое
#include <thread> //Подключает возможность работы с потоками
 
//=== Необходимые для Lua константы ============================================================================//
#define LUA_LIB
#define LUA_BUILD_AS_DLL
 
//=== Заголовочные файлы LUA ===================================================================================//
extern "C" {
#include "Lua\lauxlib.h"
#include "Lua\lua.h"
}
 
//=== Стандартная точка входа для DLL ==========================================================================//
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   return TRUE;
}
 
//Функция вызывает функцию из QLua с периодичностью в 1 секунду
static int MyCallback(lua_State *L)
{
   lua_getglobal(L, "MyLuaCallback"); //Находит в стеке Lua функцию по ее названию и помещает ее наверх стека
   int callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); //Получает индекс функции в специальной внутренней таблице(реестре) Lua
 
   for (int i = 0; i < 10;i++)
   {
      lua_rawgeti(L, LUA_REGISTRYINDEX, callbackRef); //Достает функцию из реестра Lua по индексу и помещает в стек
      lua_pushstring(L, "Привет из DLL"); //Добавляет в стек параметр, который будет передан функции
      lua_call(L, 1, 1); //Вызывает выбранную функцию в скрипте QLua, передавая в нее 1 параметр (L - стек, 1 - количество передаваемых параметров, 1 - количество возвращаемых значений(нужно, чтобы обновлять стек))
      Sleep(1000); //Пауза в 1 секунду
   }
 
   return 0; //Выход из функции
}
 
//=== Реализация функций, вызываемых из LUA ====================================================================//
static int forLua_StartCallback(lua_State *L)
{
   std::thread thr(MyCallback, L); //Запускает выполнение функции MyCallback() в отдельном потоке
   thr.detach(); //Отсоединяет созданный поток от основного, делая его "фоновым"
 
   return (0); //Завершает работу функции forLua_StartCallback, при этом функция MyCallback продолжает работать в отдельном потоке
}
 
//=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
static struct luaL_reg ls_lib[] = {
   { "StartCallback", forLua_StartCallback }
};
 
//=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
extern "C" LUALIB_API int luaopen_LuaCallback(lua_State *L) {
   luaL_openlib(L, "LuaCallback", ls_lib, 0);
   return 0;
}

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

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

Автор записи: Дмитрий (Admin)

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

Отправка стакана из QUIK (QLua) в приложение C#

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dll
При отправке из терминала QUIK таких часто изменяющихся данных, как "СТАКАН", необходимо использовать обратную связь от C# о получении данных. Так же, на стороне QLua необходим буфер (стек), в который будут заноситься и из которого, в последствии, будут отправляться новые данные, по мере получения их приложением C#. На практике этот процесс происходит очень быстро, так что данные не успевают задерживаться в стеке в ожидании своей очереди. Благодаря чему, приложение C# всегда своевременно получает актуальные изменения. А благодаря стеку, ни одно изменение не останется упущенным.
Примеры кода:Смотреть полностью...

Как отправить команду в QUIK из приложения C#

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dllВ статье "Обмен данными между DLL (C/C++) и приложением C#" показан простой пример отправки сообщений из DLL в приложение C#, а QUIK(Lua) просто запускает и останавливает эту отправку. Для отправки команд из приложения C# в QUIK лучше использовать примерно следующую конструкцию:Смотреть полностью...

Обмен данными между DLL (C/C++) и приложением C#

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dll
Для обмена данными между библиотекой DLL, написанной на языке C/C++ и приложением, написанном на языке C#, удобно и эффективно использовать Отображаемые в Памяти Файлы (MemoryMappedFile). По сути, это выделенный участок оперативной памяти компьютера (скорость!), который имеет свое уникальное имя и размер в байтах. Оба эти параметра задаются программистом. В дальнейшем можно, как читать из этой памяти, так и писать в нее, подключившись к ней в библиотеке DLL и в приложении C#.

Был проведен тест скорости обмена сообщениями, в тесте принимали участие следующие технологии: MemoryMappedFile, NamedPipes и Socket. Создавались по два отдельных приложения на C#, сервер и клиент, которые должны были обменяться друг с другом текстовыми сообщениями размером 120 символов 500 000 раз. На все это у них ушло следующее количество времени:
MemoryMappedFile: 1,5 секунды
NamedPipes: 12,5 секунд
Socket: 14 секунд

При этом, количество требуемого кода, так же, было меньше всего у MemoryMappedFile, по моему, выбор очевиден!

Пример создания и использования именованной памяти с именем "MyMemory" и размером 256 байт. В примере реализован следующий алгоритм:Смотреть полностью...

Взаимодействие Lua и библиотеки DLL, написанной на C/C++

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dll
Взаимодействие происходит по стандартному алгоритму: в скрипте QLua(Lua) вызываются функции из подключенной при помощи директивы "require" библиотеки DLL, написанной на языке C/C++ (о том как ее создать, можно прочитать в данной статье). В функцию можно передавать данные, в виде параметров. Обрабатывать их внутри функции и получать в скрипт результат(ы) выполнения функции.

Для этого служит Lua-стек, который представляет из себя массив разнотипных данных (таблицу Lua). Первое значение, помещенное в стек, получает индекс 1, второе - 2 и т.д.

Для каждого отдельного вызова функции автоматически используется отдельный стек!

Получить результаты можно обычным способом, и, если их несколько, используя параллельное присваивание.
Пример, если бы функция из приведенного примера DLL возвращала 4 значения:Смотреть полностью...

Коннектор DLL QUIK - QLua(Lua) - C++

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dll
Для Quik 8 x64 (Lua 5.1) скачать готовое решение VS 2019 Community можно по этой ссылке 
Для Quik 8 x64 (Lua 5.3.5) скачать готовое решение VS 2019 Community можно по этой ссылке

Для того, чтобы обмениваться данными между скриптом Qlua и приложением на C# требуется библиотека DLL, написанная на языке C/C++. Для этого в Visual Studio нужно "Создать проект", выбрав язык C++ и тип проекта "Пустой проект". Создайте новую папку для проекта, если необходимо.Смотреть полностью...