Блог им. vitales

Скрипт lua Баланс покупок/продаж

Всем привет. Переделал первоначальную версию скрипта. Исправил некоторые ошибки и немного расширил функционал. Теперь скрипт может сохранять данные в текстовый файл, который потом можно анализировать в другой программе (например exсel). Также, в отличии от первого варианта, скрипт показывает в таблице усредненную цену, по которой прошли сделки. В первом варианте отображалась цена последней сделки. И в скрипте добавлен показ накопленной дельты за все время пока скрипт работает.

TICER = "SBER";
CLASS_CODE = "TQBR";
FilePath = getScriptPath() .. "\\export.txt";--путь к файлу
save = false;--сохранять данные в файл если false нет, true да

f = nil;
stopped = false;
t_id = nil
H = -1;
M = -1;
VSELL = 0;
VBUY  = 0;
CDelta = 0;
CountTrans = 0;
PriceTrans = 0.0; 
t = "";
function OnInit()
    CountTrans = 0;
        if save then f = io.open(FilePath,"w"); end
        CreateTable();
end 

function main() 
        while not stopped do 
          if IsWindowClosed(t_id) then
         stopped = true;
      end       
          sleep(10);
        end
end

function CreateTable()
   t_id = AllocTable(); 
   AddColumn(t_id, 0, "Время", true, QTABLE_STRING_TYPE, 10);
   AddColumn(t_id, 1, "BUY", true, QTABLE_INT_TYPE, 10);
   AddColumn(t_id, 2, "SELL", true, QTABLE_INT_TYPE, 10);
   AddColumn(t_id, 3, "Дельта V", true, QTABLE_INT_TYPE, 10);   
   AddColumn(t_id, 4, "AVG Цена", true, QTABLE_DOUBLE_TYPE, 15);
   AddColumn(t_id, 5, "Накопленная Дельта", true, QTABLE_INT_TYPE, 15);
   AddColumn(t_id, 6, "Кол-во сделок", true, QTABLE_DOUBLE_TYPE, 12);   
   tab = CreateWindow(t_id);
   local NAME = tostring(getParamEx(CLASS_CODE,TICER,"LONGNAME").param_image);
   SetWindowCaption(t_id, TICER.." ("..NAME..") Баланс покупок/продаж");
   SetTableNotificationCallback(t_id, EventCallBack);
end

function Calc(alltrade)
        if bit.test(alltrade.flags, 0) then VSELL = VSELL+alltrade.qty;  --Продажа
        else VBUY  = VBUY+alltrade.qty;  end                            
        CountTrans = CountTrans+1;
        PriceTrans = PriceTrans+alltrade.price;                 
end

function OnAllTrade(alltrade)    
        if alltrade.sec_code == TICER then      
                local Rows, Col = GetTableSize(t_id);
                
                if H==-1 or H~= alltrade.datetime.hour then 
                        H = alltrade.datetime.hour;
                        M = alltrade.datetime.min;
                        t = tostring(alltrade.datetime.hour)..":"..tostring(alltrade.datetime.min);
                end
                if M==alltrade.datetime.min then
                        Calc(alltrade);
                else                                    
                M=alltrade.datetime.min;        
                        InsertRow(t_id, -1);                                               
                        local Delta = VBUY-VSELL;
                        Price = PriceTrans/CountTrans;
                        SetCell(t_id, Rows, 6, tostring(CountTrans));                   
                        SetCell(t_id, Rows, 0, t);
                        SetCell(t_id, Rows, 1, tostring(VBUY));
                        SetCell(t_id, Rows, 2, tostring(VSELL));                           
                        SetCell(t_id, Rows, 3, tostring(Delta));
                        local SEC_SCALE = tostring(getParamEx(CLASS_CODE,TICER,"SEC_SCALE").param_value);
                        SEC_SCALE = string.format("%.0f",SEC_SCALE);                    
                        SetCell(t_id, Rows, 4, string.format("%."..SEC_SCALE.."f", tostring(Price)));
                   if Rows>=2 then
                           local OldPrice = tonumber(GetCell(t_id,Rows-1,4).image);
                           if OldPrice>Price then 
                                        Red(Rows,4); 
                           else 
                                        Green(Rows,4);
                           end
                           CDelta = tonumber(GetCell(t_id,Rows-1,5).image);
                           CDelta = CDelta + Delta;                        
                        else 
                          CDelta = Delta;
                        end
                        SetCell(t_id, Rows, 5, tostring(CDelta));
                    if Delta<0 then Red(Rows,3); end
                    if Delta>0 then Green(Rows,3); end
                    if CDelta<0 then Red(Rows,5); end
                    if CDelta>0 then Green(Rows,5); end                                                   
                   if save then
                                local Str = tostring(H)..";"..tostring(M)..";"..tostring(VBUY)..";"..tostring(VSELL)..";"
                                                ..tostring(Delta)..";"..tostring(Price)..";"..tostring(CDelta);
                           Str=Str.."\n";
                           SaveFile(Str);
                        end
                t = tostring(alltrade.datetime.hour)..":"..tostring(alltrade.datetime.min);                        
                    VBUY = 0;VSELL = 0;
                        PriceTrans = 0;
                        CountTrans = 0;
                        Calc(alltrade);
                end
        end --if alltrade.sec_code == TICER then        
end

function SaveFile(Str)
        if f ~= nil then 
                f:write(Str);           
                f:flush();                               
        end
end

function Red(row,col)
        SetColor(t_id, row, col, RGB(255,0,0), RGB(0,0,0), RGB(255,0,0), RGB(0,0,0));
end
function Yellow(row,col)
        SetColor(t_id, row, col, RGB(240,240,0), RGB(0,0,0), RGB(240,240,0), RGB(0,0,0));
