Суть такая убрал расчеты алгоритмов анализирующих Рынок назад в терминал. Индикаторы написаны через "замыкание", кушали в мега байтах - назад в килобайты. Проще синхронизация в разных таймфревов (подход 4 окон). А главное все можно рассмотреть на графике.
"Такого не было ни когда и вот опять" мое произведение уронило терминал.
Уж и не знаю кто здесь главнее мой скрипт, данная функция, или терминал.
Ziveleos, Огромное Вам спасибо! Очень ценно глубокомысленно талантливо!
Владимир, "Скальперский" это шаблон в подходах к организации торговле и удержанию позиции.
Что читать, не читать дело личное. Я лишь уточняю свой подход. John F.Ehlers (так правильно) опубликовал свой подход в четырех книгах в алгоритмах. Я одно время увлекся написав себе индикаторы, не которые до сих пор применяю в своих подхода. Отлично работает его "мгновенная линия тренда".
Это уже кому интересно, может посмотреть готовую реализацию не которых идей в свободном доступе у Николая.
Спасибо за предметное развитие темы и поддержку. Не с логий норм у меня (пока). Николай дал свои наработки для примера, Попробовал по своему разумению. Не прошла фильтрация (от разработчиков)? опубликовал даже поругал, Ответ 0 or nil?
Из Ваших публикаций на форуме, делаю краткий вывод: 1) Стратегия "скальперская" 2) Широкая диверсификация нужна на покрытие риска (> кол. тикеровв ) ну и конечно для заработка. 3) теперь понятна, грусть о потерянном рынке и подход "с высокой колокольне на все".
Я отошёл от таких подходов. Интересует средний срок и инвест. подход (Горизонт прогнозирования или цели). Именно о них я и рассуждаю в своих высказываниях. Именно здесь расхождение понятиях. Да и не считаю среднии, а фильтрую (Линия мгновенного тренда). отставание 1-3 периода данных в отличии 0.5 Периода. Это подходы Дхона Элерса. Надеюсь правильно на писал.
nikolz написал: Вот вам пример преимущества перед чистым LUA
Наверняка что то есть полезное, но большинству пользователей хотя бы с луа разобраться. Просматривая ветки ведь основные нарекания идут на взаимодействие скрипта с терминалом (движок). Бросал свои рабочие скрипты потому что поиск ошибки становился затратным по Времени. Сейчас все тупо пишу в лог, и придерживаюсь чем проще тем лучше! Но Вопросов к реализации полно.
Всем добрый день! Наконец дискуссия пошла в предметном русле русле.
swerg, Путать это мое Все. Так как моя личная подготовка слаба (уходит к истокам). Цель - уму разуму набираться. Не чего личного. Если чем то обидел прошу простить. Просто хочется от опытных пользователей предметного обсуждения вместо общих фраз.
Касаемо предмета. Переписал у себя т. всех сделок как показывает TGB, "и последний стал первым" - пока без нареканий. Обработку т. 'trades' веду в колбеке пример взял у Владимир, - работает. Но все ругают колбеки чего ждать от них не понятно,
Владимир написал: Время от времени даже солиднейшие компании с целой армией аналитиков высочайшей квалификации терпят миллиардные убытки
Недавний пример с "Colden Sachs" с ее хедж фондом или современные банкротства инцест банков. И что Одни капиталисты обули других. Или Ваш супер скрипт поучаствовал. "Зин а деньги где"?
Цитата
Владимир написал: Другое дело, что с деньгами намного легче зарабатывать, чем без них. А стабильность - это минимизация рисков
Согласен целиком и полностью.
Цитата
Владимир написал: снижение вероятности заработать много и быстро
Вероятность Выигрыша в начале нужно перетянуть на свою сторону - минимизация рисков один из подходов. А Вы мне помнится отрицаете обработку старых данных.
Цитата
Владимир написал: Сеточные алгоритмы как раз и относятся к высокорисковым.
Не знаю насчет, риска опыт мал, только в планах докрутить хорош больно во флате. Но есть подозрение что Маркет Мейкер активно пользует или ребята обеспечивающие ликвидность.
Нет гонять следить можно, Здесь ключевое стабильно зарабатывать.
Те ребята с которыми мы имеем дело на рынке, свои сделки готовят, читают рынок на раз два, инсайд, закрытые каналы и т.д. Там где серьёзные средства, существуют отдельные отделы, следящие за RM, отдельно трейдер, аналитический отдел, в общем структура.
Нет укусить откусить конечно можно и Ваш подход наверняка имеет место быть об это толь ко Вы можете судить.
Я же говорю о стабильности.
Ну к примеру была у меня сетка нашел алгоритм сам слепил торговал брент на минутках. Набирала до открытия ам. рынка "мама негорюй" Просыпались капиталисты все отберали еще и мои просили.
Скажите Сетку нельзя торговать очень широко применяется с широким спредом и более серьезными средствами.
Владимир написал: То, что лежит во внешних файлах, благодаря этой утилите будет выполнено так, как если бы оно было набито непосредственно в теле скрипта.
Не совсем понимаю, под "То, что лежит во внешних файлах" т.е. нужно создать внешний файл для обмена какой то информацией и с помощью этой ф. вставлять в код, правильно?
Ну я про смыл. Спасибо обдумаю.
Цитата
Владимир написал: Эта информация НЕ ТОЛЬКО для скрипта, но и для трейдера
К примеру я вывожу в окно скрипта инфо для трейдера и в log пишу, вроде хватает?
Но в любом случае спасибо за ответ на до обдумать.
Где мне попадалось Вы говорили о подготовке переменных на лету с помощью этой функции, можете показать?
Владимир, Простите что вмешиваюсь в столь полезный диспут.
Но не могу не сказать, что в постановке задачи на мой взгляд есть ошибка. Вот здесь.
Цитата
Владимир написал: А тормозной интерпретатор позволяет спокойно обслуживать сотни и даже тысячи тикеров - выше крыши для любого трейдера.
Ни Каму не нужны сотни молчу про тысячи тикеров в механической торговой программе (МТС), тем более брокеру!
Для отбора тикеров их фильтрации используют другие программы, а в МТС тикеры гонят уже зная чем торговать, как торговать, за с чет кого торговать!
Маркет (ММ), где то специалист, ММВБ автоматически сводит заявки. Для поддержания десятка тикеров требуются огромные средства когда их не хватает MM запрашивает помощь у других.
Через квик торговать FTP и жаловаться на быстродействие мягко говоря бессмысленно, по одно только причине MM РАЗРЕШЕНО делать задержки. Высокочастотники сидят в подвалах биржи.
Не, это оставьте себе, тем более у Вас есть куда его применить.
Не я про расширение функционала за ф. стандартной библиотеки (loadstring or load). Я у себя попробовал по образу и подобию не понял смысла в каких случаях она полезна?
Первый мой подход работает от Роберта Е. работает. считает правильно есть с чем сравнить. С памятью остаются "непонятки"? Зато можно модулем организовать!
Но вроде с кланяюсь к простате.
К стати есть реализация FIFO от разработчиков в колбеках. Фильтрует по классу память кушает на глазах, Но это все к вопросу задачи. Выкладывать нет смысла все есть в документации.
Владимир написал: Ну, покопайтесь в моих комментах, если интересно - мне лень.
Покопался, более того Ваши сообщения выделил по пользователю отдельно. Ну если оставить в покое Ваши рассуждения
Цитата
"бабла до мамы"
Кстати когда реализуете поделитесь.
Ну а если серьёзно у Вас оригинальный подход к программированию. Раньше попадались такие библиотеки на луа.
Не понял 1) преимущества ф. стандартной библиотеки loadstring. Если не сложно можно простой пример. 2) Файл txt пишите сложно это привычка , метод или что то еще. Ведь можно сохранить в формате луа а потом прочитать?
Владимир написал: Навскидку: если у меня бабла до мамы, а я хочу обрушить рынок, то ставлю в стакан две-три лонговые плиты и держу цену на какой-то из них, время от времени меняя, чтобы не скучно было. А когда рынок поверит, что курс вниз не пустят и отодвинет его вверх от моих плит, вываливаю накопленные бумаги.
Ни какое "бабла до мамы" не поможет если не читаете рынок. Рынки ходят за ликвидностью, Только Вы ее покажите, как она очутится в других руках. Ни чего личного это бизнес - больших дяденек.
Уважаемые форумчане вот инструкция от разработчика.
Использование Lua в Рабочем месте QUIK
1. Возможные подходы написания скриптов Lua для плагина QLua в Рабочем месте QUIK
Для запуска добавьте необходимый скрипт и нажмите на кнопку «Запустить». Запуск скрипта всегда начинается с обработки тела скрипта вне каких-либо функций, обозначим его . Можно выделить три подхода при создании Lua скрипта:
1. Вся необходимая логика описывается в области . В этом случае сценарии, описанные в теле скрипта вне каких-либо функций, после запуска выполняются только один раз, и скрипт переходит в состояние «Остановлен». Данный подход применим для Lua скриптов, целью которых является разовый подсчет необходимых данных. Скрипты с такой структурой выполняются в основном потоке РМ QUIK, ...
2. Вся необходимая логика описывается в функции с предопределенным именем main(). В этом случае после запуска скрипта первоначально выполняются сценарии, описанные в , если они присутствуют. Далее в отдельном потоке выполняется функция main(). ...
3. Событийная модель. При выборе данного подхода предоставляется гибкая среда выполнения пользовательских сценариев внутри QUIK, позволяющая мгновенно получать интересующие события от РМ QUIK, производя нужную обработку этих событий. Для обработки того или иного события необходимо в скрипте прописать функцию с предопределенным названием. Описание данных функций приведено в разделе 2.2 «Функции обратного вызова» Руководства пользователя Интерпретатора языка Lua. Скрипт Lua может содержать несколько функций с предопределенными названиями, являющимися обработчиками событий, таких как новая сделка, новая обезличенная сделка, изменение котировок и т.д
Как и в предыдущей структуре скрипта Lua, после его запуска первоначально выполняются сценарии, описанные в , если они присутствуют. Далее происходит вызов обработчика с именем OnInit(), если он присутствует. В обработчике OnInit() пользователь имеет возможность инициализировать все необходимые переменные и библиотеки перед запуском отдельного потока. После завершения функции OnInit() происходит создание отдельного потока РМ QUIK, и в этом потоке начинает выполнение функция main(), которая обязательно должна присутствовать в скрипте. Скрипт считается работающим, пока работает функция main(). При завершении работы
Владимир написал: А на рынке не просто нет ликвидности - самого рынка нет. А вот у капиталистов - есть.
Мне последнее время NG нравится торгуется хорошо в американскую сессию, или BRENT, гоняю RTS Маленький. Да полно Все конечно зависит от депозита если млн.$ то тесно.
Владимир написал: ТОС - это Таблица Обезличенных Сделок. То самое говно, в котором Вы ковыряетесь.
Ну тут все просто отследить крупные сделки для определения куда "Умные деньги" толкают рынок.
Я не знаю читали что-то на эту тему. Это классика жанра торговали так еще в начале 20 века. и ныне стратегия рабочая для Крупных денег с некоторыми изменнениями.
Идея следующая "Умные деньги" двигают рынок в нужно им направлении. В накапливая огромный объем удерживая рынок в границах скидывают лишних и толкают вверх так как не осталось предложения. Затем распределяют.
ТОС здесь и используют для разных целей основная когда Маркет Мейкер вступает в дело обменивая 100 млн$ не двину рынок не пункт, не попадая в стакан. Собственно это основная цель Рынка сделать Возможно обмена крупной сделки. Зачем нам буте уверены отследили такую сделку вставайте за ней.
Владимир, Я не понял что такое ТОС. А свечи чем не угодили по своей природе отфильтрованные сделки. Есть H есть L есть C на акциях есть Объем (Кол. сделок). По сути квантованные данные за разный промежуток времени с указание момента фиксации. Ну просто сказка.
Я Себя практикую 4 таймфрема 1м, 15М, 60М, конечно D.
При определении целей заглядываю на W но это уже руками.
На акциях нынче Все руками В длинную не включаю Месячный. Все свалилось купил и держи. Зайти два раза в день подкорректировать не сложно, В режиме Эксперт скрипт работает. На рынке нет ликвидности.
Это стала понятно. Вы об этом постоянно говорите. Мой не так крут. Работает всего в 3 режимах; Тестер, Expert, AVTO; выставляет сминает заявки Buy, Sell, TP, SL , trail Stop, Stop от % Деро. отслеживает Поз. расчет ММ ведет аналитику 5-7 индикаторов и многое чего.
Это собственно у всех так, только реализация разная.
Есть смысл обсуждать у кого какие приемы!
2)
Цитата
Владимир написал: Да и Вам таблица всех сделок нафиг не нужна. А если бы и была нужна, код для работы с нею наверняка копеечный.
Мне нужна. Если Вам интересно расскажу не секрет да на форуме круче меня понаписано. Насчет копейки у меня вызывает затруднение. Сами посмотрите на отзывы 0. Зато ломаного гроша нестоит OnInit широкими массами.
3)
Цитата
Владимир написал: Это УЖЕ СОВЕРШЁННЫЕ сделки, это ПРОЙДЕННЫЙ этап, дела давно минувших дней. За каким хреном кому-то нужен этот мусор?
Ну конечно! На этом строится тех. анализ Выделить статистически значимое событие и сесть ему на хвост. Так не Вы не я Рынок двинуть не можем это бизнес Фонда банка Крупных денег.
И это другой подход, сесть на хвост Оператору (SmartMoney, Специалисты) и тд.
Написано много всего но стоящие вещи помещаются на пальцах одной руки. Сегодня Валютный рынок хороший пример Закончился квартал рынок отдан на откуп Экспортерам попробуйте встать им против шерсти. У меня позиция CNY Рано перевернулся.
Владимир, Согласен что то не то, Код вам и не нужен, пока не надумаете таблицу всех сделок в свой скрипт прикрутить.
Эталон перед глазами
Если серьезно то танцы с бубнами вокруг таблицы всех сделок.
Задача отфильтровать по нужным инструментам, на каждом посчитать баланс ну и выделить Оператора. Чтоб в последствии прикрутить к рабочему.
У Николая там полный спектор пока не сильно не разбирался, позже запущу и посмотрю, больно уж закручен.
Этот скрипт сейчас работает в терминале после первого цикла 50 kB, за сессию накопит на верно надо чистить. Это поставил фильтр на одну бумагу, гоняю RTS не самая ликвидная.
Рабочий скрипт скачет от 4000 до 7000 за сессию накопит. При этом первым моим способ обрабатывает все сделки.
--[[ LOGGING ]]--
local Log = {
logfile = nil,
loglevel = 0,
loglevels = {
[-1] = 'Debug',
[ 0] = 'Trace',
[ 1] = 'Info',
[ 2] = 'Warning',
[ 3] = 'Error',
}
}
function Log:Log(log_text, log_level)
if (log_level >= self.loglevel) then
local msg = string.format("[%s] %s: %s\n", os.date(), self.loglevels[log_level], log_text)
if (log_level > 0) then
message(msg, log_level)
end
self.logfile:write(msg)
self.logfile:flush()
end
end
function Log:debug(t)
self:Log(t, -1)
end
function Log:trace(t)
self:Log(t, 0)
end
function Log:info(t)
self:Log(t, 1)
end
function Log:warning(t)
self:Log(t, 2)
end
function Log:error(t)
self:Log(t, 3)
end
function Log:fatal(t)
self:error(t)
error(t)
end
--return Log
local List = {};
function List.new()
return {first = 0, last = -1}
end
--Теперь мы можем вставлять и удалять элементы с обоих концов за постоянное время:
function List.pushfirst (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end
function List.pushlast (list, value)
local last = list.last + 1;
list.last = last;
list[last] = value;
--Log:trace('List.pushlast: '..'; '..tostring(last)..'; '..tostring(value.sec_code)..'; '.. tostring(value.price)..'; '..tostring(value.qty))
end
function List.popfirst (list)
local first = list.first;
if first > list.last then
--error("list is empty")
return nil
end
local value = list[first]
list[first] = nil -- чтобы разрешить сборку мусора
list.first = first + 1
return value
end
function List.poplast (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- чтобы разрешить сборку мусора
list.last = last - 1
return value
end
--[[Если вы будете использовать эту структуру для обслуживания в порядке поступления,
вызывая только pushlast и popfirst, то и first, и last будут постоянно расти.
Однако, так как мы представляем массивы в Lua при помощи таблиц,
вы можете индексировать их как с 1 до 20, так и с 16 777 216 до 16 777 236.
Поскольку Lua использует для представления чисел двойную точность, ваша программа можем
выполняться на протяжении двухсот лет, делая по миллиону вставок в секунду,
прежде чем возникнет проблема с переполнением.--]]
------------------------
local function get_date(td)-- получаем -- формат QUIK
if td==nil then return '0' end
local d = td and td.year and td.month and td.day and string.format("%.4d%.2d%.2d",td.year,td.month,td.day) or '0';
return d--(d or '0')
end
local function get_time(td)-- получаем -- формат QUIK
if td==nil then return '0' end
local t = td.hour and td.min and td.sec and string.format("%.2d%.2d%.2d",td.hour,td.min,td.sec) or '0';
--local t = string.format("%.2d%.2d",td.hour,td.min)..'00'
return t--(t or '0')
end
----- AT local AT;
local allt={};
function allt:new() -- проинициализируем поля, процедуры и фунции нашего класса
---- Создает экземпляр теперь уже объекта, описывает поля объекта и присваивает полям начальные значения.
local obj={
[0]=0,
['b']=0,
[1] = { ['d']='0',['t']='0', ['o']=0,['q']=0,['p']=0,['b']=0, },
['n']=0,
['sm'] = { ['d']='0',['t']='0',['o']=0,['q']=0,['p']=0,['b']=0,},
['Z']=0,
['Seconds']={ [1]=1 },
['ty']=os.time(),
['SP']={[1]=0},
['SQ']={[1]=0},
['Balance']=0,
['WP']={[1]=0},
};
----далее превращаем таблицу в класс
setmetatable(obj,self)
---- объект получает доступ к методам класса
self.__index = self
---- возвращаем наш объект (экземпляр класса)
return obj
end
function allt:printf()
print = message or print --Log:trace
--print('------------ параметры: ' )
local a,v; for a,v in pairs(self) do
--if type(v)==table then type(v)
print( 'allt['..tostring(a)..'] = '..tostring(v) )
--end
end
end
--local Q={};
function AllTrade()
local at = nil; at = List.popfirst(list);
if not at then return end;
local sec=at.sec_code;
local cl=at.class_code;
--if sec~=symbol then return end
local dir=0;
if bit.test(at.flags, 0) then ---- Если сделка на продажу, вычитает объем из текущего
dir=-1; --local balance=AT.Balance; balance = balance+at.qty*dir; AT.Balance=balance;
else -- Если сделка на покупку, прибавляет объем к текущему
dir=1; --local balance=AT.Balance; balance = balance+at.qty*dir; AT.Balance=balance;
end
local b = AT['b']; b=b+at.qty*dir; AT['b']=b;
--Log:info('at: '..tostring(AT[0])..'; '..tostring(stec)..'; '..tostring(AT['b']) );--
local dt=at.datetime; -- datetime TABLE Дата и время
local stec=AT[0]; stec=stec+1; AT[0]=stec;
AT[stec]={};
AT[stec]['t']=get_time( dt )
AT[stec]['d']=get_date( dt )
AT[stec]['o']=dir;
AT[stec]['q']=dir*at.qty;--fd0(at.qty);
AT[stec]['p']=at.price;--round(at.price,scale);
AT[stec]['b']=b;
--AT[stec]['s']=at.sec_code;
--AT[stec]['c']=at.class_code;
--Log:info('at: '..AT[stec]['d']..'; '..AT[stec]['t']..'; '..tostring(AT[stec]['o'])..'; '..tostring(AT[stec]['b']));
--[[---- smart money
if at.qty>=1000 then
local stec=AT[0]; stec=stec+1; AT[0]=stec;
AT[stec]={};
AT[stec]['d']=AT['d'];
AT[stec]['t']=AT['t'];
AT[stec]['o']=AT['o'];
AT[stec]['q']=AT['q'];
AT[stec]['p']=AT['p'];
Log:trace('at-SM: '.."("..stec..") "..AT[stec]['d']..'; '..AT[stec]['t']..'; '..( sec )..'; '..( cl )..'; '..round( AT[stec]['p'],scale)..'; '..fd0(AT[stec]['q'])..'; '..fd0(AT.Balance).."\n");
end
---]]
--Q[at.price]=at.qty;
--Log:trace( 'at-Q: '..at.price..'; '..Q[at.price] );
-----*
local x=os.time()-AT.ty; --F:write('x=',x.."\n")
if x~=AT.Z then
local i;
for i=1,#AT.Seconds do
AT.SQ[i]=AT.SQ[i]+dir*at.qty;
AT.SP[i]=AT.SP[i]+dir*at.qty*at.price;
AT.WP[i] = 0;
if x%AT.Seconds[i]==0 then
--loadstring("F"..AT.Seconds[i].."("..i..")")();
AT.WP[i] = AT.SQ[i]~=0 and round(AT.SP[i]/AT.SQ[i],scale) or 0;
AT.Z=0;
AT.Balance=fd0( AT.SQ[i] );
AT.WP[i]=round(AT.WP[i],scale);
--Log:trace('at: '..AT.Seconds[i].."("..i..")"..'; '..round(AT.WP[i],scale)..' '..fd0(AT.Balance).."\n");
--AT.SQ[i]=0;--AT.SP[i]=0;
end;
end;
end;
AT.Z=x;
--Log:trace('AT.Z= '..AT.Z..' '..AT.WP[i]..' '..Balance.."\n")
--collectgarbage()
--List.pushfirst(list, at)
--List.poplast(list)
end
local is_run;
function OnStop(flag)--вызывается при остановке скрипта из диалога управления
-- 2.2.24 Функция вызывается терминалом QUIK при остановке скрипта из диалога управления.
is_run = false
return 1000
end
function OnClose()--Функция вызывается перед закрытием терминала QUIK и при выгрузке файла qlua.dll.
is_run = false
end
--function OnInit() -- вызывается терминалом QUIK перед вызовом функции main (2.2.25 OnInit)
--end
local class,symbol;
function main()-- Функция, реализет основной поток выполнения в скрипте.(2.2.26 main)
local myLog='AllTrade1'
Log.logfile = io.open(myLog ..'.log', 'w')
Log:trace(myLog)
Log:trace('Создал Лог ');
is_run = true;
--local list=List.new();
-- message('0 '..'first='..tostring(list.first)..'; '..'last='..tostring(list.last) )
--local AT=allt:new();
class= "SPBFUT";
symbol='RMU3'--NGN3';
Log:trace( "----------------InitParameter: ".. tostring(class)..'; ' .. tostring(symbol)..'; ');
-----------all_trades
--Если перечисленные параметры отсутствуют в списке полей элемента, то в качестве параметра передается nil.
function fn(par1,par2)
if par1 == class and par2 == symbol then
return true
else
return false
end
end
local t1 = nil;
--[[---- возвращает таблицу с индексами элементов, удовлетворяющих условию поиска
t1 = SearchItems("all_trades", 0, getNumberOf("all_trades")-1, fn, "class_code, sec_code")
local at=nil;
--local number_of_rows = getNumberOf('all_trades')
local first,last=1,#t1;
for i = 1, #t1 do
at = getItem('all_trades', i)
if at --and at.sec_code==symbol
then
List.pushlast(list, at);
--AllTrade();
List.popfirst(list);
end
end
--]]
local first=0;
local at = nil;
--Log:trace('1 '..'first='..tostring(list.first)..'; '..'last='..tostring(list.last) )
----
local j=1;
while is_run do ----- основной поток выполнения скриптa:
local last=getNumberOf("all_trades");
Log:trace(j..' '..'first='..tostring(first)..'; '..'last='..tostring(last) )
if last>first then
---- возвращает таблицу с индексами элементов, удовлетворяющих условию поиска При возникновении ошибки в функции fn функция SearchItems прерывает свою работу и возвращает «nil».
--t1 = SearchItems("all_trades", first, getNumberOf("all_trades")-1, fn, "class_code, sec_code")
--if t1 then
Log:trace(j..'): '..'first='..tostring(first)..'; last='..tostring(last)--..'; #t1='..tostring(#t1) ..'; t1[1]='..tostring(t1[1])..'; t1[#t1]='..tostring(t1[#t1])
);
at = {};
--for i = t1[1], t1[#t1] do
for i = first, getNumberOf("all_trades")-1 do
if not is_run then break end
at = getItem('all_trades', i)
--if at and at.sec_code==symbol then
--List.pushlast(list, at);
--AllTrade();
--List.popfirst(list);
--end
--if symbol==at.sec_code then
local d = at and at.sec_code and at.sec_code==symbol and get_date(at.datetime) or 0;
local t = at and at.sec_code and at.sec_code==symbol and get_time(at.datetime) or 0;
local sec = at and at.sec_code and at.sec_code==symbol and at.sec_code or 'x';
local p = at and at.sec_code and at.sec_code==symbol and at.price or 0;
local q = at and at.sec_code and at.sec_code==symbol and at.qty or 0;
local dir = (at and at.sec_code and at.sec_code==symbol and bit.test(at.flags,0) and -1 or 1) or 0;
--if bit.test(at.flags, 0) then ---- Если сделка на продажу, вычитает объем из текущего
-- dir=-1;
--else -- Если сделка на покупку, прибавляет объем к текущему
-- dir=1;
--end
Log:trace(j..'): ['..i..']; '..tostring(d)..'; '..tostring(t)..'; '..tostring(sec)..'; '.. tostring(p)..'; '..tostring(q*dir)..'; '..tostring(dir) );
end
---- Последний стал первым
first=getNumberOf("all_trades");--last;--t1[#t1];
end
--end
j=j+1;
--Log:trace(j..' '..'first='..tostring(first)..' list.first='..tostring(list.first)..'; '..'list.last='..tostring(list.last) )
sleep(1000);
end
if Log and Log.logfile~=nil then io.close(Log.logfile) end;
Log:trace('Закрыл Лог '.. tostring(Log.logfile));
end
Ну если кому то будет интересно то вот что получилось.
Следуя рекомендациям Владимира: Зачем жизнь усложнять когда она и так не проста.
1) отключил сортировку от Квик что не идет у меня. 2) применил старый добрый метод if;
Нужно разбираться с индексацией если с последним все понятно, то первого надо проверить. От Роберта пока не отказался. Так дело пойдет и его задвинем Вот что получилось.
Скрытый текст
Скрытый текст
--[[ LOGGING ]]--
Скрытый текст
local Log = {
Скрытый текст
logfile = nil,
Скрытый текст
loglevel = 0,
Скрытый текст
loglevels = {
Скрытый текст
[-1] = 'Debug',
Скрытый текст
[ 0] = 'Trace',
Скрытый текст
[ 1] = 'Info',
Скрытый текст
[ 2] = 'Warning',
Скрытый текст
[ 3] = 'Error',
Скрытый текст
}
Скрытый текст
}
Скрытый текст
function Log:Log(log_text, log_level)
Скрытый текст
if (log_level >= self.loglevel) then
Скрытый текст
local msg = string.format("[%s] %s: %s\n", os.date(), self.loglevels[log_level], log_text)
Скрытый текст
if (log_level > 0) then
Скрытый текст
message(msg, log_level)
Скрытый текст
end
Скрытый текст
self.logfile:write(msg)
Скрытый текст
self.logfile:flush()
Скрытый текст
end
Скрытый текст
end
Скрытый текст
function Log:debug(t)
Скрытый текст
self:Log(t, -1)
Скрытый текст
end
Скрытый текст
function Log:trace(t)
Скрытый текст
self:Log(t, 0)
Скрытый текст
end
Скрытый текст
function Log:info(t)
Скрытый текст
self:Log(t, 1)
Скрытый текст
end
Скрытый текст
function Log:warning(t)
Скрытый текст
self:Log(t, 2)
Скрытый текст
end
Скрытый текст
function Log:error(t)
Скрытый текст
self:Log(t, 3)
Скрытый текст
end
Скрытый текст
function Log:fatal(t)
Скрытый текст
self:error(t)
Скрытый текст
error(t)
Скрытый текст
end
Скрытый текст
--return Log
Скрытый текст
local List = {};
Скрытый текст
function List.new()
Скрытый текст
return {first = 0, last = -1}
Скрытый текст
end
Скрытый текст
--Теперь мы можем вставлять и удалять элементы с обоих концов за постоянное время:
---- возвращает таблицу с индексами элементов, удовлетворяющих условию поиска При возникновении ошибки в функции fn функция SearchItems прерывает свою работу и возвращает «nil».
Nikolay написал: Кстати по по поводу пути. У меня путь определяется так:local path = (_G.getScriptPath and _G.getScriptPath() or (arg[0]:gsub('[^\\/]*$', '', 1):gsub('\\', '/'))) or ''if path == '' then path = './' endИ это не в какой-то функции, а в самом начале скрипта. И как-то не вижу я проблем, чтобы getScriptPath не работал. Так что да, особого смысла в OnInit не вижу. Хотя, когда разбирался с окружением qlua, тоже использовал.
Так Вы его исключили, у вас или или это. Если его нет то идет конструкция or (arg[0]:gsub('[^\\/]*$', '', 1):gsub('\\', '/'))) or '' еще в глобальное поле занесли.
Владимир написал: Вы СВОИ задачи решайте, торговые, а не занимайтесь разной хернёй с потоками,, коллбеками, библиотеками и прочим онанизмом.
Нужно в Quik их записать Золотыми буквами
Только задачу как решать если нет даже основания.
Приведу аллегорию от инженеров: Пришел в магазин купить велосипед, продавец отвечает на полке педали под полкой колесо, еще есть спицы соберите и на здоровье ездите.
Это подход сервиса от программистов, по крайней мере в реализации Квик.
Вы посмотрите, на мой взгляд "Некчемный" вопрос, вызвал дискуссию на две страницы уже спецы подключились.
Сам луа читает все подряд сверху вниз, обернули в функцию "ни чего не вижу ни чего ни кому не скажу", Все что сделали Квиковцы вызов от терминала. Кому на до пользует не на до забыл.
Проблем у них выше крыше, одна вон реализация SearchItems чего стоит пойди догадайся (хоть примеры добавили).
Индекс RTS упал, фьючерс на индекс упал, портфель мой чудесны образом растет. Стою в Long. Чудеса да и только. Видимо наступило время нам поддержать отечественную экономику.
Nikolay написал: И если хотите обсудить конкретное решение, то лучше для этого использовать ветку Discussions GitHub (правда если есть профиль).
Да нет спасибо, мне пока достаточно Вашего примера. Он для меня пока солоноват. Но это только пока .
Я по этой логике накидал свой шаблон, Но все что было в голове стало на беккрень Вот код
Код
local is_run;
function OnStop(flag)--вызывается при остановке скрипта из диалога управления
-- 2.2.24 Функция вызывается терминалом QUIK при остановке скрипта из диалога управления.
is_run = false
return 1000
end
function OnClose()--Функция вызывается перед закрытием терминала QUIK и при выгрузке файла qlua.dll.
is_run = false
end
--function OnInit() -- вызывается терминалом QUIK перед вызовом функции main (2.2.25 OnInit)
--end
--local class,symbol;
function main()-- Функция, реализет основной поток выполнения в скрипте.(2.2.26 main)
is_run = true;
--local list=List.new();
-- message('0 '..'first='..tostring(list.first)..'; '..'last='..tostring(list.last) )
--local AT=allt:new();
class= "SPBFUT";
symbol='RMU3'--NGN3';
-----------all_trades
--Если перечисленные параметры отсутствуют в списке полей элемента, то в качестве параметра передается nil.
function fn(par1,par2)
if par1 == class and par2 == symbol then
return true
else
return false
end
end
local t1 = nil;
--[[---- возвращает таблицу с индексами элементов, удовлетворяющих условию поиска
t1 = SearchItems("all_trades", 0, getNumberOf("all_trades")-1, fn, "class_code, sec_code")
local at=nil;
--local number_of_rows = getNumberOf('all_trades')
local first,last=1,#t1;
for i = 1, #t1 do
at = getItem('all_trades', i)
if at --and at.sec_code==symbol
then
List.pushlast(list, at);
--AllTrade();
List.popfirst(list);
end
end
--]]
local first=0;
local at = nil;
--message('1 '..'first='..tostring(list.first)..'; '..'last='..tostring(list.last) )
----
local j=1;
while is_run do ----- основной поток выполнения скриптa:
local last=getNumberOf("all_trades");
message(j..' '..'first='..tostring(first)..'; '..'last='..tostring(last) )
if last>first then
---- возвращает таблицу с индексами элементов, удовлетворяющих условию поиска При возникновении ошибки в функции fn функция SearchItems прерывает свою работу и возвращает «nil».
t1 = SearchItems("all_trades", first, getNumberOf("all_trades")-1, fn, "class_code, sec_code")
if t1 then
message(j..'): '..'first='..tostring(first)..'; last='..tostring(last)..'; #t1='..tostring(#t1) ..'; t1[1]='..tostring(t1[1])..'; t1[#t1]='..tostring(t1[#t1]))
at = {};
for i = t1[1], t1[#t1] do
if not is_run then break end
at = getItem('all_trades', i)
--if at and at.sec_code==symbol then
--List.pushlast(list, at);
--AllTrade();
--List.popfirst(list);
--end
local d = at and get_date(at.datetime) or 0;
local t = at and get_time(at.datetime) or 0;
local sec = at and at.sec_code or 'x';
local p = at and at.price or 0;
local q = at and at.qty or 0;
local dir = (at and bit.test(at.flags,0) and -1 or 1) or 0;
--if bit.test(at.flags, 0) then ---- Если сделка на продажу, вычитает объем из текущего
-- dir=-1;
--else -- Если сделка на покупку, прибавляет объем к текущему
-- dir=1;
--end
message(j..'): ('..i..'); '..tostring(d)..'; '..tostring(t)..'; '..tostring(sec)..'; '.. tostring(p)..'; '..tostring(q*dir)..'; '..tostring(dir) );
end
first=getNumberOf("all_trades");--last;--t1[#t1];
end
end
j=j+1;
--message(j..' '..'first='..tostring(first)..' list.first='..tostring(list.first)..'; '..'list.last='..tostring(list.last) )
sleep(1000);
end
end
Скрытый текст
Не получилось вставить, Но ошибка в этом исполнении не фильтрует по class_code, sec_code. Что делаю не так?
function rescanBigDeals(sec_code, class_code)
local all_trades_count = getNumberOf("all_trades")
local endIndex = LastReadDeals
local beginIndex = 1
params = {sec_code=sec_code,class_code=class_code}
local t1 = SelectItems("all_trades", 1, endIndex, params)
if t1 ~= nil then
endIndex = #t1
else
endIndex = 0
end
--myLog("rescan begin "..tostring(beginIndex).." - "..tostring(endIndex))
local lastClaster = nil
for i = beginIndex, endIndex, 1 do
local at = getItem ("all_trades", t1[i])
if at ~= nil then
local datetime = os.time(at.datetime)
if curDate.day == at.datetime.day or curDate.wday==1 or curDate.wday==7 then
local value = 0
--if CountQuntOfDeals == 1 then
-- value = 1
--elseif sum_quantity == 0 then
-- value = at.value
--else
value = at.qty
--end
local itsSell = bit.band(at.flags, 0x1) ~= 0
if dirTradeType == 2 and SecData[at.sec_code]["lastDealPrice"]~=0 and at.price~=SecData[at.sec_code]["lastDealPrice"] then
itsSell = at.price<SecData[at.sec_code]["lastDealPrice"]
end
SecData[at.sec_code]["lastDealPrice"] = at.price
--myLog("deal "..at.sec_code.." qnt "..tostring(at.qty).." deal n:"..tostring(at.trade_num).." "..isnil(toYYYYMMDDHHMMSS(at.datetime)))
if lastClaster == nil then
lastClaster = {datetime = at.datetime, mcs = at.datetime.mcs, qty = 0, value = 0, price = 0, isSell = itsSell, sellVol = 0, buyVol = 0} -- time, qty, vol, wvap
end
local needNewClaster = false
if SecData[at.sec_code]["clasterTime"] == 0 and lastClaster["mcs"] ~= at.datetime.mcs then
needNewClaster = true
elseif SecData[at.sec_code]["clasterTime"] ~= 0
and ((at.datetime.sec-lastClaster["datetime"].sec+1) > SecData[at.sec_code]["clasterTime"]
or lastClaster["datetime"].min ~= at.datetime.min or lastClaster["datetime"].hour ~= at.datetime.hour) then
needNewClaster = true
end
--myLog("needNewClaster "..tostring(needNewClaster))
if needNewClaster then
if lastClaster["value"]~=0 then
lastClaster["price"] = lastClaster["price"]/lastClaster["value"]
else
lastClaster["price"] = at.price
end
lastClaster.datetime = at.datetime
local clasterQty = lastClaster["qty"]
if SecData[at.sec_code]["bigDealSize"]~=0 and clasterQty >= SecData[at.sec_code]["bigDealSize"] then
myLog("big deal "..at.sec_code.." qnt "..tostring(clasterQty).." "..isnil(toYYYYMMDDHHMMSS(at.datetime)))
if lastClaster["buyVol"]>lastClaster["sellVol"] then
lastClaster["isSell"] = false
elseif lastClaster["buyVol"]>lastClaster["sellVol"] then
lastClaster["isSell"] = true
end
addBigDealLabel(at.sec_code, lastClaster)
end
lastClaster = {datetime = at.datetime, mcs = at.datetime.mcs, qty = 0, value = 0, price = 0, isSell = itsSell, sellVol = 0, buyVol = 0} -- time, qty, vol, wvap
end
lastClaster["qty"] = lastClaster["qty"] + at.qty
lastClaster["value"] = lastClaster["value"] + at.value
lastClaster["price"] = lastClaster["price"] + at.value*at.price
if itsSell then --sell
lastClaster["sellVol"] = lastClaster["sellVol"] + at.qty
else
lastClaster["buyVol"] = lastClaster["buyVol"] + at.qty
end
--if lastClaster == nil then
-- lastClaster = {datetime = at.datetime, mcs = at.datetime.mcs, qty = 0, value = 0, price = 0, isSell = itsSell} -- time, qty, vol, wvap
--elseif lastClaster["mcs"] ~= at.datetime.mcs then
-- lastClaster["price"] = lastClaster["price"]/lastClaster["value"]
-- local clasterQty = lastClaster["qty"]
-- if SecData[at.sec_code]["bigDealSize"]~=0 and clasterQty >= SecData[at.sec_code]["bigDealSize"] then
-- myLog("big deal "..at.sec_code.." qnt "..tostring(clasterQty).." deal n:"..tostring(at.trade_num).." "..isnil(toYYYYMMDDHHMMSS(at.datetime)))
-- addBigDealLabel(at.sec_code, lastClaster)
-- end
-- lastClaster = {datetime = at.datetime, mcs = at.datetime.mcs, qty = 0, value = 0, price = 0, isSell = itsSell} -- time, qty, vol, wvap
--end
--
--lastClaster["qty"] = lastClaster["qty"] + at.qty
--lastClaster["value"] = lastClaster["value"] + at.value
--lastClaster["price"] = lastClaster["price"] + at.value*at.price
addTradeStat(at, value, itsSell)
end
end
end
if SecData[sec_code]["showHourVWAP"] == 1 then
for k,n in pairs(SecData[sec_code]["h_vwap"]) do
addPriceLabel(sec_code, n, 3, 0)
end
end
if SecData[sec_code]["showDayVWAP"] == 1 then
addPriceLabel(sec_code, SecData[sec_code]["vwap"], 5, -2)
end
if curDate.wday==1 or curDate.wday==7 then
updateSecs()
end
rescanSec = nil
rescanning = false
end
Хочу сразу предупредить мои познания в программировании как это что не обидеть себя! Для меня смысл слова очередь - это очередь в магазине.
Как то очень сложно, про то что я писал видимость и локализацию можно забыть. 1,2,3 Ничего не вижу не знаю!
for i = beginIndex, endIndex, 1 do
local at = getItem ("all_trades", t1[i])
if at ~= nil then
local datetime = os.time(at.datetime)
if curDate.day == at.datetime.day or curDate.wday==1 or curDate.wday==7 then
Но ведь луа позволяет такие конструкции типа:
local flg = at ~= nil or urDate.day == at.datetime.day or curDate.wday==1 or curDate.wday==7 or false;
Владимир написал: Уровень подавляющего большинства посетителей форума близок к абсолютному нулю, а туде же - потоки им подавай. НА ХРЕНА ОНИ ВАМ?! С переменными та же хрень: мой скрипт может обслуживать несколько тысяч тикеров, так что переменных там, возможно, миллион - и нет проблем. Вы СВОИ задачи решайте, торговые, а не занимайтесь разной хернёй с потоками,, коллбеками, библиотеками и прочим онанизмом.
Целиком поддерживаю Вас. Не от хорошей жизни колупаемся в носу и лезем не туда. Так поделитесь опытом.