Допустим получаю значение цены через OnAllTrade. Далее пишу это значение в файл или таблицу - получается 77934.0 Как сделать, что бы была обычная запись 77934, без .0 ? Только недавно перешел с 32б QUIK, в 64b. В старом такого не было.
Пользователь
Сообщений: Регистрация: 08.03.2016
01.10.2020 15:00:01
Вот так можно
Код
function round(num, n) -- Функция округляет до указанного количества знаков
local n = (n or 0)
return tonumber(string.format("%."..n.."f", num))
end
Пользователь
Сообщений: Регистрация: 01.07.2020
01.10.2020 18:23:31
> math.floor(77934.0) 77934
Пользователь
Сообщений: Регистрация: 23.02.2017
02.10.2020 12:25:40
Про string.format понял, работает, но сложно как то получается.
Про math.floor можно для чайника разжевать. Как сделать проще простую операцию: function OnAllTrade(alltrade) price = tonumber(alltrade.price);
Далее я просто записываю в файл: f:write(" "..price.."\n");
Как проще при этом использовать math.floor? Я похоже не понимаю синтаксис и поиск не помогает. (
Пользователь
Сообщений: Регистрация: 01.07.2020
02.10.2020 18:51:15
Цитата
Алексей написал: Про string.format понял, работает, но сложно как то получается.
Про math.floor можно для чайника разжевать. Как сделать проще простую операцию: function OnAllTrade(alltrade) price = tonumber(alltrade.price);
Далее я просто записываю в файл: f:write(" "..price.."\n");
Как проще при этом использовать math.floor? Я похоже не понимаю синтаксис и поиск не помогает. (
Наверное я не так понял (думал просто от нуля нужно избавиться). floor округляет вниз. Естественно, оно обнулит и не только нули.
Пользователь
Сообщений: Регистрация: 30.01.2015
03.10.2020 14:00:57
Цитата
Алексей написал: Про string.format понял, работает, но сложно как то получается.
Про math.floor можно для чайника разжевать. Как сделать проще простую операцию: function OnAllTrade(alltrade) price = tonumber(alltrade.price);
Далее я просто записываю в файл: f:write(" "..price.."\n");
Как проще при этом использовать math.floor? Я похоже не понимаю синтаксис и поиск не помогает. (
попробуйте так: ------------------- function OnAllTrade(alltrade) local price = alltrade.price; f:write(price.."\n");
написал: Про string.format понял, работает, но сложно как то получается.
Про math.floor можно для чайника разжевать. Как сделать проще простую операцию: function OnAllTrade(alltrade) price = tonumber(alltrade.price);
Далее я просто записываю в файл: f:write(" "..price.."\n");
Как проще при этом использовать math.floor? Я похоже не понимаю синтаксис и поиск не помогает. (
попробуйте так: ------------------- function OnAllTrade(alltrade) local price = alltrade.price; f:write(price.."\n");
К сожалению так не работает. Записывается цена и .0 . Оно просто занимает место в таблице или файле, а таких значений много, что очень не удобно.
Пользователь
Сообщений: Регистрация: 21.08.2015
05.10.2020 14:32:22
Порешаем вопрос радикальненько. Функция 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
s_mike@rambler.ru написал: тогда все нули после запятой отрежутся
А у зила шаг цены 5 )
И?
Пасхалочка для Алексея Иванникова:
Пользователь
Сообщений: Регистрация: 21.08.2015
05.10.2020 15:19:53
Цитата
написал: И?
Непорядочек. Ладно, с зилом это вроде шутки, но есть шаги и 0.02, и 0.0025 и еще какие-то, там будет совсем нехорошо.
Пользователь
Сообщений: Регистрация: 30.01.2015
05.10.2020 15:28:12
Шаг цены не представляет никакого интереса в данном случае. Для precision (при необходимости) используется значение scale из getSecurityInfo
Пасхалочка для Алексея Иванникова:
Пользователь
Сообщений: Регистрация: 21.08.2015
05.10.2020 15:39:43
Цитата
написал: Шаг цены не представляет никакого интереса в данном случае.
Звучит как предложение иметь особую функцию форматирования для каждого случая. Так тоже можно, конечно.
Пользователь
Сообщений: Регистрация: 25.09.2020
05.10.2020 15:41:11
А нельзя просто отрезать нули после запятой к чертям собачьим с помощью string.sub?
Пользователь
Сообщений: Регистрация: 21.08.2015
05.10.2020 15:57:52
Цитата
Владимир написал: А нельзя просто отрезать нули после запятой к чертям собачьим с помощью string.sub?
Можно. Тогда следующий вопрос будет "я сделал как написано в этой ветке, теряется дробная часть у <подставить бумагу>".
Пользователь
Сообщений: Регистрация: 25.09.2020
05.10.2020 16:07:27
Anton, С какой радости "теряется"? Вот навскидку алгоритм: 1. Ищем в строке точку (или что там - запятую?), если не нашли, возвращаем исходную строку. 2. В цикле по символам (не знаю, есть ли в Lua функция "забрать символ по индексу") проверяем символы "хвоста" на '0' 3. Если не равно - возвращаем исходную строку, если добежали до string.len - возвращаем огрызок до запятой.
Пользователь
Сообщений: Регистрация: 06.02.2017
05.10.2020 16:22:56
Цитата
А нельзя просто отрезать нули после запятой к чертям собачьим с помощью string.sub?
Это техническая часть, как именно резать, вопрос в том, до скольких нулей резать. Выше само форматирование две строки занимает безо всяких циклов, все остальное там это кэш информации по бумагам, чтобы не дергать на каждом вызове getSecurityInfo. Если заранее известно, как обрезать, две строки и останется. Сделайте лучше, я будто против.
Anton, Как это "сколько нулей резать"? Сколько есть, столько и резать!
Пользователь
Сообщений: Регистрация: 01.07.2020
05.10.2020 18:00:33
a=77934.000 if a==math.floor(a) then a=math.floor(a) end
может так?
Пользователь
Сообщений: Регистрация: 23.02.2017
07.10.2020 10:50:56
Цитата
Игорь написал: a=77934.000 if a==math.floor(a) then a=math.floor(a) end
может так?
Да, это именно то, что надо! Спасибо!!!
Пользователь
Сообщений: Регистрация: 25.09.2020
07.10.2020 13:22:47
Игорь, Обалдеть! Я было подумал, что при a=77934.12000 будет работать неправильно, но она чётко отрезала "хвостовые" нули, не задев дробную часть: 77934.12. Браво!
Пользователь
Сообщений: Регистрация: 25.09.2020
07.10.2020 13:46:39
Игорь, Украл к себе в виде функции - не работает, все нули на месте. Присобачил в начале tonumber - заработало.
это само по себе выведется как 77934.12. floor() тут не причем.
Пользователь
Сообщений: Регистрация: 25.09.2020
07.10.2020 16:12:27
Игорь, А кто тут при чём, если в коде кроме floor ваще ничего нет? :)
Пользователь
Сообщений: Регистрация: 25.09.2020
07.10.2020 22:23:20
В руки бы насрать тому идиоту, который придумал тип данных 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
Пользователь
Сообщений: Регистрация: 31.01.2015
08.10.2020 11:35:12
Владимир, рекомендую прежде чем возмущаться, ознакомиться с учебниками по языку Lua, раз уж приходится на нём программировать в терминале. Также можно почитать информацию о динамически типизируемых языках и зачем так сделали их создатели.
Хотите узнать тип переменной -- есть функция type(переменная), которая возвращает строку с названием типа.
Если tonumber возвращает nil, значит аргумент не может быть представлен в виде числа.
Если вы, как программист, пишете что-то в переменную, то из логики приложения должно быть понятно, что именно туда записывается.
Винить кого-то в своих ошибках -- самый простой способ, конечно.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 11:57:13
_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" вдруг "не может быть представлен в виде числа"?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.10.2020 13:12:02
Цитата
Владимир написал: а не хочу я узнать тип переменной - мне нужно, чтобы она не меняла свой тип,
В Lua, как и большинстве (или всех?) других языков, тип переменной произвольно не меняется. Тип может измениться только при определённых действиях над переменной. И опытный программист всегда знает, какой тип переменной будет при той или иной операции над переменной.
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.10.2020 13:17:33
Цитата
Anton написал: все остальное там это кэш информации
Кешировать степень числа (pwr10) не имеет смысла, т.к. возведение в степень быстрее в два раза, чем вытащить значение из таблицы. А вот операции со строками в Lua на порядок дольше, т.ч. strf будет полезно.
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 13:23:21
Старатель, Ну вот Вы, лично Вы - опытный программист? Можете мне сказать, что этой гадине от меня требуется? У меня вчера даже такой код давал ошибку: SetCell(T,j,7,d0(tostring(a[i][5][1])));
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.10.2020 13:30:26
Владимир, мой скил не так высок, чтобы по приведённому кусочку кода дать ответ
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 13:37:28
Старатель, Блин, ну если непосредственно перед вызовом функции стоит tostring, а первая же команда внутри функции tonumber, то КАКОЙ ЖЕ требуется "скилл", чтобы это объяснить?
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.10.2020 13:43:07
Владимир, у меня нет навыка чтения мыслей. В той кода, что вы привели нет tonumber. Вы можете привести полный код скрипта или продолжить возмущаться, но лучше не на этом форуме, т.к. тут общаются взрослые дяди
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 13:50:45
Старатель, Код самой функции приведён выше, и взрослые дяди обычно читают ВСЮ всеку.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 13:52:24
Всю ВЕТКУ.
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
08.10.2020 14:05:45
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 14:10:23
Старатель, Некорректный пример - Вы передали в функцию не переменную, а значение. Более того: эта функция даёт ошибку НЕ ВСЕГДА, но вот на то, что я написал - давала.
Пользователь
Сообщений: Регистрация: 23.01.2015
08.10.2020 14:31:41
Владимир, То что ситуация повторяется не всегда, совершенно не значит что мы сможем разобраться по отдельным строкам кода. Просьба привести полный пример кода на котором повторяется проблема, иначе разбор может затянуться на века.
Например, Вы знаете что функция tonumber может принимать два параметра, а не один, и если случайно передать туда что попало во второй параметр, то тоже будет nil? мы же не знаем что Вы туда передаете. ну "s" и что? а вдруг эта самая "s" и не "s" вовсе, а функция или еще что. Вот и получается что мы можем только гадать как у Вас там устроено, а Вы будете эти догадки отметать. И так по кругу пока воображения на догадки хватает.
Пользователь
Сообщений: Регистрация: 31.01.2015
08.10.2020 14:38:22
В начало функции поставьте проверку на 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
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 14:51:38
Я хренею, дорогая редакция! Запустил сейчас свой вчерашний скрипт - ошибок НЕТ, но и данных в таблице НЕТ! Клянусь - ни единого байта в коде не менял! В смысле, первая строчка (код тикера) выводится, а остальные - нет, пусто! Поставил 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 и т.д.), так что мне из-за такого "варварства" мог какой-нить "сборщик мусора" как-то гадить, но и сейчас я делаю именно так! Воистину "тихо шифером шурша"...
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 15:00:15
Sergey Gorokhov, Ну я ведь тоже не мальчик в программировании, а код у меня там сложный. АЛГОРИТМИЧЕСКИ сложный.
Нет, я не знаю, что "функция tonumber может принимать два параметра, а не один" (точнее, где-то читал, но тут же забыл - кажется, основание системы счисления от 2 до 36), но я-то передаю ОДИН параметр!
Вот я и говорю: что там за s - одному Богу известно! В смысле, интерпретатору. Я инициализирую переменные из строк файла, а что там в моей таблице получается - без понятия: я-то переменным присваиваю вроде как строки (результат string.sub), но по смыслу там в подавляющем большинстве записаны числа...
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 15:05:46
_sk_, Ну уж нет! Там у меня информация по тикерам сидит, обновляющаяся по прерываниям: цена последней сделки, объёмы сделок и цена покупки и т.д. Что мне толку от лога? Я лучше не буду забывать внутренние структуры инициализировать!
Да, это даже не "на nil намёк", а сам nil собственной персоной!
Пользователь
Сообщений: Регистрация: 25.09.2020
08.10.2020 15:40:58
Ха-ха-ха! А мой последний "шыдевр" ажно General Protection Fault схлопотал! Internal exception happened, панимаш, весь Квик вылетел! А всего-то написал: SetCell(T,j,8,string.format("%1.2f",d0(a[i][4]/a[i][5][1]*100-100)));
А второй раз запустил - вроде, работает...
Всё, всем спасибо, код буду чистить на свежую голову.