SignificantFigures
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © SimpleCryptoLife

//@version=5

// @description Takes a floating-point number - one that can, but doesn't have to, include a decimal point - and converts it to a floating-point number with only a certain number of digits left. 
// For example, say you want to display a variable from your script to the user and it comes out to something like 45.366666666666666666666667 or whatever. 
// That looks awful when you, for example, print it in a label. Now you could round it up to the nearest integer easily using a built-in function, or even to a certain number of decimal places 
// using a reasonably simple custom function. But that's a bit arbitrary. Suppose you don't know what asset the script will be used on, and so you can't predict what the price is, 
// and what the value will turn out to be. It could be 0.00045366666666666666666666667 instead. Now if you round it up to 3 decimal places it comes out as 0.000, which is useless.
// My function will round that number to 0.0004536 instead, if told to do it to 4 significant digits. I think this is more friendly.
// Note that this function only truncates the number, it does not do any rounding. So in the example above, it will show 0.0004536 and not 0.0004537. Feel free to extend it to do this if you have the time.

library("SignificantFigures", overlay=true)


// @function sigFig Converts float with arbitrary number of digits to one with a specified number of significant figures.
// @param float _float is the floating-point number to manipulate.
// @param int _figures is the number of significant figures you want.
// @returns Returns a float with the specified number of significant figures.

inputFloat = input.float(defval=12345.678912345, title="Float", tooltip="The number that you want to round.")  // Values used for testing: 123456789  123456789.123  12.3456789  0.123456789  0.0000123456
inputSigFigs = input.int(defval=4, minval=1, maxval=99, title="Significant Figures", tooltip="The number of significant figures that you want the number rounded to.")
inputShowLabel = input.bool(defval=true, title="Show label with numbers")

export sigFig(float _float = 12345.6789, int _figures = 7) =>
    float _numberOfTens = math.log10(math.abs(_float))  // How many tens are in the number (or whatever; I don't really maths)
    int _remainingTens = int(_numberOfTens) - _figures  // How many more than the significant figures is that
    var float _roundedFloat = na
    if _figures > _numberOfTens  // Detect if the decimal place is included in the number of significant digits specified, or not
        _roundedFloat := math.round(_float, _figures-int(math.floor(math.log10(math.abs(_float))))-1)  // Method to round if it is, courtesy of @tepmoc
    else
        _roundedFloat := (math.round(_float / math.pow(10, _remainingTens+1))) * math.pow(10,_remainingTens+1)  // Method to round if it is not, what I made up
    _roundedFloat


// === EXAMPLE USAGE ===

var floatSigFigged = sigFig(inputFloat,inputSigFigs)

string labelText = "Original float: " + str.tostring(inputFloat) + "\nTruncated to " + str.tostring(inputSigFigs) + " significant figures: " + str.tostring(floatSigFigged)

var label labelExample = na
int timeblock = (time - time[1])  // So you can plot labels or lines in the future
if inputShowLabel
    labelExample := label.new(time + (timeblock*3), close[1], labelText, xloc=xloc.bar_time, yloc=yloc.price, style=label.style_label_left, size=size.normal, color=color.gray, textcolor=color.white)
label.delete(labelExample[1])  // Only keep the most recent one

