// --- VARIÁVEIS GLOBAIS ---

JSONArray velas;

float[] aberturas, máximas, mínimas, fechamentos, volumes;

float preçoAtual, ATH , LOW= 0;

String ech = "1m";

ArrayList clustersLiquidação = new ArrayList();

ArrayList contagensCluster = new ArrayList();

//ArrayList suportes = new ArrayList();

ArrayList suporteQuebrado = new ArrayList();

int aleatório= 0;

ArrayList suportes = new ArrayList();

ArrayList quebrasSuporte = new ArrayList();

String símbolo = "BTCUSDT";

int contagemSímbolo=1;

String[] símbolos = {

"BTCUSDT", "PAXGUSDT","BTCUSDC","TRUMPUSDC","ANIMEUSDC", "CAKEUSDC", "VIRTUALUSDC", "SAHARAUSDC","CUSDC","FUSDC", "PEPEUSDT","ETHUSDT", "BNBUSDT", "SOLUSDT", "XRPUSDT", "DOGEUSDT", "ADAUSDT", "AVAXUSDT", "AUCTIONUSD", "DOTUSDT",

"TRXUSDT", "LTCUSDT", "LINKUSDT", "BCHUSDT", "ATOMUSDT", "XLMUSDT", "HMSTRUSD","UNIUSDT", "ETCUSDT", "FILUSDT", "ICPUSDT",

"HBARUSDT", "APTUSDT", "IMXUSDT", "ARBUSDT", "NEARUSDT", "OPUSDT", "GRTUSDT", "VETUSDT", "EGLDUSDT", "SANDUSDT",

"AXSUSDT", "MANAUSDT", "STXUSDT", "XTZUSDT", "THETAUSDT", "RNDRUSDT", "AAVEUSDT", "KAVAUSDT", "ALGOUSDT", "DYDXUSDT",

"TUSDT", "CROUSDT", "FTMUSDT", "GALAUSDT", "CHZUSDT", "ENJUSDT", "ONEUSDT", "RUNEUSDT", "ZILUSDT", "LRCUSDT",

"FLOWUSDT", "ROSEUSDT", "CRVUSDT", "ENSUSDT", "ZRXUSDT", "BATUSDT", "KSMUSDT", "COMPUSDT", "WAVESUSDT", "1INCHUSDT",

"BALUSDT", "SUSHIUSDT", "XEMUSDT", "YFIUSDT", "BNTUSDT", "SKLUSDT", "OCEANUSDT", "ANKRUSDT", "CELOUSDT", "GLMRUSDT",

"SRMUSDT", "MOVRUSDT", "CTSIUSDT", "REEFUSDT", "CVCUSDT", "BANDUSDT", "LITUSDT", "API3USDT", "ALICEUSDT", "RLCUSDT",

"KNCUSDT", "STORJUSDT", "NKNUSDT", "DENTUSDT", "POWRUSDT", "RENUSDT", "ARPAUSDT", "VTHOUSDT", "TRBUSDT", "IDEXUSDT",

"FORTHUSDT", "MTLUSDT", "PERLUSDT", "SYSUSDT", "TLMUSDT", "UFTUSDT", "XNOUSDT", "XVGUSDT", "ELAUSDT", "BICOUSDT"

};

ArrayList resistances = new ArrayList();

float fundingRates[] ;//= fetchFundingRates(symbol, 1000); // Taxas de financiamento de 1000 derniers

float[] fetchFundingRates(String symbol, int limit) {

float[] taxas = novo float[limite];

String url = "https://fapi.generallink.top/fapi/v1/fundingRate?symbol=" + symbol + "&limit=" + limit;

tentar {

String raw = join(loadStrings(url), "");

JSONArray arr = parseJSONArray(raw);

println(" nome do financiamento: "+ arr.size());

para (int i = 0; i < arr.size(); i++) {

JSONObject obj = arr.getJSONObject(i);

taxas[i] = float(obj.getString("taxaDeFundamento"));

se ( taxas[i] < 0) println( " detecteeeee");

}

} catch(Exception e) {

println("Erro ao buscar taxas de financiamento: " + e);

}

taxas de retorno;

}

// --- PARÂMETROS (como suas entradas Pine) ---

int lookbackVol = 50;

float volMult = 2.5;

float wickRatio = 0.6f;

float minBodyRatio = 0.1f;

float proximityPts = 20f; // tolerância para agrupamento de clusters

int pivotLeft = 5;

int pivotRight = 5;

int interval = 1000; // 1000 ms = 1 segundo

int últimaAtualização = 0;

larguras inteiras;

// --- Cálculo da EMA ---

float[] ema(float[] data, int period) {

float[] ema = new float[data.length];

float alpha = 2.0 / (período + 1.0);

// Inicialização: começamos com o primeiro valor bruto

ema[0] = data[0];

para (int i = 1; i < data.length; i++) {

ema[i] = alpha * data[i] + (1 - alpha) * ema[i-1];

}

retornar ema;

}

// --- CONFIGURAR ---

void setup() {

//tamanho(1200, 800);

tela cheia();

//tamanho(int(larguraExibição*2),int(alturaExibição));

símbolo = símbolos[contagemSímbolo];

buscarDados( símbolo );

larguras = int(largura*8.7);//8.1

taxasDeFinanciamento = buscarTaxasDeFinanciamento(símbolo, 1000); // Últimas 1000 taxas de financiamento

//frameRate(1);

// Altere o símbolo se desejar

}

