Sergey Gorokhov, Это не сотрудничество. Я абсолютно точно знаю, что мне пришлось бы МЕСЯЦ рассказывать, что и как делает код. Вы хотели отслеживать a? Ну, рискните - вот её описание:
-- Структура таблицы данных для i-го тикера -- [0] - код тикера -- [1] - справочная информация по тикеру -- [1][0] - код класса тикера -- [1][1] - код валюты тикера (0 - рубли, 1 - доллары, 2 - евро) -- [1][2] - код качества тикера (0 - наихудший 3 - наилучший) -- [1][3] - размер лота (берётся из справочника) -- [1][4] - общее количество сделок (минимум одна, хотя бы виртуальная) -- [1][5] - общее количество закупленных лотов по тикеру -- [1][6] - сумма затрат по тикеру -- [1][7] - средняя цена по всем лотам -- [2] - последнее значение курса (берётся из таблицы текущих торгов) -- [3] - глобальный стоп-лосс -- [4] - стоп-лосс последней ставки -- [5] - сделки текущего тикера в виде пар: размер ставки в лотах - цена покупки -- [6] - свечи текущего тикера по периодам (накапливаемые) -- [7] - свечи текущего тикера (предпоследние) -- [8] - свечи текущего тикера (последние) -- [9] - ID строки в таблице визуализации или -1
Sergey Gorokhov, Сергей, я 40 лет программистом, причём системщик, был даже когда-то в соавторы бортовой операционки включён. Поверьте, я кое-что смыслю в программировании.
Sergey Gorokhov, SP- строка (массив) на три числа, а - сложное, разветвлённое дерево объектов с разнообразной информацией по тикерам, отследить которое не представляется возможным. В частности, этот код выполняется в "большом" прерывании, инициализация - в main, визуализация результатов - малом,обновление - в разных местах.
Sergey Gorokhov, Не логично. Там алгоритмически сложный код, в котором любой запутается, а тут простейшее действие, выделенное мною после "ругательств" интерпретатора на арифметику.
Sergey Gorokhov,Нго у меня-то воспроизводится! И что делать?
i - переменная цикла по тикерам a[i][1][1] - код валюты для данного тикера (в данном случае 2 - евро) SP - сумма средств, вложенных в акции по данной валюте (считается в цикле).
Сделал для себя два вывода из вчерашних-сегодняшних экспериментов:
1. Вставку строк (InsertRow) следует производить всегда в конец таблицы (код -1) - тогда индексы и ключи совпадают, а вот DeleteRow не следует делать вообще, поскольку в этом случае у исполнителя крыша едет, и данные начинают попадать не в те строки. Не нашёл ничего лучшего, чем при необходимости удалить строку обнулять всю таблицу (Clear) и заново перенабить в ней все строки, которые должны отображаться.
2. При описании столбцов (AddColumn) не задавать им никаких QTABLE_INT_TYPE, QTABLE_DOUBLE_TYPE - оставить только QTABLE_STRING_TYPE, и при занесении значения в ячейки (SetCell) заворачивать значения в tostring - тогда, по крайней мере, сортировка по столбцам работает именно как сортировка строк, а не выдаёт результаты, от которых глаза на лоб лезут.
3. Ну и, конечно, как мне тут подсказали, любой чих, любые действия с таблицей должны заворачиваться в проверку флага, что кнопка останова скрипта не нажата.
Aleksandr, У меня такое ощущение, что конвертация не гарантирует, что переменная впоследствии сохранит свой тип, а не поменяет его в любой момент. По виду код чистый - в таблице имеем дело только со строками, и nil здесь возможен лишь если в строке записаны не только цифры и десятичная точка, и строка '0.08' в этом плане безукоризненна. У меня была та же проблема (я о ней здесь писал), но потом она исчезла, и я так и не понял, почему. Подозреваю, что "сейчас эта функция стала возвращать nil" НЕ ВСЕГДА.
Anton, Какая разница? Насколько я помню, копирование СТРОК наиболее быстро производится через регистры сопроцессора (fld-fstp). Тип int тоже, по большому счёту, разновидность типа var - я всегда пользуюсь i16 или i32. Вот со стеком хуже: запихиваешь туда байт, а он, паскуда, пихает, что ему в голову взбредёт. И выравнивание структур, как компилятору в головожопу вдарит... странно, что вся эта софтина до сих пор хоть как-то работает! В любом случае, тип int отличается от типа float только разной интерпретацией входящих туда битов.
Александр, Да я и не собираюсь разбираться в такой теме! Если вместо нормального инта используется float, значит, у разработчиков вместо головы задница. Тем более, что Сергей сказал, что "type number uses two internal representations, or two subtypes".
Для справки: ВЕЗДЕ, где хранятся данные типа double, МОЖНО хранить и int64 (int32, Int 16, int8 и прочее - это просто кусок памяти! И в этой "теме" я разобрался лет эдак 40 назад..
Александр, А зачем там вообще double? Код заявки - ЦЕЛОЕ число! Эксперимент показал, что его разрядности достаточно. Какому дебилу понадобилось объединить int и float в идиотский number, да ещё и на уровне исполнения использовать именно float? Мало других способов поймать приключения на свою задницу?
Хм... GetCell возвращает таблицу, у которой есть как image (строковое представление значения в ячейке), так и value (числовое значение). Может, и в getItem что-то подобное есть - она ведь тоже "возвращает таблицу Lua"... А вообще я уже не раз матерился на "динамический тип данных". Руки бы пообрывал изобретателям"!
Aleksandr, Да её, по-моему, как раз отметившийся тут Игорь, и придумал. А я украл и переделал в функцию. Вот она:
Код
function d0(s) -- обрезка концевых нулей после запятой
s=tonumber(s); -- для числовых переменных
if s==math.floor(s) then s=math.floor(s) end
return s; -- возвращаем огрызок
end; -- конец функции d0()
Aleksandr, Ошибка, очевидно, в формате представления данных с плавающей точкой. Чуть-чуть поигрался - получилось так: Код: i=1892945602368303872; j=1892945602368303872.0000; s=tostring(i); message(s.."\n"..i.."\n"..j); Результат: 1892945602368303872 1892945602368303872 1.8929456023683e+18
Как ни странно, помогла недавно разбиравшаяся тут d0, обрезающая концевые нули: Код: i=1892945602368303872; j=1892945602368303872.0000; j=d0(j); s=tostring(i); message(s.."\n"..i.."\n"..j); Результат: 1892945602368303872 1892945602368303872 1892945602368303872
Кажется, я начинаю понимать, что происходит при удалении/вставке строк: я-то к ним отношусь, как к ключам, а утилиты работы с таблицами, похоже, принимают их за индексы. Неприятно...
Nikolay, И что этот пример должен демонстрировать? Тупо запустил в Квике - выскочила табличка с одной пустой строкой и столбцами "price" и "val!", чёрно-белая с головы до пят.
Nikolay, Я не только смотрел - я ПРОВЕРЯЛ! RGB возвращает число от 0 до 0xFFFFFF, где младший байт - это R, а старший - это B. Так что в моём примере ячейка должна бы окраситься в красный цвет, а цвет текста должен быть чёрным. А выделенная ячейка мне нафиг не нужна - таблица чисто информационная.
Sergey Gorokhov, Я не понимаю, ЧТО Вы считаете "примером кода". Информация о проблеме изложена ПОЛНОСТьЮ! Как ранее(чуть выше) была ПОЛНОСТЬЮ изложена другая проблема, про потерю управления при передаче данных между потоками, и даже было открытым текстом заявлено, что это "зона ответственности Квика" и даже, что эта проблема была поднята более года назад - что толку-то? Пришлось решать проблему с помощью своих костылей.
Sergey Gorokhov,Господи, да я и привёл пример кода, даже с комментариями!
SetCell (iT,1,2,"SomeValue); -- Значение в столбце 2 строки 1 обновляется SetColor (iT, 1, 2, 255, 0); -- цвет ячейки остаётся прежним
Код на удаление и вставку строк вообще "боевой"! Ну, добавлю я пропущенное:
Код
k=0; -- признак ненужности тикера в таблице
a[i][2]=getParamEx(a[i][1][0],a[i][0],"LAST").param_value;
j=a[i][2]/a[i][1][7]*100-100; -- текущее изменение средней цены
if j<-5 then k=1;end -- провалившиеся тикеры показываем
if a[i][1][5]>0 then -- если есть ставки по тикеру
j=a[i][2]/a[i][5][a[i][1][4]-1]*100-100;
if j>3 or j<-3 then k=1;end -- тикеры с отклонившейся последней ставкой
end; -- конец условия "есть ставки по тикеру"
if k==0 and a[i][9]~=-1 then -- тикер есть, а его быть не должно
...
Хотелось бы обсудить ещё одну проблему - на этот раз "с весёлыми картинками и большими буквами".
Таблица от работы скрипта для юзера оказалась чрезвычайно информативной - настолько, что мне захотелось пользоваться только ею, если я сам хочу торговать, а не [только] доверять делать заявки роботу. Но тут выявились очередные нюансы:
1. Не работает раскраска ячеек: вызов SetCell меняет содержимое ячеек "автоматически", а вот на SetColor она пилюёт: всё остаётся чёрно-белым, а я бы хотел раскрасить таблицу как попугая: цвет - это тоже информация, и весьма наглядная.
2. Попытка динамически обновлять количество строк в таблице закончилась крахом. Я делал так: а) После создания таблицы в main и прописывания в ней столбцов, я набиваю её пустыми строками, соответствующие тем тикерам, которые меня интересуют (на старте это все тикеры, по которым у меня в данный момент что-то куплено). iRow=InsertRow(iT,-1); И вообще не набиваю их мясом (только запоминаю айдишки строк в своей таблице тикеров). Появляется пустая таблица с номерами строк. б) В "малом" прерывании (1.5 секунды) я пробегаюсь по тем тикерам, для которых были созданы строки и набиваю их всякими данными (последняя цена и т.п.) с помощью SetCell - в таблице тут же отображаются эти данные, которые обновляются при следующих прерываниях, если курс изменился или были какие-то сделки. в) а вот в "большом" прерывании (15 секунд) я хочу изменять набор тикеров, показываемых юзеру - убирать те строки, которые ему в данный момент не интересны и добавлять те, которые стали представлять интерес. Делаю я это так: while i<N do -- цикл по тикерам k=0; -- признак нужности тикера в таблице (по умолчанию не нужен) ... -- тут кое-какой расчёт, который может установить k=1 (тикер нужен в таблице). Далее парочка "ифов":
if k==0 and a[i][9]~=-1 then -- тикер есть, а его быть не должно DeleteRow(iT,a[i][9]);a[i][9]=-1;end if k~=0 and a[i][9]==-1 then -- тикера нет, а он нужен a[i][9]=InsertRow(T,-1);end i=i+1; -- переходим к следующему тикеру end; -- конец цикла по тикерам a[i][9] - это, естественно, ID строки, полученный от InsertRow и хранящийся в моей таблице для i-го тикера
Мясом строки тоже не наполняются (как и раньше, это сделает "малое" прерывание"). Запускаю - работает, часть стартовых строк из таблицы пропали, но... не все и не те. Вставка тоже работает непонятно как: в разных строках появляются одни и те же тикеры (с разными значениями данных) - в общем, прорисовываются удалённые строки и не прорисовываются неудалённые. Какой-то закономерности в этом я пока не заметил. Вопрос: кто и когда перерисовывает таблицу в окне Квика, и можно ли заставить её делать это принудительно - в доках я такого почему-то не нашёл.
Да, поэкспериментировал сегодня немного на работающем рынке (убил DestroyTable - появился финальный message). Будем считать, что всё работает. Спасибо всем, особенно Anton,
nikolz, А зачем? Для знакомства с HFT вполне достаточно вики - лично я подобные алгоритмы давлю ещё на уровне подсознания, не допуская их до головного мозга. И у меня нет ни малейших сомнений: "новой парадигме финансовых рынков" самое место на помойке.
Где Вы увидели "агрессивность"? Это называется "идеальный стиль общения".
Максим, Как Вы можете получить значение индикатора, если в таблице текущих торгов только ОДНО значение? Грубо говоря, последний тик (ну и всякая сопутствующая лабуда). А график - это уже набор, причём свечей. Впрочем, не в курсе - графики меня не интересуют, только таблица текущих торгов.
Костя, Ну так забирайте в цикле данные от getItem в свою таблицу, и больше ничего не делайте. Насколько я могу судить по коду, тормозит именно table.insert.
А, ну да - ведь DestroyTable у меня гарантированно вызывается при f=false, так что, видимо, теперь он и вешает всё это дело, а файл успел записаться до того.
Anton, Ах, да, конечно - это ведь только по смыслу обработчик прерываний, а по факту всего лишь поганый CALL.. .
Вот же гнида! Обложил все действия с таблицами "if f then" - ФАЙЛ появился, ТАБЛИЦА обнулилась (я думал, DestroyTable должна бы её вообще уничтожить), а месседж финальный - НЕ появился!
"Он то плакал, то смеялся, то щетинился как ёж — он, гад, над нами издевался. Ну сумасшедший — что возьмёшь?"(С) В конце концов, хрен бы с ним, с месседжем - главное, файл, но Я НЕ ПОНИМАЮ, как она работает, от слова "совсем"!
TGB, Ну, если эта скотина хоть раз мне загубит файл результатов, придётся перенести это дело в OnStop, хотя и очень не хочется.
Старатель, О! На мой взгляд ТОЖе "это уже зона ответственности квика"!
Anton, Ой! Не надо мне ковыряться в кишках квика! Я уж столько лет ковырялся в разных кишках, что...
Ах, сволочь какая! Стало быть... нет, секундочку! У меня же мейн НЕ вызывает SetCell - это происходит в обработчике, то бишь в главном потоке. Ладно, завтра попробую что-то сообразить на свежую голову, спасибо за инфу.
Вот меня больше всего и убивает нестабильность: тут играем, тут не играем, тут мы селёдку заворачивали.(с) А sleep() и small() я уже поменял местами (из других соображений - в мейне таблица только инициализируется, а наполняется данными уже в обработчике - чтобы не было паузы для юзера) - это тоже не помогает. И мне это ОЧЕНЬ не ндравицца! Значит, скрипт у меня проработает целый день, а во время записи результатов начнёт выдрипываться, и все результаты псу под хвост? Неужели в OnStop конец мейна присобачивать придётся? Меня от одной мысли об этом воротит - это уже не код, а урод получается.
TGB, А я знаю, какую версию? Ща посмотрю... на одном Квике 8.8.4.3, на втором - 8.7.1.3. Блин, а отлаживался почти всё время на первой. О, сколько нам открытий чудных!
Довёл код индикации практически до финального варианта - всё прекрасно работало. Запустил через час - опять теряет управление. ВААПЩе НИЧЕГО НЕ ДЕЛАЛ СО СКРИПТОМ!
Приколы на этом не кончились: добавил я после SetCell вывод ещё двух столбцов таблицы: j=a[i][5][a[i][1][4]-1]; SetCell(T,a[i][9],8,tostring(d0(j))); SetCell(T,a[i][9],9,string.format("%1.2f",a[i][2]/j*100-100));
И... управление чудесным образом вернулось! Закомментировал взад - а теперь всё работает! Кошмар какой-то!
TGB, Нер, это мы уже проходили - раньше обработчик вызывался раз в 15 секунд, и там стояло "return 20000", сейчас это уже не требуется - 5 секунд на завершение предостаточно, но если поставить, не помогает: скрипт всё равно завершается принудительно.
Начал я потихоньку оформлять свой первый "боевой" скрипт - "уж совсем была бы наша победа, но тут припёрся очередной Мальчиш-Кибальчиш": после остановки скрипта теряется управление. Локализация места ошибки привела вот к такому коду:
Код
function main()
f=true;-- признак работы скрипта (false - завершение)
c=0; -- малый счётчик прерываний
C=0; -- большой счётчик прерываний
... -- идёт начальная инициализация данных (вместо onInit)
while f do -- бесконечный цикл до остановки скрипта
sleep(1500); -- раз в 1.5 секунды запускаем утилиту опроса
small(); -- текущих данных и вывода их юзеру
end; -- конец бесконечного цикла
... -- идёт запись результатов в файл
message("Скрипт остановлен!");
end;
function small()-- обработчик прерывания по таймеру
local i=0; -- индекс текущего тикера
local j=0; -- значение последней цены
c=c+1; -- счётчик "мелких" прерываний
if c==10 then c=0; big();end; -- прошло 15 секунд, включаем анализ
while i<N do -- цикл по тикерам (опрос текущих курсов)
if a[i][9]~= 0 then -- если тикер присутствует в таблице
j=getParamEx(a[i][1][0],a[i][0],"LAST").param_value;
if j~=a[i][2] then -- если курс изменился
a[i][2]=j; -- запоминаем новое значение курса
SetCell(T,a[i][9],3,tostring(d0(a[i][2])));
end; -- конец условия "курс изменился"
end; -- конец условия "тикер присутствует в таблице"
i=i+1;-- переходим к следующему тикеру
end; -- конец цикла по тикерам
end
function big() -- более серьёзный обработчик
... -- идёт некий анализ данных
end
function d0(s) -- обрезка концевых нулей после запятой
s=tonumber(s); -- для числовых переменных
if s==math.floor(s) then s=math.floor(s) end
return s; -- возвращаем огрызок
end
function OnStop()-- вызов по нажатию кнопки "Остановка скрипта"
f=false; -- команда на прекращение бесконечного цикла
end
Если закомментировать вызов SetCell (а он прекрасно работает, таблица значениями заполняется), то по остановке и файл результатов записывается, и сообщение "Скрипт остановлен!" выскакивает. А "на нет и суда нет" - ни файла, ни месседжа! Насколько я понимаю, какая-то скотина, связанная с SetCell, не возвращает управление в main. Что делать? Ну не писать же в onStop окончание main!
nikolz написал: Вы еще далеки от понимания реальности фондовых рынков.
А зачем мне понимать их реальности? Есть тикеры, есть цена спроса и предложения и это ЕДИНСТВЕННАЯ реальность, которая меня интересует.
Нет, я не помню игровые автоматы в супермаркетах и беспроигрышную лотерею у вокзалов - мне всегда хватало мозгофф понять, что это лохотрон. Так что, бывшие напёрсточники теперь называются "маркетмейкеры"? ВОТ ЭТО ВОТ теперь называется ""монстры фондового рынка"? Я же говорю: КАБЗДЕЦ финансовому рынку с такими "трейдерами"! КАКИМ ОБРАЗОМ эта хрень может "сделать ликвидность и уменьшить спред"? Развести лохов на бабки? Да лохи и так все свои бабки благополучно просрут, без этих долбаных "мейкеров"!
А брокеры - это НЕ ТОЛЬКО "всего лишь посредники между биржей и клиентами" - цитата из Вики: На бирже маркетмейкером может являться, например, брокерская контора, которая по договору с биржей берёт на себя обязательство держать в течение оговорённого времени (скажем, не менее 90 % торгового времени) одновременно выставленные заявки с разницей между ценами покупки и продажи (см. спред) не более оговорённой величины, за это биржа предоставляет маркетмейкеру определённые льготы, например, по оплате комиссионного сбора.
Про HFT роботов: кого и как они там "обгладывают" - меня не интересует: меня они не обглодают. Ну что они могут обглодать за свои сраные доли секунды? Ну, получат они какую-то там "информацию" раньше - и что? Ну, купят что-то на полкопейки дешевле, ну, продадут на три копейки дороже - да и то лишь в том случае, если они по этой информации примут правильные решения. Я если рынок тупо проигнорирует эту инфу? А если они неправильно оценят эту информацию? Где тогда будут эти "пираньи"? Правильно, в зопе!
Да какие они "маркетмейкеры", если работают аж на миллисекундах? Брокер - это маркетмейкер, это я понимаю. А эти... И вообще, как это биржи существовали в докомпьютерные времена?
Nikolay, Но здесь-то форум по Квику! И лично я не хочу искать ничего лучшего, даже если оно и существует.
Господи, алгоритму-то какое дело до этих трепыханий? Моему-то уж точно по барабану! Как и мне - просто, когда заходишь в стакан, а там эта мышиная возня - раздражает. Кстати, то, что я видел - это вообще НЕ торговля: суходроч происходит вблизи цены последней сделки (чуть выше или чуть ниже), а сама цена при этом стоит, как вкопанная!
А что такое "чрезмерная активность"? Кто "меру" устанавливает? У меня, например, активность на порядок выше, чем у моей сестры - для неёё моя активность чрезмерная. А мне - нормально...