end
function Green(row,col)
        SetColor(t_id, row, col, RGB(0,200,0), RGB(0,0,0), RGB(0,200,0), RGB(0,0,0));
end


function EventCallBack(t_id, msg, par1, par2)
   if msg==QTABLE_CLOSE then
     OnStop();
   end;
end

function OnStop(s)
  if f ~= nil then f:close(); end
  if t_id ~= nil then
    DestroyTable (t_id);
  end;
  stopped = true;
end



★48
26 комментариев
Пиши исчо 
avatar
данные лучше пишите в csv — удобнее потом анализировать excel`ем. Можно на поток настроить, только надо, чтобы csv закрыт был файл. Ну это лирика. А еще рекомендую сделать цикл по таблице обезличенных сделок, чтобы не копить данные, а просчитать все имеющиеся :)
avatar
Vitaliy, В комментариях к первому варианту мне предлагали что то подобное сделать, пока руки не доходять, мало свободного времени. Я этот вариант почти неделю делал и отлаживал. Не удобно в квик нет отладчика, да и опыта программирования на lua мало. Встроенная справка не очень помогает. А в текстовом файле в качестве символа разделителя используется точка запятая как и в csv файлах. Если поменять расширение файла, то он без проблем откроется в эксель.
avatar
Виталий, Возможно, я и предлагал. Мои пути развития данного скрипта были следующие: сначала я сделал бота, который собирал информацию и складывал в csv, позже я научил его разделять по заданному интервалу, чтобы удобнее было анализировать (суммировал по минутам, по 5 минут — как задам), потом анализируя эксель и балуя с этим всем мракобесием, я нашел своего рода грааль и его превратил в индикатор для Квика. Потом шлифовка для быстродействия и тд. В общем поле деятельности тут есть — массивы освоите потихоньку в процессе :)
avatar
Vitaliy, Понятно, спасибо за подсказки. 
avatar
Vitaliy, 
А еще рекомендую сделать цикл по таблице обезличенных сделок, чтобы не копить данные, а просчитать все имеющиеся :)
каждый расчет скрипта пробегать циклом таблицу обезличенных сделок?
avatar
Андрей К, Зачем же каждый?! Достаточно при запуске. 
avatar
код сохранять как *.luac? сохранил как *.lua — не работает
avatar
Glago, Файл скрипта, должен иметь расширение lua. Почему не работает, ошибку выдает? После запуска скрипта сначала появляется пустая таблица. Скрипту необходимо некоторое время что бы собрать данные за 1 минуту. После этого таблица будет пополнятся данными раз в 1 минуту.
avatar
Виталий, никакой ошибки не выдает, просто висит пустое окно и на 2 и 3… минуты. хз квик 8.4.1.6 Win 10 Pro x64. Скрипты из этого и прошлого поста запускал из *.luac файла, работает! Среда Lua на компе не установлена, и lua не прописан в PATH. Я копировал отсюда код в NotePad++ (кодировка по умолчанию ANSI), потом в нём сохранял как *.lua и *.luac. Из первого не запускалось, поменял на *.luac и заработало. Но всё равно поставил за пост +) 
avatar
Glago, Странно, я не знаю почему у вас с расширением Lua не работает.  У меня версия квик такая же. Тоже 64 бит, только ось Win 7.  Ни каких дополнительных программ не устанавливал. Скачал дистрибутив от брокера, установил, и кроме настроек рабочего места больше ни чего не трогал.
avatar
Виталий, получается разница только в ОСях. Про финт с луак видел на форуме квика примерно год назад. Подробностей по той теме сейчас уже не помню, поскольку плохо ориентируюсь в программировании)
avatar
Glago, Я точно не уверен, но возможно это как то связано именно с ОС. Вероятно, что в вашей ОС расширение luac ассоциировано с языком LUA. А расширение lua ОС не воспринимает. У меня работает как с расширением lua так и с расширением luac. Специально проверил у себя поменяв расширение файла на luac.
avatar
ещё в прошлом скрипте обнаружился баг, когда не двузначные минуты некорректно отображаются)



avatar
Glago, Это не совсем баг. Преобразуя числовое значение в строковое, впереди просто не добавляются незначащие нули. То есть запись 23:3 это есть 23 часа 03 минуты. Но «03» это строка числа 03 не бывает. Попробуйте в экселе в числовую ячейку напишите 03 эксель преобразует его в 3. 
avatar
Я чего-то не вкурил: TICER это переменная? вместо неё мы можем написать абракадабра = «инструмент? если это переменная почему она явно не объявляется или в луа это необязательно?
avatar
Glago, Глобальная переменная. В ней пишешь код нужного инструмента. В lua нет необходимости предварительно объявлять переменную и указывать ее тип.
avatar
ВАЖНО! Недопустим вызов функций Clear и DestroyTable для t_id внутри функции обратного вызова f_cb, назначенной на таблицу с данным t_id.
avatar
protorus, Почему?
avatar
Виталий, А кто его знает? Просто запомнил, что так написано в источниках которые встречал. Но я это все равно проверил и ничего подозрительного не обнаружил.
Например, здесь https://arqatech.com/upload/iblock/194/quik_lua.zip. Интерпретатор языка Lua.pdf. Раздел 3.15.16.
Хотя может сам не так понял.
avatar
protorus, Да, действительно написано, что не допускается. О причинах ни чего не сказано. Но у меня вроде работает, ошибок времени выполнения нет. 
avatar
спасибо
avatar
скажите, как и где изменить накопление на другой интервал? 15 минут к примеру
avatar
Infomax, В этом скрипте такого нет. Накопленная дельта считается за все время пока сприпт работает. Если будет свободное время попробую сделать такую возможность.
avatar
Виталий, спасибо

avatar

теги блога Виталий А

....все тэги



UPDONW
Новый дизайн