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

//@version=5

// @description Extract a clean symbol from a composite ticker. E.g., (BINANCE:BTCUSD+KRAKEN:BTCUSD)/2 as input will return BTCUSD or BINANCE:BTCUSD
library("composite_ticker_cleaner")

// @function Extract the first symbol out of the supplied string (usually ticker.standard(syminfo.tickerid) )
// @param symbol <simple string> input string to search in
// @param keepexchange <simple bool> (optional) Keep exchange in the returned ticker? By default, we only return the symbol without the exchange.
// @returns <simple string> first occurrence of a symbol
export extract_first_symbol(simple string symbol, simple bool keepexchange=false) =>
	// This is a generalization of an implementation of a similar code I made in this indicator: https://www.tradingview.com/script/kPIEzGqV-Liquidations-by-volume-TG-fork/
	regexclean = not keepexchange ? "(?<=:)[a-zA-Z1-9]+" : "[a-zA-Z1-9]+:[a-zA-Z1-9]+"  // clean up the extracted substring, as it can contain other characters, such as math operators and parenthesis, we only keep letters and numbers.
	str.match(symbol, regexclean)  // apply the cleaning regex on the ticker target (the target symbol) and extract the first occurrence

// @function Extract the first symbol out of the supplied string (usually ticker.standard(syminfo.tickerid) )
// @param symbol <series string> input string to search in
// @param keepexchange <series bool> (optional) Keep exchange in the returned ticker? By default, we only return the symbol without the exchange.
// @returns <series string> first occurrence of a symbol
export extract_first_symbol(series string symbol, series bool keepexchange=false) =>
	// This is a generalization of an implementation of a similar code I made in this indicator: https://www.tradingview.com/script/kPIEzGqV-Liquidations-by-volume-TG-fork/
	regexclean = not keepexchange ? "(?<=:)[a-zA-Z1-9]+" : "[a-zA-Z1-9]+:[a-zA-Z1-9]+"  // clean up the extracted substring, as it can contain other characters, such as math operators and parenthesis, we only keep letters and numbers.
	str.match(symbol, regexclean)  // apply the cleaning regex on the ticker target (the target symbol) and extract the first occurrence

// @function Extract the first symbol out of the current tickerid (as provided by ticker.standard(syminfo.tickerid) )
// @param keepexchange <simple bool> (optional) Keep exchange in the returned ticker? By default, we only return the symbol without the exchange.
// @returns <simple string> first occurrence of a symbol in the current tickerid
export extract_first_symbol(simple bool keepexchange=false) =>
	// Overloads the other function to use tickerid automatically
	extract_first_symbol(ticker.standard(syminfo.tickerid), keepexchange)

// @function Extract the part of the string before the specified pattern
// @param symbol <simple string> Input string to search in
// @param pattern <simple string> Pattern to search
// @returns <simple string> Part of the string before the first occurrence of the matched pattern
export extract_before(simple string symbol, simple string pattern) =>
	usd_start_location = str.pos(symbol, pattern)  // autodetect where the pattern is located in the ticker symbol string
	str.substring(symbol, 0, usd_start_location)  // extract substring before the pattern

// @function Extract the part of the string before "USD" (includes USDT, USDC, etc). This is especially useful to extract the symbol out of USD* pair ticker. Eg, out of BTCUSD, we will extract BTC.
// @param symbol <simple string> Input string to search in
// @returns <simple string> Part of the string before the first occurrence of "USD".
export extract_before_usd(simple string symbol) =>
	extract_before(symbol, "USD")

// @function Display some text on the last bar. Helper function to facilitate debugging or user display (eg, to confirm which symbol was detected).
// @param intext <simple string> Text to display.
// @param tooltip <simple string> (optional) Tooltip text to display on mouse hover.
// @returns <simple string> Nothing. Display the supplied text in a table in the top right corner. Note that this will not affect viewport scaling (ie, the viewport will still be scaled according to the content, not the text).
export display_table_text(simple string intext, simple string tooltip="") =>
	// Display a popup with the currently detected symbol, so that the user can verify the indicator does indeed provide pertinent data for the currently selected chart
	// We use `var` to only initialize the table on the first bar.
	// Also we use a table instead of a label because table do not rescale the chart, so that the chart's scale is maximized to the metrics, not the text.
	var table textDisplay = table.new(position.top_right, 1, 1, bgcolor=color.new(color.gray, 85))
	if barstate.islast
		// var label textLabel = na
		//textLabel := label.new(x=bar_index + 2, y=0, text=intext, color=color.new(color.gray, 85), style=label.style_label_left, textcolor=color.gray, textalign=text.align_left, tooltip=tooltip)
		table.cell(textDisplay, 0, 0, text=intext, text_color=color.gray, text_halign=text.align_left, tooltip=tooltip)


// Example, shown only when adding this library to a chart as an indicator: Show current market used as a label on the last bar
display_table_text('First symbol: ' + extract_first_symbol() + '\nFirst symbol with exchange: ' + extract_first_symbol(keepexchange=true) + '\nSymbol without USD: ' + extract_before_usd(extract_first_symbol()))
