English Русский Español
preview
Analisamos o código binário dos preços no mercado (Parte I): Um novo olhar sobre a análise técnica

Analisamos o código binário dos preços no mercado (Parte I): Um novo olhar sobre a análise técnica

MetaTrader 5Indicadores |
157 1
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Introdução

Lembra como, no filme "Matrix", Neo via o mundo como um código binário verde? E se olhássemos os gráficos de mercado exatamente assim? No meu dia a dia de trading, frequentemente me pergunto se conseguimos "ouvir" o que o mercado está tentando nos dizer ao imaginarmos seus movimentos como uma espécie de código ou linguagem.

A ideia surgiu de forma inesperada enquanto eu analisava o gráfico do Bitcoin. Ao observar as bruscas altas e quedas de preço, percebi que certas combinações de movimentos se repetiam, como se fossem letras em uma palavra. Isso me levou a pensar: e se eu codificasse esses movimentos em formato binário e tentasse "ler" a mensagem resultante?

Parece loucura? Talvez. Mas pense bem: a análise técnica não se baseia justamente na busca por padrões? As velas japonesas não são uma forma de codificação do movimento do preço? No fim das contas, o próprio mercado é um imenso fluxo de informações codificadas digitalmente.

Neste artigo, quero compartilhar meu experimento de transformar os movimentos de preço em sequências binárias com sentido. Vamos ver como podemos converter diferentes aspectos do comportamento do mercado — desde movimentos simples até padrões complexos — para o formato binário, e tentar encontrar regularidades nesse código que nos ajudem a entender melhor a linguagem do mercado.

Sim, é uma abordagem fora do convencional. Mas não é essa a essência do trading: buscar novas maneiras de enxergar o que os outros não veem?

Vamos juntos descer pela toca do coelho e ver até onde ela nos leva...


Conceito de representar movimentos de preço em forma de código binário

A base da minha abordagem é uma ideia simples, porém instigante: qualquer movimento de preço pode ser representado como uma sequência de zeros e uns. Pense bem: quando olhamos para um gráfico, o que vemos? Subida e descida, movimentos fortes e fracos, volumes acima ou abaixo da média. Na verdade, já estamos inconscientemente convertendo essas informações para um formato binário dentro da nossa mente!

Vamos pegar um exemplo simples. Suponha que vejamos três velas seguidas: uma de alta, outra de baixa e outra de alta novamente. Na forma mais primitiva, isso pode ser codificado como "101". Mas e se adicionarmos mais parâmetros? Por exemplo, considerar a força do movimento, o volume negociado ou a posição em relação à média móvel?

Em meus experimentos, percebi que até mesmo uma codificação básica baseada no princípio "alta-queda" pode gerar resultados interessantes. No entanto, a verdadeira mágica começa quando passamos a considerar múltiplos timeframes. Imagine: a mesma sequência "101" em um gráfico de 1 hora pode se apresentar de forma completamente diferente em um gráfico diário ou semanal. Isso cria uma espécie de matriz de dados, onde cada movimento de preço é descrito por uma sequência binária única.

Os resultados se tornam especialmente interessantes ao analisar criptomoedas. A volatilidade do Bitcoin gera padrões nítidos e facilmente distinguíveis na representação binária. Às vezes, parece que essas sequências lembram o código Morse, como uma dança rítmica de pontos e traços; só que, neste caso, o que temos é a alta e a queda dos preços.

Claro que os céticos podem dizer que isso não passa de uma versão complicadamente estilizada da análise técnica clássica. Mas não é esse o propósito do progresso, olhar para o que já conhecemos com um novo ponto de vista? Afinal, um dia as velas japonesas também pareciam uma excentricidade, e hoje nenhum trader opera sem elas.

Nas próximas seções, vamos explorar detalhadamente as diversas formas de codificar os movimentos de preço e como essas informações podem ser úteis na prática do trading. Por ora, convido você a olhar para o seu gráfico favorito e tentar enxergá-lo como uma sequência de zeros e uns. Tenho certeza de que isso mudará sua visão sobre a análise técnica...


Princípios básicos da conversão

Lembra dos primeiros jogos de computador? Aqueles em que o gráfico era feito de pixels e o som era em 8 bits? Pois é, nossa abordagem à análise de mercado é parecida com a criação de um jogo retrô: pegamos o mundo complexo das cotações do mercado e o transformamos em um código binário simples.

Deixe-me contar como essa ideia surgiu. Um dia, enquanto eu desenvolvia mais um indicador, acabei por acaso exibindo no gráfico apenas zeros e uns em vez das linhas tradicionais. E sabe o que aconteceu? Começaram a surgir padrões interessantes naquela sequência de números. Era como se o mercado estivesse tentando dizer algo em sua linguagem binária.

Para quem gosta de mexer com código, é assim que funciona em Python:

