Из QLua (Lua) в Excel (CSV)

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

csvФайл CSV-формата это обычный текстовый файл, с которым Excel и аналогичные программы могут работать как с таблицей. Каждая строка таблицы в этом файле записывается как новая строка со знаком переноса в конце, а значения полей разделены между собой каким-то символом, чаще ";". В самой первой строке такого файла можно (не обязательно) указать названия столбцов, так же через ";".

Ниже приведен пример создания такого файла и записи в него данных о совершенных сделках средствами QLua(Lua):

Код скрипта QLua
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
Run = true;		-- Флаг поддержания работы скрипта
 
TradeNums = {};	-- Массив для хранения номеров записанных в файл сделок (для предотвращения дублирования)
 
-- Вызывается терминалом QUIK в момент запуска скрипта
function OnInit()
	-- Создает, или открывает для чтения/добавления файл CSV в той же папке, где находится данный скрипт
	CSV = io.open(getScriptPath().."/MyTrades.csv", "a+");
	-- Встает в конец файла, получает номер позиции
	local Position = CSV:seek("end",0);
	-- Если файл еще пустой
	if Position == 0 then
		-- Создает строку с заголовками столбцов
		local Header = "Дата и время;Код класса;Код бумаги;Номер сделки;Номер заявки;Операция;Цена;Количество\n"
		-- Добавляет строку заголовков в файл
		CSV:write(Header);
		-- Сохраняет изменения в файле
		CSV:flush();
	end;
end;
 
-- Основная функция скрипта (пока работает она, работает скрипт)
function main()
	-- Цикл, поддерживающий работу скрипта
	while Run do sleep(100); end;
end;
 
-- Вызывается терминалом QUIK в момент остановки скрипта
function OnStop()
	-- Выключает флаг, чтобы остановить цикл while внутри main
	Run = false;
	-- Закрывает открытый CSV-файл
	CSV:close();
end;
 
-- Функция вызывается терминалом QUIK при совершении Вами новой сделки
-- (обычно вызывается по 2 раза для каждой сделки)
function OnTrade(trade)
	-- Перебирает массив с номерами записанных сделок (в обратном порядке)
	for i=#TradeNums,1,-1 do
		-- Если данная сделка уже была записана, выходит из функции
		if TradeNums[i] == trade.trade_num then return; end;
	end;
 
	-- Если мы здесь, значит сделка не была найдена в числе уже записанных
	-- Добавляет в массив номер новой сделки
	TradeNums[#TradeNums + 1] = trade.trade_num;
	-- Вычисляет операцию сделки
	local Operation = "";
	if CheckBit(trade.flags, 2) == 1 then Operation = "Продажа"; else Operation = "Покупка"; end;
	-- Создает строку сделки для записи в файл ("Дата и время;Код класса;Код бумаги;Номер сделки;Номер заявки;Операция;Цена;Количество\n")
	local TradeLine = 	os.date("%c", os.time(trade.datetime))..";"..
						trade.class_code..";"..
						trade.sec_code..";"..
						trade.trade_num..";"..
						trade.order_num..";"..
						Operation..";"..
						trade.price..";"..
						trade.qty.."\n";
	-- Записывает строку в файл
	CSV:write(TradeLine);
	-- Сохраняет изменения в файле
	CSV:flush();
end;
 
-- Функция возвращает значение бита (число 0, или 1) под номером bit (начинаются с 0) в числе flags, если такого бита нет, возвращает nil
function CheckBit(flags, bit)
   -- Проверяет, что переданные аргументы являются числами
   if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!"); end;
   if type(bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!"); end;
   local RevBitsStr  = ""; -- Перевернутое (задом наперед) строковое представление двоичного представления переданного десятичного числа (flags)
   local Fmod = 0; -- Остаток от деления
   local Go = true; -- Флаг работы цикла
   while Go do
      Fmod = math.fmod(flags, 2); -- Остаток от деления
      flags = math.floor(flags/2); -- Оставляет для следующей итерации цикла только целую часть от деления
      RevBitsStr = RevBitsStr ..tostring(Fmod); -- Добавляет справа остаток от деления
      if flags == 0 then Go = false; end; -- Если был последний бит, завершает цикл
   end;
   -- Возвращает значение бита
   local Result = RevBitsStr :sub(bit+1,bit+1);
   if Result == "0" then return 0;
   elseif Result == "1" then return 1;
   else return nil;
   end;
end;

Скрипт создает файл следующего вида:
Таблица
Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!