float startDist;

zoom flutuante = 1,0;

float offsetX = 0;

float offsetY = 0;

void touchStarted() {

se (touches.length == 2) {

distânciaInicial = dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y);

}

}

void touchMoved() {

se (touches.length == 2) {

float newDist = dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y);

float d = newDist / startDist;

zoom *= d;

zoom = constrain(zoom, 0.1, 10); // limita o zoom

distânciaInicial = novaDist;

} senão se (touches.length == 1) {

offsetX += (touches[0].x - pmouseX) / zoom;

offsetY += (touches[0].y - pmouseY) / zoom;

}

}

// Arraste com o mouse (útil para testes no PC)

void mouseDragged() {

offsetX += (mouseX - pmouseX) / zoom;

offsetY += (mouseY - pmouseY) / zoom;

se ( mouseX < largura && mouseX > largura-100 && mouseY > altura-200 && mouseY < altura-100){

++gapMin;

}

se ( mouseX < largura && mouseX > largura-100 && mouseY > altura-100 && mouseY < altura){

--gapMin;

}

}

void mousePressed()

{

//++countSymbol;

//preencher(255);

//rect(largura-200, 100,200,200);

se ( mouseX > largura-200 && mouseY < 300 && mouseY >100 )

++countSymbol;

se ( mouseX > largura-200 && mouseY < 500 && mouseY >300 )

--contarSímbolo;

se (contagemSímbolo<0)

countSymbol = 0;

se (contagemSímbolo>101)

countSymbol = 0;

//texto(símbolos[contagemSímbolo],largura-150,150);

símbolo = símbolos[contagemSímbolo];

}

void mouseReleased()

{

se ( mouseX < largura && mouseX > largura-100 && mouseY > altura-200 && mouseY < altura-100){

++gapMin;

}

se ( mouseX < largura && mouseX > largura-100 && mouseY > altura-100 && mouseY < altura){

--gapMin;

}

}

float rsi(int i, float[] closes, int period) {

se (i < período) retorne 50; // padrão se não houver dados suficientes

ganho de ponto flutuante = 0, perda = 0;

para (int j = 1; j <= período; j++) {

mudança de ponto flutuante = fecha[i - j + 1] - fecha[i - j];

se (variação > 0) ganho += variação;

caso contrário, perda -= mudança;

}

float avgGain = ganho / período;

float avgLoss = perda / período;

Se (perda média == 0) retorne 100; // RSI máximo se não houver perda

float rs = ganho médio / perda média;

retornar 100 - (100 / (1 + rs));

}

int n = 30; // tamanho da janela

float tolerance = 100.5; // margem para dizer "atinge o limite máximo"

void detectarResistência(int i, float[] highs, float[] closes) {

se (i < n) retornar; // ainda não há dados suficientes

// Selecionamos o valor máximo das últimas n velas

float maxRecent = highs[i];

para (int j = 1; j < n; j++) {

se (highs[i - j] > maxRecent) {

maxRecent = highs[i - j];

}

}

Contamos quantas vezes o preço "chegou perto" do máximo.

int toques = 0;

para (int j = 0; j < n; j++) {

se (abs(highs[i - j] - maxRecent) < tolerância) {

toques++;

}

}

// Cálculo do RSI não será exibido

// vender na baixa

float rsiValue = rsi(i, closes, 27);

// Se ocorrer com frequência, mas a temperatura não ultrapassar 100 °C, sinalize

se (touchess > 2 && closes[i] < highs[i] - tolerance && rsiValue > 60) {

float xp = map(i, 0, closes.length - 1, 50, widths - 50);

float y = map(highs[i], min(closes), max(closes), height - 50, 50);

preencher(255, 255, 0, 150);

semAcidente();

rect(xp, y, 30, 15);

//preencher(255);

textAlign(CENTRO);

texto("CURTO ×100", xp, y - 10);

}

}

// --- DESENHAR LOOP ---