def encode_price_movement(self, prices):
    normalized = ((prices - np.min(prices)) / 
                 (np.max(prices) - np.min(prices)) * 255).astype(np.uint8)
    data = bytes(normalized)
    entropy = hashlib.sha256(data).digest()
    mnemonic = self.mnemo.to_mnemonic(entropy)
    return mnemonic

Pelo sentido do movimento (alta/queda)

Sabe o que é mais curioso no trading? O fato de passarmos horas olhando gráficos tentando prever o próximo movimento de preço, quando no fundo tudo se resume à escolha mais simples possível: subir ou descer? Um ou zero?

Durante o desenvolvimento deste projeto, passei horas experimentando com o Bitcoin. Por que justamente ele? Porque cripto é código puro. Não há relatórios trimestrais, dividendos nem nenhuma dessas coisas fundamentalistas. Apenas a psicologia pura da massa, codificada em números.

Veja como é feita uma análise básica em Python:

def analyze_words_frequency(self, prices):
    price_diff = np.diff(prices)
    bullish_mnemonics = []
    bearish_mnemonics = []
    
    for i in range(len(price_diff)):
        window = prices[max(0, i-4):i+1]
        if len(window) < 5:
            continue
        mnemonic = self.encode_price_movement(window)
        if price_diff[i] > 0:
            bullish_mnemonics.extend(mnemonic.split())
        else:
            bearish_mnemonics.extend(mnemonic.split())

E agora vem a parte mais interessante que é como isso funciona no trading real. Imagine: você olha para um gráfico e, em vez das velas tradicionais, enxerga a sequência "1011101". Parece algo sem sentido? Pois não é! Essa sequência pode dizer mais do que uma dúzia de indicadores técnicos.

É curioso, mas quando mostrei esse código aos meus colegas traders, no começo eles fizeram pouco caso. "Pra quê complicar?", diziam. Até que um deles reparou num detalhe interessante: certas sequências binárias aparecem com mais frequência antes de grandes movimentos do que seria esperado pela teoria das probabilidades.

Claro que isso não significa que inventamos uma máquina de fazer dinheiro. Mas vamos combinar, pois há algo fascinante na ideia de que o mercado se comunica conosco através de um código binário. Igualzinho naquela "Matrix", lembra?

Com relação à média móvel

Trabalhando com o MetaTrader 5 via Python, descobri uma nova maneira de olhar para médias móveis. Engraçado como as coisas acontecem, já que só queria conectar o terminal ao Python, mas acabei encontrando algo além disso.

import MetaTrader5 as mt5
import numpy as np

def encode_ma_crossings(symbol, timeframe, ma_period=20):
    # Connect to the terminal
    if not mt5.initialize():
        print("MT5 initialization error")
        return None
        
    # Get data
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1000)
    prices = np.array([rate[4] for rate in rates])  # Use Close prices
    
    # Calculate SMA and program crossover
    ma = np.convolve(prices, np.ones(ma_period)/ma_period, mode='valid')
    crossings = prices[ma_period-1:] > ma
    
    mt5.shutdown()
    return np.where(crossings, 1, 0)

O mais interessante começou quando percebi uma regularidade estranha: no gráfico do Bitcoin, a sequência "101" próxima à média móvel frequentemente antecedia movimentos fortes. Especialmente em períodos de alta volatilidade. Como se o mercado estivesse "se preparando" para um salto.

Pela força do movimento (impulso)

"O mercado ou dorme ou corre", essa é uma frase que costumo repetir aos amigos traders. Agora imagine: podemos codificar esses estados com simples zeros e uns. Lindo, né?

def encode_momentum(symbol, timeframe, threshold=0.02):
    if not mt5.initialize():
        return None
        
    # Load data from MT5
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1000)
    prices = np.array([rate[4] for rate in rates])
    
    # Calculate price changes
    price_changes = np.diff(prices) / prices[:-1]
    
    # Program strong movements
    strong_moves = np.abs(price_changes) > threshold
    momentum = np.zeros_like(price_changes)
    momentum[strong_moves] = np.sign(price_changes[strong_moves])
    
    mt5.shutdown()
    return momentum

Lembro do meu primeiro experimento com esse código. Rodei no gráfico horário do ETH/USD, e sabe o que descobri? Que após a sequência "000", (período de baixa volatilidade), a chance de um movimento forte aumentava em 23%. Não que isso seja uma regra de ouro no trading, mas convenhamos que é algo que dá o que pensar.

Aliás, quando incluí os volumes na análise, a coisa ficou ainda mais interessante. Mas isso fica para as próximas seções. Por enquanto, convido você a brincar com esses padrões. Quem sabe você não encontra algo que eu deixei passar.

Sobre os volumes negociados


E com os volumes surgiu uma história curiosa. No começo, não dei muita importância pra eles, e pensei: "mais um parâmetro pra codificar". Mas quando comecei a analisar os padrões no BTC/USD, percebi que os volumes às vezes dizem mais que o próprio preço.

