// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © Halving32 - ( ) = valor actual | [ ] = valor teórico Benford // _ _ _ _ ____ ___ // | | | | | | (_) |___ \__ \ // | |__| | __ _| |_ ___ _ __ __ _ __) | ) | // | __ |/ _` | \ \ / / | '_ \ / _` ||__ < / / // | | | | (_| | |\ V /| | | | | (_| |___) / /_ // |_| |_|\__,_|_| \_/ |_|_| |_|\__, |____/____| // __/ | // |___/ //@version=6 // © Halving32 — Benford's Law Multi-Exchange % Change // Compara la distribución del primer dígito del cambio % (precio o volumen) // con la distribución teórica de Benford — hasta 8 exchanges simultáneas indicator("Benford's Law — Multi Exchange", overlay = false, max_bars_back = 5000, max_labels_count = 500, max_lines_count = 500) // ════════════════════════════════════════════════════════════════════════ // CONFIGURACIÓN GENERAL // ════════════════════════════════════════════════════════════════════════ data_source = input.string('Price', 'Fuente de Datos', options = ['Price', 'Volume'], group = 'General') use_auto_bars = input.bool(true, 'Auto-ajustar Barras por Timeframe', group = 'General') manual_len = input.int(5000, 'Barras Manuales', minval = 100, group = 'General') // ════════════════════════════════════════════════════════════════════════ // EXCHANGES // // ⚠️ IMPORTANTE: TradingView valida TODOS los símbolos al cargar el script // sin importar si el exchange está desactivado (show=false). // Por eso los exchanges 5-8 usan BINANCE:BCHUSDT como placeholder seguro. // Para activar un exchange adicional: // 1) Cambia su símbolo en los inputs (busca primero en TV que exista) // 2) Activa el toggle "Visible" // // Exchanges confirmados para BCH: BINANCE:BCHUSDT · BYBIT:BCHUSDT · // OKX:BCHUSDT · KRAKEN:BCHUSD · BITFINEX:BCHUSD // Para probar: MEXC:BCHUSDT · KUCOIN:BCHUSDT · GATEIO:BCHUSDT // ════════════════════════════════════════════════════════════════════════ // ── Exchanges activos por defecto (símbolo verificado) ───────────────── sym1 = input.symbol('BINANCE:BCHUSDT', 'Símbolo', group = 'Exchange 1 — Binance') c1 = input.color(color.rgb(243,186,47), 'Color', group = 'Exchange 1 — Binance') show1 = input.bool(true, 'Visible', group = 'Exchange 1 — Binance') sym2 = input.symbol('BYBIT:BCHUSDT', 'Símbolo', group = 'Exchange 2 — Bybit') c2 = input.color(color.rgb(255,140,0), 'Color', group = 'Exchange 2 — Bybit') show2 = input.bool(true, 'Visible', group = 'Exchange 2 — Bybit') sym3 = input.symbol('OKX:BCHUSDT', 'Símbolo', group = 'Exchange 3 — OKX') c3 = input.color(color.rgb(0,200,220), 'Color', group = 'Exchange 3 — OKX') show3 = input.bool(true, 'Visible', group = 'Exchange 3 — OKX') sym4 = input.symbol('KRAKEN:BCHUSD', 'Símbolo', group = 'Exchange 4 — Kraken') c4 = input.color(color.rgb(100,70,220), 'Color', group = 'Exchange 4 — Kraken') show4 = input.bool(true, 'Visible', group = 'Exchange 4 — Kraken') // ── Exchanges opcionales — placeholder seguro hasta que el usuario ────── // ── cambie el símbolo y verifique que existe en TradingView ───────────── sym5 = input.symbol('BINANCE:BCHUSDT', 'Símbolo (prueba: BITFINEX:BCHUSD)', group = 'Exchange 5 — Opcional A') c5 = input.color(color.rgb(0,185,75), 'Color', group = 'Exchange 5 — Opcional A') show5 = input.bool(false, 'Visible (activa solo si el símbolo es válido)', group = 'Exchange 5 — Opcional A') sym6 = input.symbol('BINANCE:BCHUSDT', 'Símbolo (prueba: MEXC:BCHUSDT)', group = 'Exchange 6 — Opcional B') c6 = input.color(color.rgb(0,100,255), 'Color', group = 'Exchange 6 — Opcional B') show6 = input.bool(false, 'Visible (activa solo si el símbolo es válido)', group = 'Exchange 6 — Opcional B') sym7 = input.symbol('BINANCE:BCHUSDT', 'Símbolo (prueba: KUCOIN:BCHUSDT)', group = 'Exchange 7 — Opcional C') c7 = input.color(color.rgb(0,150,100), 'Color', group = 'Exchange 7 — Opcional C') show7 = input.bool(false, 'Visible (activa solo si el símbolo es válido)', group = 'Exchange 7 — Opcional C') sym8 = input.symbol('BINANCE:BCHUSDT', 'Símbolo (prueba: GATEIO:BCHUSDT)', group = 'Exchange 8 — Opcional D') c8 = input.color(color.rgb(210,50,140), 'Color', group = 'Exchange 8 — Opcional D') show8 = input.bool(false, 'Visible (activa solo si el símbolo es válido)', group = 'Exchange 8 — Opcional D') // ════════════════════════════════════════════════════════════════════════ // BARRAS MÁXIMAS POR TIMEFRAME // ════════════════════════════════════════════════════════════════════════ get_max_bars() => int r = 5000 if use_auto_bars if timeframe.isseconds r := 1000 else if timeframe.isminutes m = timeframe.multiplier r := m <= 5 ? 5000 : m <= 15 ? 3000 : 2000 else if timeframe.isdaily r := 2000 else if timeframe.isweekly r := 1000 else if timeframe.ismonthly r := 500 else r := manual_len r len = get_max_bars() // ════════════════════════════════════════════════════════════════════════ // DISTRIBUCIÓN TEÓRICA DE BENFORD // ════════════════════════════════════════════════════════════════════════ benford = array.from(0.301, 0.176, 0.125, 0.097, 0.079, 0.067, 0.058, 0.051, 0.046) // ════════════════════════════════════════════════════════════════════════ // FUNCIONES AUXILIARES // ════════════════════════════════════════════════════════════════════════ get_leading_digit(val) => s = str.tostring(math.abs(val)) int found = 0 for k = 0 to str.length(s) - 1 ch = str.substring(s, k, k + 1) if str.contains('123456789', ch) found := int(str.tonumber(ch)) break found safe_pct(curr, prev) => na(curr) or na(prev) or prev == 0.0 ? 0.0 : math.abs((curr - prev) / prev * 100.0) count_digit(dc, pct) => int added = 0 if pct > 0.0 dg = get_leading_digit(pct) if dg >= 1 and dg <= 9 array.set(dc, dg - 1, array.get(dc, dg - 1) + 1) added := 1 added get_ex_name(sym) => p = str.split(sym, ':') array.size(p) >= 2 ? array.get(p, 0) : sym // ════════════════════════════════════════════════════════════════════════ // FETCH DATA — close y volume separados por exchange // Todos los símbolos default son VÁLIDOS → no puede haber "Símbolo incorrecto" // al cargar el script con la configuración por defecto. // ════════════════════════════════════════════════════════════════════════ p1 = request.security(sym1, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p2 = request.security(sym2, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p3 = request.security(sym3, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p4 = request.security(sym4, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p5 = request.security(sym5, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p6 = request.security(sym6, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p7 = request.security(sym7, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) p8 = request.security(sym8, timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off) v1 = request.security(sym1, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v2 = request.security(sym2, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v3 = request.security(sym3, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v4 = request.security(sym4, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v5 = request.security(sym5, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v6 = request.security(sym6, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v7 = request.security(sym7, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) v8 = request.security(sym8, timeframe.period, volume, barmerge.gaps_off, barmerge.lookahead_off) _use_price = data_source == 'Price' d1 = _use_price ? p1 : v1 d2 = _use_price ? p2 : v2 d3 = _use_price ? p3 : v3 d4 = _use_price ? p4 : v4 d5 = _use_price ? p5 : v5 d6 = _use_price ? p6 : v6 d7 = _use_price ? p7 : v7 d8 = _use_price ? p8 : v8 // ════════════════════════════════════════════════════════════════════════ // CONTADORES PERSISTENTES // ════════════════════════════════════════════════════════════════════════ var array dc1 = array.new_int(9, 0) var array dc2 = array.new_int(9, 0) var array dc3 = array.new_int(9, 0) var array dc4 = array.new_int(9, 0) var array dc5 = array.new_int(9, 0) var array dc6 = array.new_int(9, 0) var array dc7 = array.new_int(9, 0) var array dc8 = array.new_int(9, 0) var int t1 = 0 var int t2 = 0 var int t3 = 0 var int t4 = 0 var int t5 = 0 var int t6 = 0 var int t7 = 0 var int t8 = 0 // ════════════════════════════════════════════════════════════════════════ // OBJETOS VISUALES (cleanup en tiempo real) // ════════════════════════════════════════════════════════════════════════ var array v_lines = array.new() var array