
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Все записи автора Дмитрий (Admin)
Из QLua (Lua) в Excel (CSV)
Автор записи: Дмитрий (Admin)
Файл CSV-формата это обычный текстовый файл, с которым Excel и аналогичные программы могут работать как с таблицей. Каждая строка таблицы в этом файле записывается как новая строка со знаком переноса в конце, а значения полей разделены между собой каким-то символом, чаще ";". В самой первой строке такого файла можно (не обязательно) указать названия столбцов, так же через ";".
Ниже приведен пример создания такого файла и записи в него данных о совершенных сделках средствами QLua(Lua):
Смотреть полностью...
СХЕМА: Торговые циклы в QUIK
Автор записи: Дмитрий (Admin)Пример реализации функции обратного вызова OnAllTrade внутри DLL
Автор записи: Дмитрий (Admin)
Таким образом можно любую встроенную в QLua функцию заменить функцией в DLL, в результате скрипт QLua может содержать только одну строку подключения библиотеки, а всю обработку можно вынести в DLL, а из нее в C#.
[su_spoiler title="Код QLua(Lua)" style="fancy"]
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; |
[/su_spoiler]
[su_spoiler title="Код DLL" style="fancy"]
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; } |
[/su_spoiler]
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Один из простейших способов отладки DLL (C/C++), работающей с именованной памятью
Автор записи: Дмитрий (Admin)
Создайте/откройте текстовый файл для записи отладочной информации (каждый новый вызов данного кода будет перезаписывать содержимое файла):
FILE *f = fopen("C:\\DLL_Log.txt", "w+"); // Создает файл лога |
Открывайте потом этот файл для чтения в Notepad++.
Объявите следующую функцию:
Смотреть полностью...
Запуск/завершение процесса (программы) из C/C++
Автор записи: Дмитрий (Admin)
В начале, нужно объявить необходимые переменные:
TCHAR szPath[] = TEXT("info.exe"); // Путь к файлу // Необходимые для запуска процесса структуры STARTUPINFO si; PROCESS_INFORMATION pi; |
Такой код запускает процесс (программу):
Смотреть полностью...
Узнать из программы C/C++ запущен ли на компьютере процесс (программа)
Автор записи: Дмитрий (Admin)
Необходимо подключить заголовочный файл tlhelp32.h:
Смотреть полностью...
Вызов функций QLua(Lua) из DLL, написанной на C/C++
Автор записи: Дмитрий (Admin)
Для этого нужна обычная библиотека DLL, подключаемая к QLua, о том, как ее создать можете посмотреть здесь.
Пусть созданная Вами DLL называется "LuaCallback.dll", которая находится в корневом каталоге терминала QUIK.
Следующий пример 10 раз, с периодичностью в 1 секунду выведет сообщение с текстом "Привет из DLL" посредством вызова из DLL функции из Qlua скрипта MyLuaCallback():
[su_spoiler title="Код скрипта QLua" style="fancy"]
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; |
[/su_spoiler]
[su_spoiler title="Код DLL" style="fancy"]
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; } |
[/su_spoiler]
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!
Получение в QLua(Lua) данных из графиков и индикаторов
Автор записи: Дмитрий (Admin)
Чтобы получить доступ к графику(не индикатору) какого-либо инструмента нужно создать источник данных при помощи функции CreateDataSource().
ВАЖНО!!! Для получения новых данных, кроме тех, что уже есть в открытом графике на текущий момент (тем более, если он не открыт), требуется использовать одну из следующих функций: SetUpdateCallback(), или SetEmptyCallback(), о которых будет написано ниже.
[su_spoiler title="Описание функции CreateDataSource()" style="fancy"]
-- Функция предназначена для создания таблицы Lua и позволяет работать со свечами, полученными с сервера QUIK, а также реагировать на их изменение. ds, Error = CreateDataSource (class_code, sec_code, interval [, param]); -- Параметры: -- class_code - (STRING) код класса, например "SPBFUT" -- sec_code - (STRING) код бумаги, например "RIZ5" -- interval - (NUMBER) константа, обозначающая тайм-фрейм графика, например INTERVAL_M5 (полный список: https://quikluacsharp.ru/qlua-osnovy/spisok-konstant-tajm-frejmov-grafikov/) -- param - (STRING) необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы всех сделок, если задан – данные по этому параметру, например "BID" (возможные параметры смотрите ниже) -- Возвращаемые значения: -- ds - (TABLE) таблица с данными по свечам графика -- Error - (STRING) строка ошибки в случае неудачной попытки получить доступ к данным (тогда ds будет nil) -- Если график, к которому нужно подключиться не открыт в терминале, то данные заказываются с сервера, на их получение нужно время, -- по этому, рекомендуется добавлять вот такое ожидание, прежде, чем обращаться к ds: -- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт) while (Error == "" or Error == nil) and ds:Size() == 0 do sleep(1) end if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) end -- Примеры (одновременно можно подключаться к нескольким источникам данных): ds1 = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "last"); ds2 = CreateDataSource("QJSIM", "SBER", INTERVAL_M1); ds3, Error = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "bid"); if ds3 == nil then message('Ошибка подключения: '..Error); end; |
[/su_spoiler]Смотреть полностью...
Список констант тайм-фреймов графиков
Автор записи: Дмитрий (Admin)INTERVAL_TICK -- (0) Тиковые данные INTERVAL_M1 -- (1) 1 минута INTERVAL_M2 -- (2) 2 минуты INTERVAL_M3 -- (3) 3 минуты INTERVAL_M4 -- (4) 4 минуты INTERVAL_M5 -- (5) 5 минут INTERVAL_M6 -- (6) 6 минут INTERVAL_M10 -- (10) 10 минут INTERVAL_M15 -- (15) 15 минут INTERVAL_M20 -- (20) 20 минут INTERVAL_M30 -- (30) 30 минут INTERVAL_H1 -- (60) 1 час INTERVAL_H2 -- (120) 2 часа INTERVAL_H4 -- (240) 4 часа INTERVAL_D1 -- (1440) 1 день INTERVAL_W1 -- (10080) 1 неделя INTERVAL_MN1 -- (23200) 1 месяц |