void desenhar() {

aleatório = 0;

se (millis() - últimaAtualização >= intervalo) {

//fetchData(symbol); // Atualizamos os dados

/*closes = new float[666]; // redefine o array de closures

supports.clear(); // Limpamos a lista de suportes

supportBreaks.clear(); // limpa a lista de pausas

liquidationClusters.clear(); // limpamos os clusters de liquidação

clusterCounts.clear();

supportBroken.clear();*/

símbolo = símbolos[contagemSímbolo];

buscarDados( símbolo );

últimaAtualização = millis(); // Reiniciamos o contador para zero

}

pushMatrix();

traduzir(largura/2 + deslocamentoX*zoom, altura/2 + deslocamentoY*zoom-400);

//translate(largura/2 + offsetX, altura/2 + offsetY-400);

escala(zoom);

//fetchData("BTCUSDT");

fundo(20);

acidente vascular cerebral (255);

preencher(200);

// limites verticais para dimensionamento

float maxP = max(closes);;

float minP = min(fecha);

/*

para (int i = 0; i < closes.length; i+=10) {

float xpr = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(lows[i], minP, maxP, height - 50, 50);

preencher(255, 25, 255,150);

semAcidente();

rect(xpr-20, y - 40,40,40);

}

para (int i = 5; i < closes.length; i+=10) {

float xpr = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(lows[i], minP, maxP, height - 50, 50);

preencher(25, 255, 255,150);

semAcidente();

rect(xpr-20, y - 40,40,40);

}

*/

// --- PRÓXIMO ---

acidente vascular cerebral(255, 255, 0);

float yATH = map(ATH, minP, maxP, height-50, 50);

linha(50, yATH, largura-50, yATH);

preencher(255, 255, 0);

text("ATH " + ATH, 55, yATH-5);

preencher(255,0,0,55);retângulo(50,yATH,larguras,100);

// --- PRÓXIMO ---

acidente vascular cerebral (25, 255, 255);

yATH = map(LOW, minP, maxP, height-50, 50);

linha(50, yATH, largura-50, yATH);

preencher(255, 255, 0);

texto("BAIXO " + BAIXO, 55, yATH-5);

preencher(0,255,0,55);retângulo(50,yATH,larguras,-100);

// Gráfico de preços (gráfico de linhas de fechamento)

/*

para (int i=1; i

float x1 = map(i-1, 0, closes.length, 50, width-50);

float y1 = map(closes[i-1], minP, maxP, height-50, 50);

float x2 = map(i, 0, closes.length, 50, width-50);

float y2 = map(closes[i], minP, maxP, height-50, 50);

acidente vascular cerebral (180);

peso do golpe (2);

linha(x1, y1, x2, y2);

abre = novo float[n];

altas = novo float[n];

baixos = novo float[n];

fecha = novo float[n];

}*/

peso do golpe (1,3);

preencher(223,12);

iniciarForma();

para (int i = 0; i < closes.length; i++) {

float x = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(closes[i], minP, maxP, height - 50, 50);

vértice(x, y);

// pedidos limitados

}

fimForma();

semAcidente();

float[] ema3 = ema(closes, 666);//18

peso do golpe (3);

semPreenchimento();

para (int i = 1; i < ema3.length; i++) {

float x1 = map(i-1, 0, closes.length-1, 50, widths-50);

float y1 = map(ema3[i-1], minP, maxP, height-50, 50);

float x2 = map(i, 0, closes.length-1, 50, widths-50);

float y2 = map(ema3[i], minP, maxP, height-50, 50);

se (ema3[i] > ema3[i-1]) {

stroke(0, 255, 0); // vertical se estiver para cima

} outro {

stroke(255, 0, 0); // vermelho se descendo

}

linha(x1 , y1, x2 , y2);

}

ema3 = ema(fecha, 18);//18

peso do golpe (3);

semPreenchimento();

para (int i = 1; i < ema3.length; i++) {

float x1 = map(i-1, 0, closes.length-1, 50, widths-50);

float y1 = map(ema3[i-1], minP, maxP, height-50, 50);

float x2 = map(i, 0, closes.length-1, 50, widths-50);

float y2 = map(ema3[i], minP, maxP, height-50, 50);

se (ema3[i] > ema3[i-1]) {

stroke(0, 255, 0); // vertical se estiver para cima

} outro {

stroke(255, 0, 0); // vermelho se descendo

}

linha(x1 , y1, x2 , y2);

}

/*

// largura de cada vela + espaço

vela flutuanteW = 5;

float spacing = 2; // espaço entre as velas

float chartWidth = (candleW + spacing) * closes.length;

para (int i = 0; i < closes.length; i++) {

// X com espaçamento regular

float x = 50 + i * (candleW + spacing);

// mapeamento Y

float yo = map(opens[i], minP, maxP, height - 50, 50);

float yc = map(closes[i], minP, maxP, height - 50, 50);

float yh = map(highs[i], minP, maxP, height - 50, 50);

float yl = map(lows[i], minP, maxP, height - 50, 50);

// --- Pavio ---

acidente vascular cerebral (200);

linha(x, yh, x, yl);

// --- Corpo ---

se (fecha[i] >= abre[i]) {

preencher(0, 200, 0);

traço(0, 200, 0);

rect(x - candleW/2, yc, candleW, yo - yc);

} outro {

preencher(200, 0, 0);

acidente vascular cerebral(200, 0, 0);

rect(x - candleW/2, yo, candleW, yc - yo);

}

}

*/

para (int i = 0; i < closes.length; i++) {

float x = map(i, 0, closes.length - 1, 50, widths-50);

// mapeamento Y

float yo = map(opens[i], minP, maxP, height - 50, 50);

float yc = map(closes[i], minP, maxP, height - 50, 50);

float yh = map(highs[i], minP, maxP, height - 50, 50);

float yl = map(lows[i], minP, maxP, height - 50, 50);

// largura de uma vela

vela flutuanteW = 4,5;

// --- Pavio ---

se (fecha[i] >= abre[i])

// Vela verde

acidente vascular cerebral(0,200,0);

outro

acidente vascular cerebral(200,0,0);

peso do golpe (1,3);

linha(x, yh, x, yl);

semAcidente();

// --- Corpo ---

se (fecha[i] >= abre[i]) {

// Vela verde

preencher(0, 200, 0);

traço(0, 200, 0);

rect(x - candleW/2, yc, candleW, yo - yc);

} outro {

// Vela vermelha

preencher(200, 0, 0);

acidente vascular cerebral(200, 0, 0);

rect(x - candleW/2, yo, candleW, yc - yo);

}

boolean baseHistorique = true;

se ( i > 84)

para (int j = 0; j < 83; j++) {

se (lows[i-j-1] < lows[i]) {

basHistorique = falso;

quebrar;

}

}

senão baseHistorique = falso;

se (downHistory)

{

//se (rsiC>10 && rsiC < 50-Indicator && basHistorique){

//if (rsiC < 45 && basHistorico){

//if (rsiC < 35 && basHistorico){// && dados[i]< prixHaut-20)

// Posicione o ponto

float xp = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(lows[i], minP, maxP, height - 50, 50);

preencher(255, 0, 0,150);

semAcidente();

rect(xp-20, y - 40,40,40);

//elipse(xp-5, y, 10, 10);

preencher(0, 255, 0);

textAlign(CENTRO);

//rect(x-decX, y - 8,10,10);

///bas[i]=1;

se (lows[i] < lows[i-83])

texto("LL", xp, y - 10);

outro

texto("HL", xp, y - 10);

// bas[i]=1;

// em uma compra

//CONFIRM= verdadeiro;

}

booleano HautHistorique = verdadeiro;

se ( i > 84)

para (int j = 0; j < 83; j++) {

se (highs[i-j-1] > highs[i]) {

HautHistorique = falso;

quebrar;

}

}

senão HautHistorique = falso;

se (Alta História)

{

//se (rsiC>10 && rsiC < 50-Indicator && basHistorique){

//if (rsiC < 45 && basHistorico){

//if (rsiC < 35 && basHistorico){// && dados[i]< prixHaut-20)

// Posicione seu ponto

float xp = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(highs[i], minP, maxP, height - 50, 50);

preencher(255, 255, 0,150);

semAcidente();

rect(xp-20, y - 40,40,40);

//elipse(xp-5, y, 10, 10);

preencher(0, 255, 255);

textAlign(CENTRO);

//rect(x-decX, y - 8,10,10);

///bas[i]=1;

se ( highs[i] > highs[i-83])

texto("HH", xp, y - 10);

outro

texto("Hl", xp, y - 10);

// bas[i]=1;

se ( i<990)

{

float xi = map(i+9, 0, closes.length - 1, 50, widths-50);

float yi = map(highs[i+9], minP, maxP, height - 50, 50);

acidente vascular cerebral(255,255,0);

linha(xp, y, xi,yi);

}

// em uma compra

//CONFIRM= verdadeiro;

}

//////////// os pequenos picos

baseHistorique = verdadeiro;

se ( i > 9)

para (int j = 0; j < 8; j++) {

se (lows[i-j-1] < lows[i]) {

basHistorique = falso;

quebrar;

}

}

senão baseHistorique = falso;

se (downHistory)

{

//se (rsiC>10 && rsiC < 50-Indicator && basHistorique){

//if (rsiC < 45 && basHistorico){

//if (rsiC < 35 && basHistorico){// && dados[i]< prixHaut-20)

// Posicione seu ponto

float xp = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(lows[i], minP, maxP, height - 50, 50);

preencher(255, 0, 0,150);

semAcidente();

//rect(xp-20, y - 40,40,40);

elipse(xp-5, y, 10, 10);

preencher(0, 255, 0);

textAlign(CENTRO);

//rect(x-decX, y - 8,10,10);

///bas[i]=1;

// se (lows[i] < lows[i-83])

//texto("LL", xp, y - 10);

//outro

//texto("HL", xp, y - 10);

// bas[i]=1;

// em uma compra

//CONFIRM= verdadeiro;

}

TopHistorical = verdadeiro;

se ( i > 9)

para (int j = 0; j < 8; j++) {

se (highs[i-j-1] > highs[i]) {

HautHistorique = falso;

quebrar;

}

}

senão HautHistorique = falso;

se (Alta História)

{

//se (rsiC>10 && rsiC < 50-Indicator && basHistorique){

//if (rsiC < 45 && basHistorico){

//if (rsiC < 35 && basHistorico){// && dados[i]< prixHaut-20)

// Posicione seu ponto

float xp = map(i, 0, closes.length - 1, 50, widths-50);

float y = map(highs[i], minP, maxP, height - 50, 50);

preencher(255, 255, 0,150);

semAcidente();

//rect(xp-20, y - 40,40,40);

elipse(xp-5, y, 10, 10);

preencher(0, 255, 255);

textAlign(CENTRO);

//rect(x-decX, y - 8,10,10);

///bas[i]=1;

se ( highs[i] > highs[i-7])

texto("HH", xp, y - 10);

outro

texto("Hl", xp, y - 10);

// bas[i]=1;

/*se ( i<990)

{

float xi = map(i+9, 0, closes.length - 1, 50, widths-50);

float yi = map(highs[i+9], minP, maxP, height - 50, 50);

acidente vascular cerebral(255,255,0);

linha(xp, y, xi,yi);

}*/

// em uma compra

//CONFIRM= verdadeiro;

}

// As resistências quando o preço não sobe

detectarResistência(i, máximas, fechamentos);

}

/*

para (int i = 0; i < closes.length; i++) {

float x = map(i, 0, closes.length - 1, 50, width-50);

//float y = map(closes[i], minP, maxP, height - 50, 50);

float yh = map(highs[i], minP, maxP, height - 50, 50);

float yl = map(lows[i], minP, maxP, height - 50, 50);

preencher(0,255,0,123);

rect(x-10, yh,10,yh-yl);

//abre = novo float[n];

//highs = novo float[n];

//lows = novo float[n];

//fecha = novo float[n];

// pedidos limitados

}

acidente vascular cerebral(0,0,255);

acidente vascular cerebral (25, 255, 255);

*/

peso do golpe (2);

// --- Clusters de liquidação ---

acidente vascular cerebral(255, 0, 0);

para (int i=0; i

float lvl = liquidationClusters.get(i);

float y = map(lvl, minP, maxP, height-50, 50);

linha(50, y, larguras-50, y);

preencher(255, 0, 0);

texto("LC x" + clusterCounts.get(i), widths-100, y-5);

}

/*

// --- Suportes e interrupções ---

para (int i=0; i

float nível = supports.get(i);

float y = map(lvl, minP, maxP, height-50, 50);

se (supportBroken.get(i)) {

stroke(25, 50, 255); // break = laranja

} outro {

stroke(0, 200, 255); // suporte = vert

}

linha(50, y, largura-50, y);

}*/

// --- Mapa de Calor dos Clusters ---

//desenharClusters(minP, maxP);

// --- Mapa de Calor dos Clusters ---

desenharClusters(minP, maxP);

// --- Suportes (áreas verdes) ---

desenharSuportes(minP, maxP);

// --- Interrupções (áreas laranja espessas) ---

drawBreaks(minP, maxP);

//detectResistances();

//desenharSinais(minP, maxP);

//drawClusters(minPrice, maxPrice);

desenharRetângulosDeNegociação(fechamentos, máximas, mínimas, minP, maxP);

desenharFVG(minP, maxP);

/*

int frIndex = fundingRates.length - 1; // na parte da última taxa de financiamento

// Percorremos as velas começando pela extremidade

para (int i = closes.length - 1; i >= 0 && frIndex >= 0; i -= 8) {

se (fundingRates[frIndex] < 0) {

float x = map(i, 0, closes.length - 1, 50, widths - 50);

preencher(255, 255, 0, 70); // amarelo

rect(x-5, 0, 10, height); // barra amarela na vela correspondente

}

frIndex--; // avançamos na tabela de financiamento

}

*/

se ( i == "1h")

///// sinal do verme... desculpe, dos shorts... xP

para (int i = 0; i < fundingRates.length; ++i) {

//for (int i = fundingRates.length; i < 1 ; --i) {

//int candleIndex = i * 8; // si ech = 1h

se (fundingRates[i] < 0) {

Só podemos recuperar 1000 francos

// float x = map(i*8 , 0, fundingRates.length-1, 50, widths-50);

float x = map(i*8- 600 , 0, closes.length-1, 50, (widths-50) );

float y = altura/2;

preencher(255, 255, 0, 70); // amarelo

//rect(x-5, y-5, 10, 10); // quadrado pequeno

rect(x-5, 0, 10, altura); // pequeno quadrado

tamanhoDoTexto(33);

preencher(255);

texto( "CURTO ", x-5,150);

}

}

textSize(12);

popMatrix();

String[] labels = {"1s", "1m", "3m", "15m","1day","1h","2h"}; // texto dos intervalos

int wld=0;

para (int i=0;i

{ preencher(i*10,255-i*10,i);

rect(i,0,100,100);

preencher(0,0,0);

texto( rótulos[wld % labels.length], 40+i,50);

++wld;

}

preencher(255,255,255);

texto(me, 20, 130);

se ( mouseX < 100 && mouseY < 100 ){

i = "1s"; buscarDados( símbolo );

}

se ( mouseX < 200 && mouseX > 100 && mouseY < 100 ){

i = "1m"; buscarDados( símbolo );

}

se ( mouseX < 300 && mouseX > 200 && mouseY < 100 ){

i = "3m";fetchData( símbolo );

}

se ( mouseX < 400 && mouseX > 300 && mouseY < 100 ){

i = "15m";

buscarDados( símbolo );

}

se ( mouseX < 500 && mouseX > 400 && mouseY < 100 ){

i = "1d";

buscarDados( símbolo ); ;

}

se ( mouseX < 600 && mouseX > 500 && mouseY < 100 ){

i = "1h";

buscarDados( símbolo ); ;

}

se ( mouseX < 700 && mouseX > 600 && mouseY < 100 ){

ech = "2h";

buscarDados( símbolo ); ;

}

se ( mouseX < 900 && mouseX > 670 && mouseY < 100 ){

i = "30m";

buscarDados(símbolo);

}

//rect(largura-100,altura-200,100,100);

//rect(largura-100,altura-100,100,100);

//rect(largura-200,0,largura,300);

texto(símbolos[contagemSímbolo],largura-150,150);

// textSize(30);

//preencher(t13?0:255,t13?255:0,0);

texto ("PREÇO : " + nf(closes[999],0,2),10,altura-220);

retângulo(largura-100,altura-200,100,100);

retângulo(largura-100,altura-100,100,100);

texto ( gapMin, largura-30, altura-250);

}

// --- BUSCAR DADOS ---

void fetchData(String symbol) {

//closes = new float[666];//[666]; // r������������init tableau de clôtures

supports.clear(); // Limpamos a lista de suportes

supportBreaks.clear(); // limpa a lista de pausas

liquidationClusters.clear(); // limpamos os clusters de liquidação

clusterCounts.clear();

suporteQuebrado.limpar();

String url = "https://api.generallink.top/api/v3/klines?symbol=" + símbolo + "&interval="+ech+"&limit=2500";

tentar {

String raw = join(loadStrings(url), "");

velas = parseJSONArray(bruto);

int n = candles.size();

println("vela = "+ n);

abre = novo float[n];

altas = novo float[n];

baixos = novo float[n];

fecha = novo float[n];

volumes = novo float[n];

para (int i = 0; i < n; i++) {

JSONArray c = candles.getJSONArray(i);

abre[i] = float(c.getString(1));

highs[i] = float(c.getString(2));

lows[i] = float(c.getString(3));

fecha[i] = float(c.getString(4));

volumes[i] = float(c.getString(5));

// Exemplo simplificado de detecção

se (suportes.tamanho() > 0) {

float últimoFechamento = fecha[i];

float prevClose = closes[i-1];

para (int s = supports.size()-1; s >= 0; s--) {

float sprice = supports.get(s);

// Condição de ruptura: passagens de fechamento sob o suporte

se (prevClose >= target && lastClose < target) {

supportBreaks.add(sprice);

}

}

}

}

prixAtual = fecha[n-1];

ATH = máximo(fechamentos);

BAIXO = min(fechamentos);

detectarClusters();

detectarSuportes();

detectarClustersAndFVG(gapMin);

} catch (Exception e) {

println("Erro na API: " + e.getMessage());

}

}

float gapMin = 1;

// Classe para armazenar lacunas com índices de velas

classe Gap {

flutuar baixo, alto;

int startIdx, endIdx; // índices das velas

booleano de alta; // verdadeiro = gap de alta, falso = gap de baixa

Gap(float l, float h, int start, int end, boolean bullishGap) {

baixo = l;

alto = h;

startIdx = início;

endIdx = fim;

otimista = gap de alta;

}

}

// Listas globais para FVG

ArrayList fvgUp = new ArrayList();

ArrayList fvgDn = new ArrayList();

// Detecção de FVG (versão simplificada e testável)

void detectarClustersAndFVG(float gapMin) {

fvgUp.limpar();

fvgDn.limpar();

para (int i=2; i

// --- FVG otimista ---

se (mínimos[i] - máximos[i-2] > intervaloMin) {

fvgUp.add(new Gap(highs[i-2], lows[i], i-2, i, true));

//ln("FVG UP:", highs[i-2], "->", lows[i], "indices", i-2, "->", i);

}

// --- FVG baixista ---

se (mínimos[i-2] - máximos[i] > intervaloMin) {

fvgDn.add(new Gap(highs[i], lows[i-2], i-2, i, false));

//println("FVG DOWN:", highs[i], "->", lows[i-2], "indices", i-2, "->", i);

}

}

}

// Desenho FVG (retângulos horizontais “de vela a vela”)

void drawFVG(float minP, float maxP) {

semAcidente();

// FVG otimista

para (Gap g : fvgUp) {

float x1 = map(g.startIdx, 0, closes.length-1, 50, widths-50);

float x2 = map(g.endIdx, 0, closes.length-1, 50, widths-50);

float y1 = map(g.high, minP, maxP, height-50, 50);

float y2 = map(g.low, minP, maxP, height-50, 50);

preencher(0, 255, 0, 90); // vertical semitransparente

traço(0, 180, 0);

rect(x1, min(y1,y2), max(x2-x1, 2)+100, abs(y2-y1)); // largura mínima 2px

semAcidente();

preencher(255);

textAlign(ESQUERDA, CENTRO);

texto("Long FVG " + nf(g.low,0,2) + "-" + nf(g.high,0,2), x1 + 3, min(y1,y2) + abs(y2-y1)/2);

}

// FVG baixista

para (Gap g : fvgDn) {

float x1 = map(g.startIdx, 0, closes.length-1, 50, widths-50);

float x2 = map(g.endIdx, 0, closes.length-1, 50, widths-50);

float y1 = map(g.high, minP, maxP, height-50, 50);

float y2 = map(g.low, minP, maxP, height-50, 50);

preencher(0, 100, 255, 90); // azul semitransparente

traço(0, 0, 180);

rect(x1, min(y1,y2), max(x2-x1, 2)+100, abs(y2-y1)); // largura mínima 2px

semAcidente();

preencher(255);

textAlign(ESQUERDA, CENTRO);

texto("FVG curto " + nf(g.low,0,2) + "-" + nf(g.high,0,2), x1 + 3, min(y1,y2) + abs(y2-y1)/2);

}

}

/*

Armazenamos as lacunas como pares (mínimo, máximo)

classe Gap {

flutuar baixo, alto;

Lacuna(float l, float h) {

baixo = l;

alto = h;

}

}

ArrayList fvgUp = new ArrayList();

ArrayList fvgDn = new ArrayList();

void detectarClustersAndFVG() {

liquidationClusters.clear();

clusterCounts.clear();

fvgUp.limpar();

fvgDn.limpar();

// média simples do volume

float volMA = 0;

para (int i=0; i

volMA += volumes[i];

}

volMA /= volumes.comprimento;

para (int i=0; i

float corpo = abs(fecha[i]-abre[i]);

vela flutuante = máximas[i]-mínimas[i];

float wickUp = highs[i]-max(opens[i], closes[i]);

float wickDn = min(opens[i], closes[i]) - lows[i];

// --- Liquidação de detecção de cluster ---

se (volumes[i] > volMA*volMult && candle > 0 && body/candle <= minBodyRatio) {

float liquidPrice = Float.NaN;

se (wickUp/candle >= wickRatio) liquidPrice = highs[i];

senão se (wickDn/candle >= wickRatio) liquidPrice = lows[i];

se (!Float.isNaN(liquidPrice)) adicioneCluster(liquidPrice);

}

*/

/*

// --- Detecção de Lacunas de Valor Justo (FVG) ---

se (i >= 2) {

// FVG em tendência de alta (mínima atual > máxima de 2 velas atrás)

se (mínimos[i] > máximos[i-2]) {

//fvgUp.add(new Gap(highs[i-2], lows[i]));

fvgUp.add(new Gap(highs[i-2], lows[i]));

//fvgDn.add(new Gap(highs[i], lows[i-2]));

}

// FVG em tendência de baixa (máxima atual igual à mínima de 2 velas atrás)

se (altos[i] < baixos[i-2]) {

// fvgDn.add(new Gap(highs[i], lows[i-2]));

// fvgUp.add(new Gap(highs[i-2], lows[i]));

fvgDn.add(new Gap(highs[i], lows[i-2]));

}

}

*/

/*

float gapMin = 1000; // tolerância mínima para considerar um FVG

se (i >= 2) {

// FVG otimista

se (mínimos[i] - máximos[i-2] > intervaloMin) {

fvgUp.add(new Gap(highs[i-2], lows[i]));

println("FVG UP:", highs[i-2], "->", lows[i]);

}

// FVG baixista

se (mínimos[i-2] - máximos[i] > intervaloMin) {

fvgDn.add(new Gap(highs[i], lows[i-2]));

println("FVG DOWN:", highs[i], "->", lows[i-2]);

}

}

}

}

void drawFVG(float minP, float maxP) {

semAcidente();

// FVG verde otimista

para (Gap g : fvgUp) {

float y1 = map(g.high, minP, maxP, height-50, 50);

float y2 = map(g.low, minP, maxP, height-50, 50);

acidente vascular cerebral (255);

preencher(0, 255, 0); // vértice transparente

rect(50, y1, widths-100, y2-y1);

preencher(0, 180);

texto("FVG" + nf(g.low,0,2)+"-"+nf(g.high,0,2), larguras-490, y1+12);

}

// FVG azul baixista

para (Gap g : fvgDn) {

float y1 = map(g.high, minP, maxP, height-50, 50);

float y2 = map(g.low, minP, maxP, height-50, 50);

acidente vascular cerebral(255,0,0);

preencher(0, 100, 255); // azul transparente

rect(50, y1, widths-100, y2-y1);

preencher(0, 180);

texto("FVG" + nf(g.low,0,2)+"-"+nf(g.high,0,2), larguras-490, y1+12);

}

}

*/

// --- DETECTAR AGLOMERADOS DE LIQUIDAÇÃO ---

void detectarClusters() {

liquidationClusters.clear();

clusterCounts.clear();

// média simples do volume

float volMA = 0;

para (int i=0; i

volMA += volumes[i];

}

volMA /= volumes.comprimento;

para (int i=0; i

float corpo = abs(fecha[i]-abre[i]);

vela flutuante = máximas[i]-mínimas[i];

float wickUp = highs[i]-max(opens[i], closes[i]);

float wickDn = min(opens[i], closes[i]) - lows[i];

se (volumes[i] > volMA*volMult && candle > 0 && body/candle <= minBodyRatio) {

float liquidPrice = Float.NaN;

se (wickUp/candle >= wickRatio) liquidPrice = highs[i];

senão se (wickDn/candle >= wickRatio) liquidPrice = lows[i];

se (!Float.isNaN(liquidPrice)) adicioneCluster(liquidPrice);

}

}

}

// --- Agrupar clusters próximos ---

void addCluster(float price) {

para (int i=0; i

se (abs(liquidationClusters.get(i) - preço) <= proximityPts) {

// increment

clusterCounts.set(i, clusterCounts.get(i)+1);

retornar;

}

}

liquidationClusters.add(price);

clusterCounts.add(1);

}

// --- DETECTAR SUPORTES + QUEBRAS ---

void detectarSuportes() {

supports.clear();

suporteQuebrado.limpar();

para (int i=pivotLeft; i

booleano isPivot = verdadeiro;

para (int j=1; j<=pivotLeft; j++) se (lows[i] >= lows[i-j]) isPivot=false;

para (int j=1; j<=pivotRight; j++) se (lows[i] >= lows[i+j]) isPivot=false;

se (éPivot) {

float s = lows[i];

suporta.adicionar(s);

// quebrar?

boolean broken = (closes[closes.length-1] < s);

suporteBroken.adicionar(quebrado);

}

}

}

// --- Clusters de liquidação em heatmap ---

void drawClusters(float minP, float maxP) {

semAcidente();

para (int i=0; i

float lvl = liquidationClusters.get(i);

int count = clusterCounts.get(i);

// mapeamento de preços para y

float y = map(lvl, minP, maxP, height-50, 50);

// Intensidade proporcional ao número de ocorrências

int alpha = constrain(40 + count*30, 40, 200);

int rectHeight = 6 + count*2; // ��������paisseur de zone

preencher(255, 0, 0, alfa);

rect(50, y - rectHeight/2, widths-100, rectHeight);

// texto discreto à direita

preencher(255, 200);

texto(nível + " Cluster de liquidação x" + contagem, larguras-490, y-5);

}

}

// --- Suportes (áreas verdes) ---

void drawSuportes(float minP, float maxP) {

semAcidente();

para (int i=0; i

float nível = supports.get(i);

float y = map(lvl, minP, maxP, height-50, 50);

preencher(0, 200, 0, 100); // verde translúcido

rect(50, y-3, widths-100, 6);

preencher(0, 255, 0);

texto(nível+" Suporte", 60, y-5);

}

}

// --- Interrupções de suporte (áreas laranja espessas) ---

void drawBreaks(float minP, float maxP) {

semAcidente();

para (int i=0; i

float lvl = supportBreaks.get(i);

float y = map(lvl, minP, maxP, height-50, 50);

preencher(255, 140, 0, 150); // laranja semi-opaco

rect(50, y-4, widths-100, 8);

preencher(255, 180, 0);

texto("Pausa de suporte", 60, y-6);

}

}

///////#######

// --- Análise de cluster para áreas de compra/venda ---

float clusterZoneMargin = 5f; // margem ao redor do cluster para desenhar a zona

void drawClusterZones(float minP, float maxP) {

para (int i=0; i

float lvl = liquidationClusters.get(i);

int count = clusterCounts.get(i);

// Mapeamento de preço -> e

float y = map(lvl, minP, maxP, height-50, 50);

// Defina a cor de acordo com a tendência (ex.: tons claros = promoção, tons escuros = compra)

float wickUp = highs[i] - max(opens[i], closes[i]);

float wickDn = min(opens[i], closes[i]) - lows[i];

boolean isBuyZone = wickDn > wickUp; // pavio inferior maior

boolean isSellZone = wickUp > wickDn; // pavio mais alto maior

// Ajuste a opacidade e a espessura de acordo com o número de ocorrências

int alpha = constrain(60 + count*30, 60, 200);

int rectHeight = 6 + count*2;

se (isBuyZone) {

preencher(0, 0, 255, alfa);

rect(50, y - clusterZoneMargin, widths-100, clusterZoneMargin*2);

preencher(0, 0, 255);

texto("Compre x"+contagem, larguras-180, y);

}

se (isSellZone) {

preencher(255, 0, 0, alfa);

rect(50, y - clusterZoneMargin, widths-100, clusterZoneMargin*2);

preencher(255, 0, 0);

texto("Venda x"+contagem, larguras-180, y);

}

}

}

////////€€

// --- Configurações ---

float rsiOverbought = 70f;

float rsiOversold = 45f;

int rsiLength = 27; // Comprimento do RSI

int shortTrendLength = 33; // número de velas para calcular a tendência de baixa

float rectMargin = 10f; // espessura do retângulo

// --- Cálculo simples do RSI ---

float calcRSI(float[] closes, int idx, int length) {

Se (idx < comprimento) retorne 50; // valor neutro se não houver dados suficientes

ganho de ponto flutuante = 0, perda = 0;

para (int i=idx-length+1; i<=idx; i++) {

float diff = closes[i] - closes[i-1];

se (diferença > 0) ganho += diferença;

caso contrário, perda -= diferença;

}

se (perda == 0) retorne 100;

retornar 100 - (100 / (1 + ganho/perda));

}

// --- Detecção de tendências de curto prazo ---

boolean isShortDowntrend(float[] closes, int idx, int len) {

se (idx < len) retorne falso;

retornar closes[idx] < closes[idx-len];

}

boolean isShortUptrend(float[] closes, int idx, int len) {

se (idx < len) retorne falso;

retornar closes[idx] > closes[idx-len];

}

void drawTradeRectangles(float[] closes, float[] highs, float[] lows, float minP, float maxP) {

para (int i=comprimentoDaTendênciaCurta; i

float rsi = calcRSI(closes, i, rsiLength);

// Calculando a posição X de acordo com a linha do tempo

float x = map(i, 0, closes.length-1, 50, widths-50);

// --- Sinal de venda ---

se (rsi >= rsiOverbought && isShortDowntrend(closes, i, shortTrendLength)) {

float recentHigh = highs[i];

float y = map(recentHigh, minP, maxP, height-50, 50);

preencher(255, 0, 0, 80);

rect(x-10, y-rectMargin, 20, rectMargin*2); // retângulo centralizado em x

preencher(255, 0, 0);

texto("S", x, y-rectMargin-5); // texto logo acima do retângulo

}

// --- Sinal de compra ---

se (rsi <= rsiSobrevendido && isShortUptrend(closes, i, shortTrendLength)) {

float recentLow = lows[i];

float y = map(recentLow, minP, maxP, height-50, 50);

preencher(0, 0, 255, 80);

rect(x-10, y-rectMargin, 20, rectMargin*2); // retângulo centralizado em x

preencher(0, 0, 255);

texto("B", x, y-rectMargin-5); // texto logo acima do retângulo

}

}

}