<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[QUIK -> DDE &mdash; СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"]]></title>
		<link>https://quik2dde.ru/viewtopic.php?id=359</link>
		<atom:link href="https://quik2dde.ru/extern.php?action=feed&amp;tid=359&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"».]]></description>
		<lastBuildDate>Wed, 15 Dec 2021 21:02:00 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=3395#p3395</link>
			<description><![CDATA[<div class="quotebox"><cite>RRR пишет:</cite><blockquote><p> Хотел добавить столбцы ВходящиеСредства, ТекущиеСредства, что бы учитывать изменения средств после каждой сделки, это возможно или я не там где смотрел...?</p></blockquote></div><p>getPortfolioInfo (STRING firm_id, STRING client_code)<br />вместо ТекущиеСредства, лучше использовать НаПокупНеМаржин, т.к. этот параметр отображает реальные ваши средства без учета позиций, открытых по маржируемым инструментам.<br />например, купив акции сбера, вы заплатите не единицу денег, а 1 * d_long, где d_long - понижающий коэфф. <br />в ВТБ24 (у меня) он 0.22, что означает, что вместо 100тыс.руб с меня возьмут всего 22тыс.руб. и ТекущиеСредства будут завышены, относительно реальной позиции.<br />коэфф. можно посмотреть в таблице купить/продать (щелкнуть 2 раза левой кнопкой мышки по таблице &quot;Клиентский портфель&quot;).</p>]]></description>
			<author><![CDATA[null@example.com (kalikazandr)]]></author>
			<pubDate>Wed, 15 Dec 2021 21:02:00 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=3395#p3395</guid>
		</item>
		<item>
			<title><![CDATA[Re: СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=3394#p3394</link>
			<description><![CDATA[<div class="quotebox"><cite>kalikazandr пишет:</cite><blockquote><div class="quotebox"><cite>RRR пишет:</cite><blockquote></blockquote></div><p>код в помойку, самое правильное решение.</p></blockquote></div><p>Согласен, так и придется сделать, просто праздное любопытство...<br />Ваш скрипт на много красивее и лаконичней, мне он больше нравится. <br />Такой вопрос, getNumberOf() ведь не работает с значениями в таблице &quot;Клиентский портфель&quot;,по крайне мере ничего&nbsp; подобного я не смог найти. Хотел добавить столбцы ВходящиеСредства, ТекущиеСредства, что бы учитывать изменения средств после каждой сделки, это возможно или я не там где смотрел...?</p>]]></description>
			<author><![CDATA[null@example.com (RRR)]]></author>
			<pubDate>Wed, 15 Dec 2021 12:31:14 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=3394#p3394</guid>
		</item>
		<item>
			<title><![CDATA[Re: СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=3393#p3393</link>
			<description><![CDATA[<div class="quotebox"><cite>RRR пишет:</cite><blockquote><p>Как-то нарыл один почти простой скрипт, который выводит совершённые сделки в экселевский файл.</p></blockquote></div><p>код в помойку, самое правильное решение.<br />ни о каком динамическом сохранении сделок в файл не может быть речи, если в процессе записи будет конец света, то запись будет рваная, а проверять, что там да как - нет смысла.</p><p>встраиваете код ниже в любого вашего робота, по завершению работы которого, нужно вызвать save_trade().<br />либо используйте как самостоятельного бота - по окончании торговли запустить и остановить.<br />сделки будут сохранены в папку со скриптом.<br /></p><div class="codebox"><pre><code>--save_trade.lua
local exitflag
local path = getScriptPath()

--направление сделки
local function trades_bs(flags)
    if bit.band(flags, 0x4) ~= 0 then
        return &quot;Продажа&quot;
    else
        return &quot;Купля&quot;
    end
end
local function save_trade()
    local n = getNumberOf(&quot;trades&quot;)
    if n &lt; 1 then return end
    
    local t = getItem(&quot;trades&quot;, n-1)
    local curr_date = os.date(&quot;%Y.%m.%d&quot;, os.time(t.datetime))
    local f = io.open(path..&quot;\\trades_&quot;..curr_date..&quot;.csv&quot;,&#039;w&#039;)
    f:write(&quot;Номер;ТС;Дата;Время;Код класса;Инструмент;Операция;Цена;Кол-во;Объем\n&quot;)
    local res, px = {}
    for i=0, n-1 do
        t = getItem(&quot;trades&quot;, i)
        px = os.time(t.datetime)
        if os.date(&quot;%Y.%m.%d&quot;, px) == curr_date then
            res[#res+1] = t.trade_num..&quot;;&quot;..
                t.account..&quot;;&quot;..
                os.date(&quot;%Y.%m.%d;%H:%M:%S&quot;,px)..&quot;;&quot;..
                t.class_code..&quot;;&quot;..
                t.sec_code..&quot;;&quot;..
                trades_bs(t.flags)..&quot;;&quot;..
                string.gsub(tostring(t.price), &quot;%.&quot;, &quot;,&quot;)..&quot;;&quot;..
                math.floor(t.qty)..&quot;;&quot;..
                string.gsub(tostring(t.value), &quot;%.&quot;, &quot;,&quot;)
        end
    end
    f:write(table.concat(res,&quot;\n&quot;)); f:flush(); f:close()
end
function main()
    while not exitflag do
        --some code
        sleep(1)
    end
    save_trade()
end
function OnStop()
    exitflag = true
    return 300
end</code></pre></div><p>з.ы. луа не любит кириллицу, папки и названия файлов нужно писать латиницей.</p>]]></description>
			<author><![CDATA[null@example.com (kalikazandr)]]></author>
			<pubDate>Tue, 14 Dec 2021 16:30:27 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=3393#p3393</guid>
		</item>
		<item>
			<title><![CDATA[СКРИПТ "ХРАНИТЕЛЬ СДЕЛОК"]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=3392#p3392</link>
			<description><![CDATA[<p>Как-то нарыл один почти простой скрипт, который выводит совершённые сделки в экселевский файл.<br />Всё бы ничего, но ведёт он себя оч. странно. Обращался к его же создателю, но ответ получился невразумительным, он не знает что c ним произошло или что произошло с обновлениями Quik-а, раз вылазит такая хрень.<br />Если в терминале ещё не было сделок, то скрипт стартует без помех.<br /><span class="postimg"><img src="https://quik2dde.ru/static-img/359/d9814260584d.jpg" alt="https://quik2dde.ru/static-img/359/d9814260584d.jpg" /></span><br />Стоит только совершить сделку или несколько, сразу выскакивает окошко с ошибкой, <br />которое сигнализирует о неисправности скрипта, <br />но скрипт продолжает дальше работать.<br /><span class="postimg"><img src="https://quik2dde.ru/static-img/359/2d696870c9d4.jpg" alt="https://quik2dde.ru/static-img/359/2d696870c9d4.jpg" /></span><br /><span class="postimg"><img src="https://quik2dde.ru/static-img/359/e51e4ec3893e.jpg" alt="https://quik2dde.ru/static-img/359/e51e4ec3893e.jpg" /></span><br />Это выход из сделки, <br />всё так же, ошибка и работающий скрипт<br /><span class="postimg"><img src="https://quik2dde.ru/static-img/359/6641dbd4f1c0.jpg" alt="https://quik2dde.ru/static-img/359/6641dbd4f1c0.jpg" /></span><br />Если теперь скрипт остановить и попытаться запустить по новой, <br />то он уже не запуститься и будет выдавать всё ту же ошибку<br /><span class="postimg"><img src="https://quik2dde.ru/static-img/359/88f7f7f64b18.jpg" alt="https://quik2dde.ru/static-img/359/88f7f7f64b18.jpg" /></span></p><p>По идее всё должно работать, но он не работает. Подскажите где закралась ошибка в коде.<br /></p><div class="codebox"><pre><code>Run = true; -- флаг работы цикла в main
 
DataFolder = &#039;&#039;; -- Полный путь к папке &quot;Данные(c)quikluacsharp.ru&quot;
TradesFiles = {};-- Массив дескрипторов файлов
 
function OnInit()
   -- Получает полный путь к папке &quot;Данные(c)quikluacsharp.ru&quot;
   DataFolder = getWorkingFolder()..&#039;\\Данные(c)quikluacsharp.ru\\&#039;;
   -- Создает папки по всем найденным счетам
   CreateAccountsFolders();
   -- Записывает все ранее не записанные сделки из таблицы &quot;Сделки&quot; в файлы
   CheckAndSaveTerminalTrades();
end;
 
function main()
   while Run do      
      sleep(1);
   end;   
end;
 
-- Создает каталоги по всем найденным счетам
function CreateAccountsFolders()
   -- Перебирает все счета
   for i=0, getNumberOf(&quot;trade_accounts&quot;)-1 do
      -- Получает номер счета
      local Account = getItem(&quot;trade_accounts&quot;, i).trdaccid;
      -- Получает путь
      local Path = &#039;&quot;&#039;..DataFolder..Account..&#039;\\&quot;&#039;;
      -- Если каталог не существует
      if os.execute(&#039;cd &#039;..Path) == 1 then
         -- Создает каталог
         os.execute(&#039;mkdir &#039;..Path); 
      end;
   end;
end;
 
-- Проверяет записана ли данная сделка в файл истории
function CheckTradeInFile(trade)
   -- Получает путь к файлу инструмента в папке торгового счета
   local PathAccountSec = DataFolder..trade.account..&#039;\\&#039;..trade.sec_code..&#039;.csv&#039;;
   -- Пытается открыть файл текущего инструмента в режиме &quot;чтения&quot;
   local TradesFile = io.open(PathAccountSec,&quot;r&quot;);
   -- Если файл не существует, то сделка не записана
   if TradesFile == nil then return false;
   else -- Если файл существует
      -- Получает индекс файла
      local FileIndex = trade.account..&#039;_&#039;..trade.sec_code;
      -- Если файл еще не открыт для дописывания
      if TradesFiles[FileIndex] == nil then
         -- Открывает файл текущего инструмента в режиме &quot;дописывания&quot;
         TradesFiles[FileIndex] = io.open(PathAccountSec,&quot;a+&quot;);
      end;
      -- Перебирает строки файла
      local Count = 0; -- Счетчик строк
      for line in TradesFile:lines() do
         Count = Count + 1;
         if Count &gt; 1 and line ~= &quot;&quot; then
            -- Если номера сделок совпадают, то сделка записана
            local i = 0;
            for str in line:gmatch(&quot;[^;^\n]+&quot;) do
               i = i + 1;
               if i == 3 and tonumber(str) == trade.trade_num then
                  TradesFile:close();
                  return true; 
               end;
            end;
         end;      
      end;
   end;
   TradesFile:close();
   return false;
end;
-- Записывает все ранее не записанные сделки из таблицы &quot;Сделки&quot; в файлы
function CheckAndSaveTerminalTrades()
   local trade = nil;
   -- Перебирает все сделки в таблице &quot;Сделки&quot;
   for i=0,getNumberOf(&quot;trades&quot;)-1,1 do      
      trade = getItem (&quot;trades&quot;, i);
      -- Если данная сделка еще не записана в файл истории
      if not CheckTradeInFile(trade) then        
         -- Добавляет сделку в файл истории
         AddTradeInFile(trade);
      end;
   end;
end;
-- Добавляет новую сделку в файл истории
function AddTradeInFile(trade)
   local DateTime = trade.datetime;
   local Date = tonumber(DateTime.year);
   local month = tostring(DateTime.month);
   if #month == 1 then Date = Date..&quot;0&quot;..month; else Date = Date..month; end;
   local day = tostring(DateTime.day);
   if #day == 1 then Date = Date..&quot;0&quot;..day; else Date = Date..day; end;
   Date = tonumber(Date);
   local Time = &quot;&quot;;
   local hour = tostring(DateTime.hour);
   if #hour == 1 then Time = Time..&quot;0&quot;..hour; else Time = Time..hour; end;
   local minute = tostring(DateTime.min);
   if #minute == 1 then Time = Time..&quot;0&quot;..minute; else Time = Time..minute; end;
   local sec = tostring(DateTime.sec);
   if #sec == 1 then Time = Time..&quot;0&quot;..sec; else Time = Time..sec; end;
   Time = tonumber(Time);
   -- Если ночная сделка, смещает дату на 1 день вперед
   if Time &lt; 90000 then
      local seconds = os.time(DateTime);
      seconds = seconds + 24*60*60;
      DateTime = os.date(&quot;*t&quot;,seconds);
      Date = tonumber(DateTime.year);
      month = tostring(DateTime.month);
      if #month == 1 then Date = Date..&quot;0&quot;..month; else Date = Date..month; end;
      day = tostring(DateTime.day);
      if #day == 1 then Date = Date..&quot;0&quot;..day; else Date = Date..day; end;
      Date = tonumber(Date);
   end;
   local Operation = &quot;&quot;;
   if CheckBit(trade.flags, 2) == 1 then Operation = &quot;S&quot;; else Operation = &quot;B&quot;; end;
 
   -- Добавляет сделку в массив
   local Trade = {};
   Trade.Account = trade.account;
   Trade.Sec_code = trade.sec_code;
   Trade.Num = trade.trade_num;
   Trade.Date = Date;
   Trade.Time = Time;
   Trade.Operation = Operation;
   Trade.Qty = tonumber(trade.qty);
   Trade.Price = tonumber(trade.price);
   Trade.Hint = &quot;Счет: &quot;..Trade.Account..&quot;_Номер: &quot;..trade.trade_num..&quot;_Дата: &quot;;
   if #day == 1 then Trade.Hint = Trade.Hint..&quot;0&quot;..day..&quot;/&quot;; else Trade.Hint = Trade.Hint..day..&quot;/&quot;; end;
   if #month == 1 then Trade.Hint = Trade.Hint..&quot;0&quot;..month..&quot;/&quot;..DateTime.year; else Trade.Hint = Trade.Hint..month..&quot;/&quot;..DateTime.year; end;
   if #hour == 1 then Trade.Hint = Trade.Hint..&quot;_Время: 0&quot;..hour..&quot;:&quot;; else Trade.Hint = Trade.Hint..&quot;_Время: &quot;..hour..&quot;:&quot;; end;
   if #minute == 1 then Trade.Hint = Trade.Hint..&quot;0&quot;..minute..&quot;:&quot;; else Trade.Hint = Trade.Hint..minute..&quot;:&quot;; end;
   if #sec == 1 then Trade.Hint = Trade.Hint..&quot;0&quot;..sec; else Trade.Hint = Trade.Hint..sec; end;
   Trade.Hint = Trade.Hint..&quot;_Количество: &quot;..trade.qty;
   Trade.Hint = Trade.Hint..&quot;_Цена: &quot;..trade.price;
 
   -- Получает путь к файлу инструмента в папке торгового счета
   local PathAccountSec = DataFolder..Trade.Account..&#039;\\&#039;..Trade.Sec_code..&#039;.csv&#039;;
   local FileIndex = Trade.Account..&#039;_&#039;..Trade.Sec_code;
   -- Если файл еще не открыт, или не существует
   if TradesFiles[FileIndex] == nil then
      -- Пытается открыть файл текущего инструмента в режиме &quot;дописывания&quot;
      TradesFiles[FileIndex] = io.open(PathAccountSec,&quot;a+&quot;);
      -- Если файл не существует, то сделка не записана
      if TradesFiles[FileIndex] == nil then 
         -- Создает файл в режиме &quot;записи&quot;
         TradesFiles[FileIndex] = io.open(PathAccountSec,&quot;w&quot;);
         -- Закрывает файл
         TradesFiles[FileIndex]:close();
         -- Открывает уже существующий файл в режиме &quot;дописывания&quot;
         TradesFiles[FileIndex] = io.open(PathAccountSec,&quot;a+&quot;);
      end;
   end;
   -- Встает в начало файла
   TradesFiles[FileIndex]:seek(&quot;set&quot;,0);
   -- Если файл пустой
   if TradesFiles[FileIndex]:read() == nil then
      -- Добавляет строку заголовков
      TradesFiles[FileIndex]:write(&quot;Счет;Код бумаги;Номер сделки;Дата сделки;Время сделки;Операция;Количество;Цена;Текст подсказки&quot;, &quot;\n&quot;);
   end;
   -- Встает в конец файла
   TradesFiles[FileIndex]:seek(&quot;end&quot;,0);
   -- Записывает сделку в файл
   TradesFiles[FileIndex]:write(Trade.Account..&quot;;&quot;..Trade.Sec_code..&quot;;&quot;..Trade.Num..&quot;;&quot;..Trade.Date..&quot;;&quot;..Trade.Time..&quot;;&quot;..Trade.Operation..&quot;;&quot;..Trade.Qty..&quot;;&quot;..Trade.Price..&quot;;&quot;..Trade.Hint, &quot;\n&quot;);TradesFiles[FileIndex]:flush();
end;
 
function OnTrade(trade)
   -- Если данная сделка еще не записана в файл истории
   if not CheckTradeInFile(trade) then        
      -- Добавляет сделку в файл истории
      AddTradeInFile(trade);
   end;
end;
 
function OnStop()
   -- Закрывает все файлы
   for key,Handle in pairs(TradesFiles) do
      if Handle ~= nil then Handle:close(); end;
   end;
   Run = false;
end;
 
-- Функция возвращает значение бита (число 0, или 1) под номером bit (начинаются с 0) в числе flags, если такого бита нет, возвращает nil
function CheckBit(flags, bit)
   -- Проверяет, что переданные аргументы являются числами
   if type(flags) ~= &quot;number&quot; then error(&quot;Ошибка!!! Checkbit: 1-й аргумент не число!&quot;); end;
   if type(bit) ~= &quot;number&quot; then error(&quot;Ошибка!!! Checkbit: 2-й аргумент не число!&quot;); end;
   local RevBitsStr  = &quot;&quot;; -- Перевернутое (задом наперед) строковое представление двоичного представления переданного десятичного числа (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 == &quot;0&quot; then return 0;     
   elseif Result == &quot;1&quot; then return 1;
   else return nil;
   end;
end;</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (RRR)]]></author>
			<pubDate>Tue, 14 Dec 2021 10:24:21 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=3392#p3392</guid>
		</item>
	</channel>
</rss>
