When writing the Price Stats indicator for TradingView I was looking for a way to format the volume with comma separators between increments of thousands. For example:

1234567.89 → 1,234,567.89

My first idea was to see if the tostring() function would support a format string to handle the above. Although the documentation does not show a format option for comma delimited output, TradingView tweeted the following format, which did the trick:

str = tostring(volume, "###,###,###,###,###.##")

Two Limitations of the Pine Script Format String

Although the format above is helpful when displaying values for those in the U.S. not all countries use that format. For example, in much of Europe, the comma and period are interchanged:

1.234.567,89

Using the tostring() format shown below would seem a reasonable guess:

volumeStr = tostring(volume, "###.###.###.###.###,##")

Unfortunately this doesn’t return the intended results.

In addition, the format string above only works for values that are of type series.

Function to Add Custom Delimiters

To accommodate additional flexibility when adding delimiters, I wrote a Pine Script function that takes the following parameters:

  • Source string
  • The preferred delimiter character
  • The distance between delimiters
  • The desired separator character between the whole number and fraction (when applicable)

The function signature follows:

f_strAddDelimiters(_src, _delimiter, _distance, _separator)

As an example, if we want to use the European format shown above (1.234.567,89), we set the delimiter to a comma and the separator of the whole number as a period.

volumeStr = f_strAddDelimiters(tostring(volume), ",", 3, ".")

Below are four examples using number formats from around the globe. I am using the close (versus the volume) as it includes both the whole number and a fractional component:

f_strAddDelimiters("12345.67", ",", 3, ".")
f_strAddDelimiters("12345,67", ".", 3, ",")
f_strAddDelimiters("12345.67", "’", 3, ".")
f_strAddDelimiters("12345,67", " ", 3, ",")
f_strAddDelimiters("ABCDEF", "❗", 2, "")
f_strAddDelimiters("456789", "💰", 1, "")

The last two lines may have little to no value as it relates to creating indicators. With that said, I included them to show the function will work with Unicode characters. Here’s the output:

Pine Script Code

The function for adding string delimiters follows, it’s wrapped inside an indictor to test a collection of strings.

// This source code is subject to the terms of the Mozilla Public License, v. 2.0. 
// © PlayTheTrade
//@version=4
study("Function - Add String Delimiters", overlay = true)
//---------------------------------------------------------------
// f_strAddDelimiters(_src, _distance, _delimiter, _separator)
//    string _src       : string to add delimiters
//    string _delimiter : delimiter character
//       int _distance  : distance between delimiters
//    string _separator : char between whole number & fraction
//
// Examples:
//   f_strAddDelimiters("12345.67", ",", 3, ".") => 12,345.67
//   f_strAddDelimiters("12345,67", ".", 3, ",") => 12.345,67
//   f_strAddDelimiters("12345.67", "’", 3, ".") => 12’345.67
//   f_strAddDelimiters("12345,67", " ", 3, ",") => 12 345,67
//---------------------------------------------------------------
f_strAddDelimiters(_src, _delimiter, _distance, _separator) =>
    // _sections[0] => whole number
    // _sections[1] > fractional number
    string[] _sections = str.split(_src, _separator == "" ? " " : _separator)
    // Get whole number digits into an array
    string[] _chars = str.split(array.get(_sections, 0), "")
    int _len = array.size(_chars)
    // f_print(tostring(_chars) , 0, color.red, -5, text.align_center)    
    // f_print(tostring(_len) , 0, color.red, -35, text.align_center)    
    string _result = _src
    if (_len > _distance)
        int _insertCount = floor((_len - 1) / _distance)
        for i = 1 to _insertCount
            _insertPoint = _len - (_distance * i)
            array.insert(_chars, _insertPoint, _delimiter)
        // Append fraction
        string _fraction = array.size(_sections) > 1 ? (_separator + array.get(_sections, 1)) : na
        _result := array.join(_chars, "") + _fraction
    _result
//---------------------------------------------------------------
// Tests
//---------------------------------------------------------------
str = "Number formats:\n" + 
      "12345.67" + "→" + f_strAddDelimiters("12345.67", ",", 3, ".") + "\n" + 
      "12345,67" + "→" + f_strAddDelimiters("12345,67", ".", 3, ",") + "\n" + 
      "12345.67" + "→" + f_strAddDelimiters("12345.67", "’", 3, ".") + "\n" + 
      "12345,67" + "→" + f_strAddDelimiters("12345,67", " ", 3, ",") + "\n\n" + 
      "Other: \n" +
      "ABCDEF → " + f_strAddDelimiters("ABCDEF", "❗", 2, "") + "\n" +       
      "456789 → " + f_strAddDelimiters("456789", "💰", 1, "") + "\n"
if (barstate.islast)
    label.new(bar_index, high, str, size = size.large, style = label.style_label_left, color = color.white)