import MetaTrader5 as mt5
import numpy as np
from datetime import datetime

def encode_volume_patterns(symbol, timeframe):
    if not mt5.initialize():
        return None
    
    # Take volume data
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, 1000)
    volumes = np.array([rate[5] for rate in rates])
    
    # Calculate average volume for the last 20 bars
    avg_volume = np.convolve(volumes, np.ones(20)/20, mode='valid')
    
    # Code: 1 for volume above average and 0 - for below
    volume_code = volumes[19:] > avg_volume
    
    mt5.shutdown()
    return np.where(volume_code, 1, 0)

Sabe o que acabou sendo o mais interessante? A sequência "111" nos volumes (três barras com volume alto seguidas) costuma aparecer antes de movimentos sérios. É como se os "baleias" estivessem aquecendo antes da corrida. Isso fica especialmente visível no gráfico de 4 horas.


Timeframes e seu impacto na codificação

Lembro de uma noite em que fiquei horas sobre o código, tentando entender por que os mesmos padrões funcionam de formas diferentes em timeframes distintos. E então tive um estalo, e se olharmos o mesmo momento no tempo em vários timeframes ao mesmo tempo?

def multi_timeframe_code(symbol, timeframes=[mt5.TIMEFRAME_M15, mt5.TIMEFRAME_H1, mt5.TIMEFRAME_H4]):
    if not mt5.initialize():
        return None
    
    combined_code = []
    
    for tf in timeframes:
        rates = mt5.copy_rates_from_pos(symbol, tf, 0, 100)
        prices = np.array([rate[4] for rate in rates])
        
        # Code direction on each timeframe
        price_direction = np.diff(prices) > 0
        combined_code.append(np.where(price_direction, 1, 0))
    
    mt5.shutdown()
    
    # Combine codes from different timeframes
    return np.array(combined_code)

Os resultados me surpreenderam. Descobri que algumas combinações só aparecem em determinados horários do dia. Por exemplo, no par EUR/USD, a sequência "101" no gráfico de 15 minutos tem um significado completamente diferente durante a sessão asiática do que durante a sessão europeia.

Teve até um caso curioso: estava operando essa abordagem no ETHUSDT e percebi algo estranho, e é que antes de cada grande movimento no gráfico de 1 hora aparecia a sequência "110", enquanto no gráfico de 4 horas, no mesmo período, aparecia "101". Coincidência? Pode ser. Mas depois da quinta vez, já não parecia tanto assim.

Aliás, é curioso ver como alguns setups "perfeitos" nos timeframes menores se desfazem diante da dura realidade dos maiores. Hoje, antes de entrar em qualquer operação, eu sempre verifico os padrões binários em pelo menos três timeframes. Exagero? Talvez. Mas no trading é melhor errar por excesso de cautela do que por falta dela.


Buscando e explorando padrões binários brutos e ingênuos com entropia zero

Deixe-me contar como surgiu a ideia de buscar padrões nos padrões binários do mercado. Tudo começou com uma observação simples: qualquer movimento de preço pode ser representado como uma cadeia de zeros e uns. Mas quanto mais eu investigava, mais interessante ficava.

import MetaTrader5 as mt5
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import base58
from sklearn.preprocessing import StandardScaler
from collections import Counter

def initialize_mt5():
    if not mt5.initialize():
        print("Initialize() failed")
        mt5.shutdown()
        return False
    return True

def get_eurusd_data(start_date, end_date, timeframe):
    rates = mt5.copy_rates_range("EURUSD", timeframe, start_date, end_date)
    df = pd.DataFrame(rates)
    df['time'] = pd.to_datetime(df['time'], unit='s')
    return df

