Допустим получаю значение цены через OnAllTrade. Далее пишу это значение в файл или таблицу - получается 77934.0 Как сделать, что бы была обычная запись 77934, без .0 ? Только недавно перешел с 32б QUIK, в 64b. В старом такого не было.
Порешаем вопрос радикальненько. Функция FormatPrice форматирует цену согласно справочнику инструментов, с правильным шагом цены и правильным числом знаков после запятой. Если цена указана не кратно шагу, она округляется по правилу "к ближайшему". Для неизвестных квику бумаг цена форматируется с 6 знаками после запятой.
Че делать по шагам: 1) рядом со своим скриптом создаем файл FormatPrice.lua 2) в него копипастим следующий код
Код
local defparams = { ['scale'] = 6, ['step'] = 0.000001 }
local strm = '-'
local stre = ''
local strf =
{
[0] = '%s%u',
[1] = '%s%u.%01u',
[2] = '%s%u.%02u',
[3] = '%s%u.%03u',
[4] = '%s%u.%04u',
[5] = '%s%u.%05u',
[6] = '%s%u.%06u',
[7] = '%s%u.%07u',
[8] = '%s%u.%08u',
[9] = '%s%u.%09u'
}
local pwr10 =
{
[0] = 1,
[1] = 10,
[2] = 100,
[3] = 1000,
[4] = 10000,
[5] = 100000,
[6] = 1000000,
[7] = 10000000,
[8] = 100000000,
[9] = 1000000000,
}
local seccache = {}
local function SecCacheMiss(classcode, seccode)
local t = getSecurityInfo(classcode, seccode)
if not t or not t.scale then
return defparams
end
local tsec = seccache[seccode]
if not tsec then
tsec = {}
seccache[seccode] = tsec
end
local tcls = tsec[classcode]
if not tcls then
tcls = { ['scale'] = t.scale, ['step'] = t.min_price_step }
tsec[classcode] = tcls
end
return tcls
end
local function GetSecParams(classcode, seccode)
local tsec = seccache[seccode]
if not tsec then
return SecCacheMiss(classcode, seccode)
end
local tcls = tsec[classcode]
if not tcls then
return SecCacheMiss(classcode, seccode)
end
return tcls
end
function FormatPrice(classcode, seccode, price)
if nil == price then price = 0 end
local prefix
if price < 0 then
prefix = strm
price = math.abs(price)
else
prefix = stre
end
local sp = GetSecParams(classcode, seccode)
local iprice, fprice = math.modf(math.floor(price / sp.step + 0.5) * sp.step)
return string.format(strf[sp.scale], prefix, iprice, math.floor(fprice * pwr10[sp.scale] + 0.5))
end
function FormatPriceFlushCache()
seccache = {}
end
Anton, С какой радости "теряется"? Вот навскидку алгоритм: 1. Ищем в строке точку (или что там - запятую?), если не нашли, возвращаем исходную строку. 2. В цикле по символам (не знаю, есть ли в Lua функция "забрать символ по индексу") проверяем символы "хвоста" на '0' 3. Если не равно - возвращаем исходную строку, если добежали до string.len - возвращаем огрызок до запятой.
Это техническая часть, как именно резать, вопрос в том, до скольких нулей резать. Выше само форматирование две строки занимает безо всяких циклов, все остальное там это кэш информации по бумагам, чтобы не дергать на каждом вызове getSecurityInfo. Если заранее известно, как обрезать, две строки и останется. Сделайте лучше, я будто против.
Игорь, Обалдеть! Я было подумал, что при a=77934.12000 будет работать неправильно, но она чётко отрезала "хвостовые" нули, не задев дробную часть: 77934.12. Браво!
В руки бы насрать тому идиоту, который придумал тип данных var! Сначала у меня "тихо шифером шурша крыша едет не спеша" от таблицы визуализации, пока не прочитал здесь же, в ветке трёхлетней давности, что "для того, чтобы строки отображались, необходимо, чтобы вызов CreateWindow() производился ДО (!!!) процедуры добавления строк в таблицу", и что эта "особенность" не только не исправлена, но до сих пор даже не документирована! Теперь крыша едет от преобразования типов: я заглатываю исходную информацию из файла (там, естественно, строки) и распихиваю её по своим таблицам (а там уже и строки, и целочисленные поля, и поля с плавающей точкой). Но я ПОНЯТИЯ НЕ ИМЕЮ по каким соображениям она присваивает данные и передаёт аргументы какого-то типа. Если строки - ругается math.floor, если предварительно поставить s=tonumber(s) - ругается на этот оператор (вернее, возвращает nil). Я уже до ручки дошёл: перед вызовом функции обуваю аргумент в tostring, а внутри функции переворачиваю его в tonumber - пофиг: "attempt to concatenate a nil value (local 's')". И уж совсем прикол, что в AddColumn тип данных столбца всё-таки УКАЗЫВАЕТСЯ: там тебе и QTABLE_STRING_TYPE, и QTABLE_INT_TYPE, и QTABLE_DOUBLE_TYPE, панимаш! Кто-нить знает, ЧТО этой скотине от меня надобно?!
Не до конца поняли вашу проблему. Что вы хотите сделать и что конкретно не получается? В таблицу необходимо отправлять тип данных, соответствующий типу данных столбца, в ячейку которого происходит вставка. Лучше всего - приведите пример когда, на котором возникает ошибка.
Я хочу знать, какой тип имеют мои данные или принудительно установить их в тип string - тем более, что, насколько я понимаю, ничего другого в Lua и нет. Я хочу, чтобы интерпретатор Lua выполнял мои команды, а не ругался нехорошими словами. С КАКОГО БОДУНА у него там в tonumber вдруг появляется nil, причём не всегда, а в любой момент, когда ему вздумается. Строки на вход ему подаются правильно - проверял, гарантирую!
Это смотря в какую таблицу! В описании языка "всё есть таблица", в реальности же никаких таблиц нет вообще, а есть дерево объектов вида key-value. Штука полезная, иногда, но и только.
А КАК, простите, я могу "в таблицу отправлять тип данных, соответствующий типу данных столбца, в ячейку которого происходит вставка", если у меня а) некоторых таких типов нет вообще б) я не имею возможности самостоятельно задать тип переменной и даже в) я не знаю, какой тип задал ей интерпретатор, причём г) я вовсе не уверен, что на следующем шаге цикла он не подставит ей какой-нибудь другой тип.
Да вот НЕ МОГУ Я "привести пример когда, на котором возникает ошибка". Ибо она возникает НЕ ВСЕГДА, а когда ей заблагорассудится. Ну вот, хотя бы тот код, который я украл у Игоря (к слову, я совершенно не понимаю, как работает его алгоритм и почему он вообще работает). Первый же оператор этой функции время от времени возвращает nil
function d0(s) -- обрезка концевых нулей после запятой s=tonumber(s) -- для числовых переменных if s==math.floor(s) then s=math.floor(s) end return s -- возвращаем огрызок end
Владимир, рекомендую прежде чем возмущаться, ознакомиться с учебниками по языку Lua, раз уж приходится на нём программировать в терминале. Также можно почитать информацию о динамически типизируемых языках и зачем так сделали их создатели.
Хотите узнать тип переменной -- есть функция type(переменная), которая возвращает строку с названием типа.
Если tonumber возвращает nil, значит аргумент не может быть представлен в виде числа.
Если вы, как программист, пишете что-то в переменную, то из логики приложения должно быть понятно, что именно туда записывается.
Винить кого-то в своих ошибках -- самый простой способ, конечно.
_sk_, Первое же, что я сделал - это именно "ознакомился с учебниками по языку Lua". Правда, очень бегло, ибо программирую я уже не один десяток лет - в том числе, и на "динамически типизируемых языках" и не устаю материться, "зачем так сделали их создатели".
Да не хочу я узнать тип переменной - мне нужно, чтобы она не меняла свой тип, когда интерпретатору моча в голову ударит! Что происходит в момент передачи этой переменной в качестве аргумента или присвоения - один Бог знает!
Я уже писал, что аргумент МОЖЕТ быть представлен в виде числа, и что я это специально ПРОВЕРЯЛ!
КОМУ "из логики приложения должно быть понятно, что именно туда записывается"? Вот фрагмент моего вчерашнего кода:
if a[i][5][0]~=0 then InsertRow(T,j); SetCell(T,j,0,a[i][1]); SetCell(T,j,2,d0(a[i][4])); SetCell(T,j,7,d0(a[i][5][1])); j=j+1 end;
Так вот: "по логике" a[i][1] у меня СТРОКА, i, j, [i][5][0] - ЦЕЛОЕ, a[i][4] и a[i][5][1] - ВЕЩЕСТВЕННЫЕ. Так КАКОГО ЖЕ ХРЕНА a[i][5][1], в котором содержится "16.4375" вдруг "не может быть представлен в виде числа"?
Владимир написал: а не хочу я узнать тип переменной - мне нужно, чтобы она не меняла свой тип,
В Lua, как и большинстве (или всех?) других языков, тип переменной произвольно не меняется. Тип может измениться только при определённых действиях над переменной. И опытный программист всегда знает, какой тип переменной будет при той или иной операции над переменной.
Надо делать так, как надо. А как не надо - делать не надо.
Anton написал: все остальное там это кэш информации
Кешировать степень числа (pwr10) не имеет смысла, т.к. возведение в степень быстрее в два раза, чем вытащить значение из таблицы. А вот операции со строками в Lua на порядок дольше, т.ч. strf будет полезно.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель, Ну вот Вы, лично Вы - опытный программист? Можете мне сказать, что этой гадине от меня требуется? У меня вчера даже такой код давал ошибку: SetCell(T,j,7,d0(tostring(a[i][5][1])));
Старатель, Блин, ну если непосредственно перед вызовом функции стоит tostring, а первая же команда внутри функции tonumber, то КАКОЙ ЖЕ требуется "скилл", чтобы это объяснить?
Владимир, у меня нет навыка чтения мыслей. В той строчке кода, что вы привели нет tonumber. Вы можете привести полный код скрипта или продолжить возмущаться, но лучше не на этом форуме, т.к. тут общаются взрослые дяди
Надо делать так, как надо. А как не надо - делать не надо.
Старатель, Некорректный пример - Вы передали в функцию не переменную, а значение. Более того: эта функция даёт ошибку НЕ ВСЕГДА, но вот на то, что я написал - давала.
Владимир, То что ситуация повторяется не всегда, совершенно не значит что мы сможем разобраться по отдельным строкам кода. Просьба привести полный пример кода на котором повторяется проблема, иначе разбор может затянуться на века.
Например, Вы знаете что функция tonumber может принимать два параметра, а не один, и если случайно передать туда что попало во второй параметр, то тоже будет nil? мы же не знаем что Вы туда передаете. ну "s" и что? а вдруг эта самая "s" и не "s" вовсе, а функция или еще что. Вот и получается что мы можем только гадать как у Вас там устроено, а Вы будете эти догадки отметать. И так по кругу пока воображения на догадки хватает.
В начало функции поставьте проверку на nil и выводите сообщение (через message, например, или в лог, если он у есть). При работе со вложенными массивами/таблицами часто бывает, что забыли внутренние структуры инициализировать.
Цитата
Я уже до ручки дошёл: перед вызовом функции обуваю аргумент в tostring, а внутри функции переворачиваю его в tonumber - пофиг: "attempt to concatenate a nil value (local 's')".
Тут же явно на nil намёк.
Можно ещё всё в xpcall завернуть и печатать стек, чтобы было понятно, откуда вы попали со значением nil. Пример, как это обычно делается в моём коде приведён ниже. При любой ошибке видно, где она произошла.
Код
logger:info("STARTED")
local status, errMessage = xpcall(function()
if isConnected() ~= 1 then
local msg = config.name .. " is not connected on start. Shutdown."
logger:error(msg)
else
initialize()
run()
end
end, function(err)
logger:error(tostring(err))
logger:error(debug.traceback())
end)
if not status and errMessage ~= nil then
logger:error(errMessage)
end
Я хренею, дорогая редакция! Запустил сейчас свой вчерашний скрипт - ошибок НЕТ, но и данных в таблице НЕТ! Клянусь - ни единого байта в коде не менял! В смысле, первая строчка (код тикера) выводится, а остальные - нет, пусто! Поставил tostring не [только] на входе, но и на выходе - заработало! Вот "мудифицированный!" код:
if a[i][5][0]~=0 then InsertRow(T,j); SetCell(T,j,0,a[i][1]); SetCell(T,j,2,tostring(d0(a[i][4]))); SetCell(T,j,7,tostring(d0(tostring(a[i][5][1])))); j=j+1 end;
Я тут было подумал, что таблицу-то я в прерывании затирал (Clear), а потом заново формировал строки (InsertRow и т.д.), так что мне из-за такого "варварства" мог какой-нить "сборщик мусора" как-то гадить, но и сейчас я делаю именно так! Воистину "тихо шифером шурша"...
Sergey Gorokhov, Ну я ведь тоже не мальчик в программировании, а код у меня там сложный. АЛГОРИТМИЧЕСКИ сложный.
Нет, я не знаю, что "функция tonumber может принимать два параметра, а не один" (точнее, где-то читал, но тут же забыл - кажется, основание системы счисления от 2 до 36), но я-то передаю ОДИН параметр!
Вот я и говорю: что там за s - одному Богу известно! В смысле, интерпретатору. Я инициализирую переменные из строк файла, а что там в моей таблице получается - без понятия: я-то переменным присваиваю вроде как строки (результат string.sub), но по смыслу там в подавляющем большинстве записаны числа...
_sk_, Ну уж нет! Там у меня информация по тикерам сидит, обновляющаяся по прерываниям: цена последней сделки, объёмы сделок и цена покупки и т.д. Что мне толку от лога? Я лучше не буду забывать внутренние структуры инициализировать!
Да, это даже не "на nil намёк", а сам nil собственной персоной!
Ха-ха-ха! А мой последний "шыдевр" ажно General Protection Fault схлопотал! Internal exception happened, панимаш, весь Квик вылетел! А всего-то написал: SetCell(T,j,8,string.format("%1.2f",d0(a[i][4]/a[i][5][1]*100-100)));
А второй раз запустил - вроде, работает...
Всё, всем спасибо, код буду чистить на свежую голову.