Blame |
Last modification |
View Log
| Download
| RSS feed
package br.com.robo.model;
import java.util.ArrayList;
import java.util.List;
/**
* Identifica sequências de 3 gatilhos em tendência de alta,
* conforme regras fornecidas.
*/
public class TriggerFinder
{
/**
* Representa um padrão completo de gatilhos:
* - refIndex: candle de referência (topo da perna de alta)
* - g1Index: índice do Gatilho tipo 1
* - g2Index: índice do Gatilho tipo 2
* - g3Index: índice do Gatilho tipo 3
*/
public static class TriggerPattern
{
private final int refIndex
;
private final int g1Index
;
private final int g2Index
;
private final int g3Index
;
public TriggerPattern
(int refIndex,
int g1Index,
int g2Index,
int g3Index
) {
this.
refIndex = refIndex
;
this.
g1Index = g1Index
;
this.
g2Index = g2Index
;
this.
g3Index = g3Index
;
}
public int getRefIndex
() {
return refIndex
;
}
public int getG1Index
() {
return g1Index
;
}
public int getG2Index
() {
return g2Index
;
}
public int getG3Index
() {
return g3Index
;
}
@
Override
public String toString
() {
return "TriggerPattern{" +
"refIndex=" + refIndex +
", g1Index=" + g1Index +
", g2Index=" + g2Index +
", g3Index=" + g3Index +
'}';
}
}
/**
* Encontra todos os padrões de 3 gatilhos em tendência de alta
* na lista de candles.
*/
public List<TriggerPattern
> findTriggers
(List<Candle
> candles
) {
List<TriggerPattern
> patterns =
new ArrayList<>();
if (candles ==
null || candles.
size() < 5) {
return patterns
;
}
int i =
2; // começa em 2 por causa da checagem de tendência
while (i
< candles.
size() -
3) {
int refIndex = i -
1;
Candle ref = candles.
get(refIndex
);
Candle possibleG1 = candles.
get(i
);
// 1) Tendência de alta antes do refIndex
if (!isUptrend
(candles, refIndex
)) {
i++
;
continue;
}
// 2) Candle de referência deve ser comprador
if (!isBullish
(ref
)) {
i++
;
continue;
}
// 3) Gatilho tipo 1: candle vendedor contrário ao ref
if (!isBearish
(possibleG1
)) {
i++
;
continue;
}
int g1Index = i
;
Candle g1 = possibleG1
;
int g2Index = -
1;
int g3Index = -
1;
// -------------------------------
// 4) Procurar G2
//
// Gatilho tipo 2:
// - Candle comprador dentro da região da referência (ref)
// => high(G2) <= high(ref) e low(G2) >= low(ref)
// OU
// - Candle vendedor rompendo com pavio o topo do G1
// => candle vendedor e high(G2) > high(G1)
//
// IMPORTANTE: aqui AINDA NÃO vale a regra especial
// do rompimento do topo da referência; ela só entra
// na etapa de busca do G3.
// -------------------------------
int j = g1Index +
1;
while (j
< candles.
size() -
1) { // deixa pelo menos 1 candle depois pra ser o G3
Candle c = candles.
get(j
);
boolean isG2 =
false;
// Caso 1: comprador dentro da região da referência
boolean compradorDentroRef =
isBullish
(c
)
&& c.
getHigh() <= ref.
getHigh()
&& c.
getLow() >= ref.
getLow();
// Caso 2: vendedor rompendo com pavio o topo do G1
// (pavio rompe topo do G1)
boolean vendedorRompeTopoG1 =
isBearish
(c
)
&& c.
getHigh() > g1.
getHigh();
if (compradorDentroRef || vendedorRompeTopoG1
) {
isG2 =
true;
}
if (isG2
) {
g2Index = j
;
break;
}
j++
;
}
// Se não achou G2, avança e segue a busca
if (g2Index == -
1) {
i++
;
continue;
}
Candle g2 = candles.
get(g2Index
);
// -------------------------------
// 5) Procurar G3
//
// Gatilho tipo 3:
// - Candle vendedor
// - topo < topo do candle de referência
// - rompe o fundo do G2 (low(G3) < low(G2))
//
// REGRA ESPECIAL:
// "Se houver o rompimento do topo do referência,
// não considerar mais os gatilhos definidos anteriormente."
//
// Ou seja: durante a busca do G3, se QUALQUER candle tiver
// high > high(ref), invalida essa sequência.
// -------------------------------
boolean invalidSequence =
false;
int k = g2Index +
1;
while (k
< candles.
size()) {
Candle c = candles.
get(k
);
// Regra especial: rompimento do topo da referência
if (c.
getHigh() > ref.
getHigh()) {
invalidSequence =
true;
break;
}
if (isBearish
(c
)
&& c.
getHigh() < ref.
getHigh()
&& c.
getLow() < g2.
getLow()) {
g3Index = k
;
break;
}
k++
;
}
if (invalidSequence
) {
// sequência descartada, segue a partir do candle
// que rompeu o topo da referência
i = k +
1;
continue;
}
if (g3Index
!= -
1) {
patterns.
add(new TriggerPattern
(refIndex, g1Index, g2Index, g3Index
));
// pula pra depois do G3 pra evitar muitos padrões sobrepostos
i = g3Index +
1;
} else {
// não houve G3, segue a partir do próximo candle após G1
i = g1Index +
1;
}
}
return patterns
;
}
// ---------- Funções auxiliares ----------
private boolean isBullish
(Candle c
) {
return c.
getClose() > c.
getOpen();
}
private boolean isBearish
(Candle c
) {
return c.
getClose() < c.
getOpen();
}
/**
* Tendência de alta simples:
* close[ref] > close[ref-1] > close[ref-2]
*/
private boolean isUptrend
(List<Candle
> candles,
int refIndex
) {
if (refIndex
< 2) {
return false;
}
double c0 = candles.
get(refIndex
).
getClose();
double c1 = candles.
get(refIndex -
1).
getClose();
double c2 = candles.
get(refIndex -
2).
getClose();
return c0
> c1
&& c1
> c2
;
}
}