class PriceDecoder:
    def __init__(self, df):
        self.df = df
        self.binary_patterns = []
    
    # Method 1: Encoding based on the movement direction
    def direction_encoding(self, window=10):
        binary = (self.df['close'] > self.df['close'].shift(1)).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 2: Encoding based on relation to MA
    def ma_encoding(self, ma_period=20, window=10):
        ma = self.df['close'].rolling(ma_period).mean()
        binary = (self.df['close'] > ma).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 3: Encoding according to movement strength
    def momentum_encoding(self, threshold=0.0001, window=10):
        returns = self.df['close'].pct_change()
        binary = (returns.abs() > threshold).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method4: Volume encoding
    def volume_encoding(self, window=10):
        avg_volume = self.df['tick_volume'].rolling(window).mean()
        binary = (self.df['tick_volume'] > avg_volume).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 5: Fractal encoding
    def fractal_encoding(self, window=10):
        highs = self.df['high'].rolling(5, center=True).max()
        lows = self.df['low'].rolling(5, center=True).min()
        binary = ((self.df['high'] == highs) | (self.df['low'] == lows)).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 6: Volatility encoding
    def volatility_encoding(self, window=10):
        volatility = self.df['high'] - self.df['low']
        avg_volatility = volatility.rolling(20).mean()
        binary = (volatility > avg_volatility).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 7: Candlestick pattern encoding
    def candle_pattern_encoding(self, window=10):
        body = abs(self.df['close'] - self.df['open'])
        shadow = self.df['high'] - self.df['low']
        binary = (body > shadow/2).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 8: Entropy Encoding
    def entropy_encoding(self, window=10):
        returns = self.df['close'].pct_change()
        entropy = returns.rolling(window).apply(lambda x: np.sum(-x[x!=0]*np.log2(abs(x[x!=0]))))
        binary = (entropy > entropy.mean()).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 9: Convergence/divergence encoding
    def convergence_encoding(self, window=10):
        ma_fast = self.df['close'].rolling(5).mean()
        ma_slow = self.df['close'].rolling(20).mean()
        binary = (ma_fast > ma_slow).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 10: Price level encoding
    def price_level_encoding(self, window=10):
        pivot = (self.df['high'] + self.df['low'] + self.df['close']) / 3
        binary = (self.df['close'] > pivot).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 11: RSI momentum encoding
    def rsi_momentum_encoding(self, window=10, rsi_period=14):
        delta = self.df['close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=rsi_period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=rsi_period).mean()
        rs = gain / loss
        rsi = 100 - (100 / (1 + rs))
        binary = (rsi > 50).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 12: Cluster encoding
    def cluster_encoding(self, window=10):
        prices = self.df['close'].values.reshape(-1, 1)
        scaler = StandardScaler()
        prices_scaled = scaler.fit_transform(prices)
        binary = (prices_scaled > 0).astype(int).flatten()
        pattern = ''.join(map(str, binary[-window:]))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 13: Extremum encoding
    def extremum_encoding(self, window=10):
        highs = self.df['high'].rolling(window).max()
        lows = self.df['low'].rolling(window).min()
        mid = (highs + lows) / 2
        binary = (self.df['close'] > mid).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 14: Trend encoding
    def trend_encoding(self, window=10):
        slope = pd.Series(np.nan, index=self.df.index)
        for i in range(window, len(self.df)):
            y = self.df['close'].iloc[i-window:i].values
            x = np.arange(window)
            slope[i] = np.polyfit(x, y, 1)[0]
        binary = (slope > 0).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    # Method 15: Hybrid encoding
    def hybrid_encoding(self, window=10):
        direction = (self.df['close'] > self.df['close'].shift(1)).astype(int)
        volume = (self.df['tick_volume'] > self.df['tick_volume'].rolling(window).mean()).astype(int)
        volatility = ((self.df['high'] - self.df['low']) > 
                     (self.df['high'] - self.df['low']).rolling(window).mean()).astype(int)
        binary = (direction & volume & volatility).astype(int)
        pattern = ''.join(binary.astype(str).tail(window))
        return pattern, self.analyze_pattern(pattern)
    
    def analyze_pattern(self, pattern, min_seq_len=2, max_seq_len=8):
        # Convert to base58 for compactness
        base58_pattern = base58.b58encode(pattern.encode()).decode()
        
        # Advanced repeatability analysis with different depths
        repeating_sequences = {}
        for seq_len in range(min_seq_len, max_seq_len + 1):
            sequences_at_depth = []
            for i in range(len(pattern) - seq_len + 1):
                sequence = pattern[i:i+seq_len]
                count = pattern.count(sequence)
                if count > 1:
                    sequences_at_depth.append({
                        'sequence': sequence,
                        'count': count,
                        'positions': [j for j in range(len(pattern)) if pattern[j:j+seq_len] == sequence]
                    })
            if sequences_at_depth:
                repeating_sequences[seq_len] = sorted(sequences_at_depth, 
                                                    key=lambda x: (x['count'], len(x['sequence'])), 
                                                    reverse=True)
        
        # Entropy analysis for different windows
        entropy_analysis = {}
        for window_size in range(2, min(9, len(pattern) + 1)):
            windows = [pattern[i:i+window_size] for i in range(len(pattern)-window_size+1)]
            window_entropy = {}
            for window in set(windows):
                count = windows.count(window)
                prob = count / len(windows)
                local_entropy = -prob * np.log2(prob) if prob > 0 else 0
                window_entropy[window] = {
                    'count': count,
                    'probability': prob,
                    'entropy': local_entropy
                }
            entropy_analysis[window_size] = window_entropy
        
        # Search for stable patterns (with zero entropy)
        stable_patterns = []
        for window_size, patterns in entropy_analysis.items():
            zero_entropy_patterns = {
                pattern: data for pattern, data in patterns.items() 
                if abs(data['entropy']) < 0.01 and data['count'] > 1
            }
            if zero_entropy_patterns:
                stable_patterns.append({
                    'window_size': window_size,
                    'patterns': zero_entropy_patterns
                })
        
        # Basic statistics
        ones_count = pattern.count('1')
        zeros_count = pattern.count('0')
        overall_entropy = 0
        if len(pattern) > 0:
            probabilities = [pattern.count(char)/len(pattern) for char in set(pattern)]
            overall_entropy = -sum(p * np.log2(p) for p in probabilities if p > 0)
        
        return {
            'base58': base58_pattern,
            'repeating_sequences': repeating_sequences,
            'stable_patterns': stable_patterns,
            'entropy_analysis': entropy_analysis,
            'ones_ratio': ones_count / len(pattern),
            'zeros_ratio': zeros_count / len(pattern),
            'overall_entropy': overall_entropy
        }

def main():
    if not initialize_mt5():
        return
    
    # Get data for the last month
    end_date = datetime.now()
    start_date = end_date - timedelta(days=30)
    df = get_eurusd_data(start_date, end_date, mt5.TIMEFRAME_H1)
    
    decoder = PriceDecoder(df)
    
    # Use all encoding methods
    methods = [
        ('Direction', decoder.direction_encoding),
        ('MA', decoder.ma_encoding),
        ('Momentum', decoder.momentum_encoding),
        ('Volume', decoder.volume_encoding),
        ('Fractal', decoder.fractal_encoding),
        ('Volatility', decoder.volatility_encoding),
        ('Candle Pattern', decoder.candle_pattern_encoding),
        ('Entropy', decoder.entropy_encoding),
        ('Convergence', decoder.convergence_encoding),
        ('Price Level', decoder.price_level_encoding),
        ('RSI Momentum', decoder.rsi_momentum_encoding),
        ('Cluster', decoder.cluster_encoding),
        ('Extremum', decoder.extremum_encoding),
        ('Trend', decoder.trend_encoding),
        ('Hybrid', decoder.hybrid_encoding)
    ]
    
    print("\nPrice Pattern Analysis Results:")
    print("-" * 50)
    
    for method_name, method in methods:
        pattern, analysis = method()
        print(f"\n{method_name} Encoding:")
        print(f"Pattern: {pattern}")
        print(f"Base58: {analysis['base58']}")
        print("\nStable Patterns with Zero Entropy:")
        for stable_group in analysis['stable_patterns']:
            print(f"\nWindow Size {stable_group['window_size']}:")
            for pattern, data in stable_group['patterns'].items():
                print(f"  {pattern}: appears {data['count']} times")
        
        print("\nRepeating Sequences by Length:")
        for length, sequences in analysis['repeating_sequences'].items():
            print(f"\nLength {length}:")
            for seq in sequences[:3]:  # show top 3 for each length
                print(f"  {seq['sequence']}: appears {seq['count']} times at positions {seq['positions']}")
        
        print(f"\nBasic Statistics:")
        print(f"Ones ratio: {analysis['ones_ratio']:.2f}")
        print(f"Zeros ratio: {analysis['zeros_ratio']:.2f}")
        print(f"Overall entropy: {analysis['overall_entropy']:.2f}")
    
    mt5.shutdown()

if __name__ == "__main__":
    main()

Imagine que você olha para o gráfico não como um trader, mas como um decodificador. Cada barra é uma letra em uma mensagem misteriosa do mercado. Basta descobrir qual alfabeto ele está usando.

Criei 15 métodos diferentes de codificação, cada um com sua própria lógica:

  • direction_encoding — o método mais simples. O preço está acima do anterior? Um. Abaixo? Zero. Como o código Morse para iniciantes.
  • ma_encoding — já é mais interessante. Observamos o cruzamento do preço com a média móvel. Quando testei no EURUSD, reparei numa coisa curiosa — algumas combinações apareciam com mais frequência durante a sessão europeia.
  • momentum_encoding — analisar a força do movimento. Sabe o que é surpreendente? Depois de três zeros seguidos (período de impulso fraco), geralmente ocorre um forte pico de atividade.
  • volume_encoding — análise dos volumes em formato binário. Lembro de quando notei um padrão estranho no Bitcoin – "10101" nos volumes quase sempre antecedia um movimento forte.
  • fractal_encoding — padrões fractais em binário. É como buscar os fractais de Bill Williams, só que no mundo dos zeros e uns.
  • volatility_encoding — codificar a volatilidade. Engraçado como certos padrões de volatilidade eram tão estáveis que sua entropia praticamente zerava.
  • candle_pattern_encoding — padrões clássicos de velas representados em binário. Um doji, nesse sistema, aparece como "101".
  • entropy_encoding — medir a entropia informacional dos movimentos de preço. Quando a entropia cai perto de zero, prepare-se para surpresas.
  • convergence_encoding — convergência-divergência de médias móveis em binário. O clássico da análise técnica em um novo formato.
  • price_level_encoding — codificamos a relação do preço com níveis-chave. Os padrões mais interessantes costumam surgir perto dos números redondos.
  • rsi_momentum_encoding — RSI em formato binário. Descobri que algumas combinações "101" no RSI apresentam entropia quase nula.
  • cluster_encoding — análise de clusters de preço em binário. É como identificar zonas de acúmulo de ordens, só que em código.
  • extremum_encoding — máximas e mínimas locais como zeros e uns. Às vezes, surgem sequências bem características antes de reversões importantes.
  • trend_encoding — direção da tendência em binário. Esse método funciona muito bem em timeframes maiores.
  • hybrid_encoding — combinação de todas as abordagens. Como um superindicador, só que em formato binário.

A parte mais empolgante começou quando acrescentei o analyze_pattern. Esse método não só busca sequências repetidas, pois ele mede a entropia, converte para base58 para tornar mais compacta e identifica os padrões com entropia zero.

Sabe o que mais me impressionou? Alguns padrões aparecem com tanta regularidade que fica difícil acreditar que seja por acaso. Por exemplo, a sequência "11001" no hybrid_encoding costuma surgir antes de grandes movimentos no EURUSD.

Lembra da teoria do caos e do efeito borboleta? Pois é, às vezes, nesse caos dos movimentos de preço, surgem ilhas de ordem, isto é, padrões com entropia quase nula. É como se o mercado, por um instante, deixasse escapar seus planos...

Nas próximas seções, vamos conversar sobre como aplicar esses padrões no trading real. Por enquanto, convido você a experimentar o código. Quem sabe você encontra suas próprias regularidades únicas no código binário do mercado?


Analisando padrões binários ingênuos nos preços

Ao examinar os resultados dos experimentos com codificação binária do mercado, descobri algumas regularidades inesperadas. Vamos dar uma olhada nas descobertas mais interessantes.

Antes de tudo, repare no padrão de momentum "1010111111". Surpreendentemente, com entropia de 0,72, esse padrão apareceu 43 vezes no nosso intervalo de tempo! A rentabilidade média foi de -0,01%, e o win rate de 44,19%. À primeira vista, o resultado pode não impressionar, mas o lucro máximo chegou a +0,34%, com um rebaixamento máximo de -0,42%. Isso mostra o potencial do padrão quando aplicado com um bom gerenciamento de risco.

Nos volumes, temos a sequência característica "0111001111" com proporção de uns para zeros de 70/30. Ao longo de um mês, esse padrão apareceu 13 vezes, com um win rate de 46,15%. Interessante notar que, mesmo com rentabilidade média negativa (-0,06%), o ganho máximo alcançou +0,28%.

A verdadeira revelação foram os padrões de convergência/divergência (Convergence). A sequência "0000000000", com entropia zero, apareceu incríveis 1652 vezes! O win rate foi de 53,27%, e o lucro máximo chegou a +0,68%. Considerando o número de sinais, trata-se de um resultado estatisticamente relevante.

Entre todos os métodos, os que apresentaram melhor desempenho foram:

  • Padrão fractal "0110000100": win rate de 63,64% em 11 operações, rentabilidade média de +0,14%
  • Padrão de volatilidade "0010001011": 100% de acerto em 2 operações, rentabilidade média de +0,21%
  • Padrão de velas "1010111110": 100% de acerto em 3 operações, rentabilidade média de +0,04%

Quanto à codificação híbrida ("0010000011"), ela gerou 12 sinais com um win rate de 25% e rentabilidade média de -0,04%. No entanto, o lucro máximo foi de +0,33%, o que sugere que o método tem potencial, desde que os sinais sejam bem filtrados.

O padrão RSI Momentum ("0010000001") apresentou resultados particularmente curiosos. Apesar de ter aparecido apenas três vezes no mês, todas as ocorrências foram negativas, o que pode indicar um forte sinal para abrir posições na direção contrária.

Com base nessas estatísticas, uma estratégia otimizada poderia ser algo assim:

  1. Sinal principal: padrão de codificação fractal (63,64% de acertos)
  2. Confirmação: convergência (alta frequência de ocorrência e win rate positivo)
  3. Filtro: padrões de volatilidade e de velas (100% de acertos)

Nas próximas seções, vamos explorar mais a fundo o uso prático dessas regularidades no trading real. Por ora, posso afirmar que a codificação binária realmente permite enxergar o mercado sob uma nova perspectiva e identificar regularidades ocultas em seu comportamento.


Tentativas de decodificar o código binário do mercado com redes neurais

Em determinado momento, enquanto analisava esses padrões binários, me perguntei e se ensinássemos o computador a "ler" essa linguagem peculiar do mercado? Foi assim que surgiu a ideia de usar o CatBoost para prever os próximos movimentos de preço.

A grande vantagem do CatBoost é sua excelente capacidade de lidar com dados categóricos. E nossos padrões binários são, na essência, categorias, ou seja, sequências de zeros e uns, cada uma representando um estado específico do mercado.

O núcleo do sistema foi a classe BinaryPatternPredictor. Sua principal função é transformar os padrões binários em atributos compreensíveis pela rede neural. Para isso, usei a técnica da janela deslizante: pegamos um trecho do histórico (período de lookback) e tentamos prever se, na próxima janela, haverá mais uns ou mais zeros.

A parte mais interessante começou durante o desenvolvimento do método prepare_features. Imagine: cada padrão se transforma num conjunto de atributos. Não só a própria sequência de zeros e uns, mas também métricas adicionais: quantos uns há na janela, qual a tendência nos últimos valores, como isso se relaciona com outros métodos de codificação.

Lembro do meu primeiro experimento com o método momentum. No código, parecia simples:

returns = self.decoder.df['close'].pct_change()
base_binary = (returns.abs() > 0.0001).astype(int)

Mas por trás dessas linhas existe toda uma filosofia, já que estamos convertendo a força do movimento de preço em uma sequência simples de zeros e uns.

O método híbrido, por outro lado, ficou particularmente interessante:

direction = (self.decoder.df['close'] > self.decoder.df['close'].shift(1)).astype(int)
volume = (self.decoder.df['tick_volume'] > self.decoder.df['tick_volume'].rolling(self.lookback).mean()).astype(int)
volatility = ((self.decoder.df['high'] - self.decoder.df['low']) > 
              (self.decoder.df['high'] - self.decoder.df['low']).rolling(self.lookback).mean()).astype(int)
base_binary = (direction & volume & volatility)

Aqui combinamos três visões distintas do mercado: direção do movimento, volume e volatilidade. É como os "três pilares" da análise técnica, só que em formato binário.

No método train, optei por não embaralhar os dados (shuffle=False). Por quê? Porque no trading real o que importa é como o modelo se comporta com dados em sequência, pois, afinal, o mercado não espalha seus padrões aleatoriamente, ele os forma um após o outro.

Quando chegou a hora de fazer previsões com predict_next_pattern, adicionei um cálculo de confiança da previsão:

prediction = self.model.predict_proba(last_window)[0]
return {
    'probability_more_ones': prediction[1],
    'probability_more_zeros': prediction[0],
    'prediction': 'More ones' if prediction[1] > 0.5 else 'More zeros',
    'confidence': max(prediction)
}

Isso se mostrou extremamente útil, pois quanto maior a confiança do modelo, mais frequente era o acerto da previsão.

Na função principal main(), fiz a análise simultânea de vários métodos de codificação. Na prática, percebi que os desacordos entre os métodos muitas vezes trazem mais informação do que uma previsão unânime. Como naquele ditado: duas cabeças pensam melhor que uma, mas cinco métodos de codificação pensam ainda melhor!

Fiquei especialmente impressionado com a forma como o modelo aprendeu a identificar padrões não óbvios. Por exemplo, a combinação de baixa volatilidade com aumento de volume frequentemente antecipava uma predominância de uns na janela seguinte. Isso, no fundo, é a clássica situação de acúmulo de posições antes de um movimento forte!


Resultados da rede neural

Sabe o que realmente me surpreendeu nos resultados desse experimento? Cada método de codificação revelou seu próprio "caráter", assim como os diferentes indicadores na análise técnica clássica.

Vamos começar com o momentum — simplesmente fantástico! Precisão de 95% e F1-score de 0,92 indicam que o modelo praticamente não comete erros ao interpretar os movimentos impulsivos do mercado. O mais interessante é que a previsão aponta 95% de chance de predominância de uns no próximo padrão. Na prática, isso é um sinal de continuação de um movimento forte.

A análise de volume também não ficou atrás. Com precisão de 83% e métricas equilibradas (precision e recall também em torno de 0,83), ela capta muito bem a atividade dos grandes players. Quando vi uma previsão com 94% de confiança na predominância de uns, imediatamente lembrei da velha máxima: "o volume confirma a tendência".

Já o método de convergência/divergência trouxe uma surpresa. Com a mesma precisão de 83%, ele prevê predominância de zeros com 78% de confiança. Isso vai diretamente contra os sinais do momentum e do volume! Tal divergência costuma indicar uma possível reversão de tendência se aproximando.

O método híbrido acabou sendo uma verdadeira revelação. Precisão de 91% e precisão (precision) de 0,92 mostram que a combinação de abordagens diferentes oferece resultados mais estáveis. Curiosamente, ele também prevê predominância de zeros (75% de chance), reforçando o sinal dado pelo método de convergência.

Lembro de quando testei esse modelo com dados reais do EURUSD. Em um dos dias, todos os métodos mostraram alta precisão, mas divergiram nas previsões, exatamente como agora. Poucas horas depois, aconteceu uma forte reversão de tendência. Coincidência? Talvez. Mas desde então, passei a observar com atenção esse tipo de "desacordo" entre os métodos.

No geral, esses resultados sugerem algo interessante: talvez o mercado realmente esteja tentando se comunicar conosco por meio de padrões binários, só que nem sempre sabemos como escutá-lo. E parece que a rede neural faz isso melhor do que nós.

Aliás, um detalhe importante, todas essas métricas foram obtidas em timeframe de 1 hora. Em outros intervalos, o cenário pode ser completamente diferente. Especialmente quando se aplica a ideia dos "barras 3D"...Mas isso já é assunto para outro estudo...


Considerações finais

No início deste artigo, nos perguntamos: é possível ouvir a voz do mercado por meio do código binário? Depois de meses de experimentos, milhares de linhas de código e incontáveis horas de análise, posso dizer que sim: o mercado realmente se comunica conosco em sua própria linguagem. Agora, começamos a entendê-la um pouco melhor.

Sabe o que mais me impressionou neste estudo? Foi perceber como uma simples conversão dos movimentos de preço em sequências de zeros e uns abre uma nova perspectiva sobre a análise técnica. Você nunca mais olhará os gráficos da mesma forma. Você passa a enxergar, em cada movimento, parte de uma grande mensagem digital.

Os resultados da rede neural são especialmente impressionantes. A precisão é de 95% nos padrões de momentum, 83% na análise de volume e 91% na abordagem híbrida. Esses não são apenas números frios. É a prova de que, dentro do aparente caos dos movimentos de mercado, existe uma ordem oculta que pode ser descoberta se soubermos onde procurar.

Claro, seria ingênuo pensar que encontramos a pedra filosofal do trading. O mercado é complexo e dinâmico demais para ser totalmente descrito, nem mesmo pelo algoritmo mais sofisticado. No entanto, descobrimos uma nova ferramenta para compreendê-lo melhor.

Para mim, esse projeto acabou sendo mais do que um experimento com código. Ele me lembrou que sempre há espaço para inovação no trading, para enxergar o velho com olhos novos. E talvez o próximo grande avanço na análise de mercado não venha das fórmulas mais complexas, mas da capacidade de compreender a linguagem binária do mercado.

E o que vem depois? A sensação que tenho é que estamos só no começo. Há muito ainda a explorar: novos métodos de codificação, relações entre diferentes timeframes, integração com abordagens clássicas da análise técnica. Mas o mais importante é continuar ouvindo o mercado. Porque ele sempre está pronto para revelar seus segredos àqueles que sabem escutar, e cujo coração está aberto à inovação. E a inovação é a base do progresso. 

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/16741

Arquivos anexados |
Price_Binary_v_1.py (27.43 KB)
Últimos Comentários | Ir para discussão (1)
Maxim Dmitrievsky
Maxim Dmitrievsky | 14 jan. 2025 em 17:16
Parece que a binarização e a quantificação de recursos, no tópico MO do fórum, não resultaram em nada :)
Do básico ao intermediário: Eventos de mouse Do básico ao intermediário: Eventos de mouse
Este artigo, é uns dos que definitivamente, é necessário não apenas ver o código e o estudar para compreender o que estará acontecendo. É de fato, necessário, criar uma aplicação executável e a utilizar em um gráfico qualquer. Isto maneira a conseguir entender pequenos detalhes, que de outra forma são muito complicados de serem compreendidos. Como por exemplo, a combinação de teclado com o mouse, a fim de construir certos tipos de coisas.
Redes neurais em trading: Agente multimodal com ferramentas complementares (FinAgent) Redes neurais em trading: Agente multimodal com ferramentas complementares (FinAgent)
Apresentamos o framework do agente multimodal para negociação financeira FinAgent, projetado para analisar dados de diferentes tipos que refletem a dinâmica do mercado e padrões históricos de negociação.
Do básico ao intermediário: Objetos (III) Do básico ao intermediário: Objetos (III)
Neste artigo iremos ver como podemos implementar um sistema de interação muito bacana e bastante interessante. Ainda mais para quem esteja começando a praticar programação MQL5. Não se trata de algo realmente novo. Porém a forma como irei abordar o assunto, de fato, tornará tudo muito mais simples de entender. Já que iremos ver na prática uma programação estrutural sendo feita com um objetivo bastante divertido.
Simulação de mercado: Iniciando o SQL no MQL5 (II) Simulação de mercado: Iniciando o SQL no MQL5 (II)
Apesar de muitos imaginarem que podemos usar tranquilamente códigos em SQL dentro de outros códigos. Isto normalmente não se aplica. Devido ao fato, de que um código SQL, será sempre colocado dentro de um executável, como sendo uma string. E este fato de colocar o código SQL como sendo uma string, apesar de não ser problemático, para pequenos trechos de código. Podem sim ser algo que nos causará muitos transtornos e uma baita de uma dor de cabeça.