Русский
preview
Mineração de dados da CFTC em Python e modelo de IA com base neles

Mineração de dados da CFTC em Python e modelo de IA com base neles

MetaTrader 5Integração |
42 1
Yevgeniy Koshtenko
Yevgeniy Koshtenko
Uma negociação bem-sucedida no mercado de câmbio exige não apenas análise técnica, mas também a consideração de fatores fundamentais. Fontes valiosas, porém frequentemente ignoradas, são os relatórios da CFTC (COT e TFF), que revelam as posições dos maiores participantes do mercado e permitem avaliar o comportamento de investidores institucionais.

O mercado Forex é o maior do mundo, mas sua alta volatilidade torna a previsão complexa. Os relatórios COT/TFF fornecem entendimento das ações do "dinheiro inteligente" e ajudam a identificar tendências de mercado ocultas.

A abordagem proposta combina dados COT/TFF e cotações de mercado em um único modelo em Python, com negociação automática via MetaTrader 5. Isso permite passar da análise para a ação sem atrasos e sem intervenção humana.



Base teórica

O que são os relatórios COT e TFF

Imagine que você tem a possibilidade de olhar dentro das carteiras dos maiores players do mercado de câmbio, hedge funds com ativos bilionários, fundos de pensão, bancos de investimento. É exatamente isso que fazem os relatórios COT e TFF, publicados toda sexta-feira pela Comissão de Negociação de Futuros de Commodities dos EUA (CFTC).

Esses relatórios surgiram após as crises de mercado das décadas de 1970 e 1980, quando os reguladores perceberam que os participantes do mercado precisavam de informações sobre o que os grandes players estavam fazendo. Agora, todos que mantêm posições acima de um determinado limite são obrigados a divulgar suas posições. A CFTC coleta essas informações e as publica de forma agregada, mostrando as posições no fechamento da terça-feira.

Quem é quem no mercado: participantes e seus motivos

Traders comerciais são negócios reais que utilizam futuros não para especulação, mas para proteção contra riscos. Uma companhia aérea compra futuros de petróleo para fixar o preço do combustível. Um exportador vende futuros de moeda para se proteger contra a queda da taxa de câmbio. Um agricultor vende futuros de trigo antecipadamente para saber quanto receberá pela colheita.

Traders não comerciais são especuladores que negociam visando lucro com movimentos de preço. Hedge funds, bancos de investimento, grandes gestoras de recursos. Eles são frequentemente chamados de "dinheiro inteligente", porque têm recursos para uma análise profunda dos mercados.

Pequenos traders são todos os demais participantes com posições abaixo dos limites de reporte. Traders de varejo, pequenos fundos, especuladores individuais.

O que mostram os relatórios COT

Os relatórios COT fornecem uma visão geral de todos os mercados futuros. Para cada grupo de participantes, são mostradas as posições longas (apostas na alta), as posições curtas (apostas na queda) e as posições líquidas (a diferença entre longas e curtas). O interesse aberto mostra o número total de contratos ativos no mercado.

Por exemplo, se no euro os traders não comerciais mantêm uma posição líquida longa de +120.000 contratos, isso significa que os especuladores, em geral, apostam na alta do EUR/USD. Se os traders comerciais mostram -115.000 contratos, então os hedgeadores ou esperam o enfraquecimento do euro ou simplesmente estão se protegendo contra riscos cambiais.

O que os relatórios TFF acrescentam

Os relatórios TFF focam apenas em futuros financeiros e mostram um quadro mais detalhado das posições institucionais. Aqui, os traders não comerciais são divididos em subcategorias: fundos alavancados (hedge funds agressivos, que utilizam ativamente capital emprestado) e gestores de ativos (fundos de pensão conservadores e seguradoras). Também são destacados os dealers e intermediários, bancos que fornecem liquidez ao mercado.

Essa nível de detalhe é criticamente importante. Se fundos alavancados aumentam bruscamente posições longas em dólar, isso é um sinal de interesse especulativo de curto prazo. Se os gestores de ativos fazem o mesmo, isso indica uma mudança de sentimento de longo prazo dos investidores institucionais.

Por que isso é importante para os traders

O principal valor dos relatórios está no fato de mostrarem para onde o "dinheiro inteligente" está se movendo antes mesmo de isso se refletir nos preços. Grandes players frequentemente atuam com base em informações indisponíveis aos participantes comuns do mercado.

Identificação de extremos. Quando os especuladores ocupam posições longas recordes, o mercado costuma estar sobrecomprado e pronto para uma correção. A situação inversa sinaliza um possível repique. Isso funciona pelo princípio da negociação contrária, isto é, agir contra a multidão em momentos de extremos.

Confirmação de tendências. Se o preço sobe e os traders não comerciais continuam aumentando posições longas, a tendência é forte. Se eles começam a reduzir posições enquanto os preços ainda sobem, a tendência enfraquece.

Detecção antecipada de reversões. Divergências entre preço e posições frequentemente antecedem reversões. O preço pode continuar subindo, mas se os grandes players já estão reduzindo apostas na alta, a reversão está próxima.

Exemplo prático

Suponha que o relatório de EUR/USD mostre: fundos alavancados mantêm +85.000 contratos, gestores de ativos +25.000, e dealers -95.000. Isso significa que tanto os especuladores agressivos quanto os investidores institucionais conservadores apostam na alta do euro. Os dealers ocupam o lado oposto, possivelmente atendendo ordens de clientes ou protegendo seus próprios riscos. O sinal geral é altista para o euro.

Nuances importantes

Os dados são publicados com um atraso de três dias, o que é crítico em mercados que mudam rapidamente. Nem todas as posições comerciais representam hedge puro, alguns bancos podem especular sob a aparência de atividade comercial. A negociação algorítmica e o aprendizado de máquina estão alterando os modelos comportamentais tradicionais dos participantes.

Algoritmos modernos podem usar os próprios relatórios COT/TFF para tomada de decisão, o que cria profecias autorrealizáveis e torna a interpretação dos dados mais complexa.

Por que isso funciona

Os relatórios COT e TFF funcionam porque mostram apostas reais de dinheiro, e não opiniões ou previsões. Quando um hedge fund aposta bilhões de dólares em uma direção específica do mercado, isso é um sinal muito mais significativo do que quaisquer comentários públicos. Esses dados refletem a sabedoria coletiva dos participantes mais informados e com maior disponibilidade de recursos do mercado.

Em combinação com aprendizado de máquina e negociação automatizada, a análise de posições institucionais se torna uma ferramenta poderosa para a criação de estratégias de trading baseadas no comportamento daqueles que realmente movem os mercados.

Previsão de preços usando dados COT/TFF

A previsão de preços é baseada na suposição de que as posições dos grandes players se correlacionam com movimentos futuros de preços. Por exemplo, o aumento de posições longas de traders não comerciais pode sinalizar um mercado altista, enquanto o crescimento de posições curtas pode indicar um viés baixista. Esses dados são usados como características para o modelo de aprendizado de máquina, complementados por preços históricos do MetaTrader 5 e indicadores técnicos, como volatilidade e médias móveis. Essa abordagem permite capturar relações complexas entre o sentimento de mercado e as tendências de preço.



Preparação dos dados

Os relatórios COT e TFF são publicados em formato Excel no site da CFTC. Para o download, utiliza-se a biblioteca requests e, para o processamento, pandas. O código abaixo demonstra o carregamento e o pré-processamento dos dados COT com uso de cache para aumentar a performance:

import requests
import zipfile
import pandas as pd
import os
import logging
import MetaTrader5 as mt5
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import importlib.util
import glob
import asyncio

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = [10, 6]

COT_URL = "https://www.cftc.gov/files/dea/history/dea_fut_xls_2024.zip"
TFF_URL = "https://www.cftc.gov/files/dea/history/fut_fin_xls_2024.zip"
OUTPUT_DIR = "data"
os.makedirs(OUTPUT_DIR, exist_ok=True)

def load_cot_reports() -> pd.DataFrame:
    cache_path = os.path.join(OUTPUT_DIR, "cot_report.csv")
    if os.path.exists(cache_path):
        logger.info(f"Загрузка COT данных из кэша: {cache_path}")
        return pd.read_csv(cache_path)

    try:
        response = requests.get(COT_URL)
        response.raise_for_status()
        zip_path = os.path.join(OUTPUT_DIR, "cot_data.zip")
        with open(zip_path, "wb") as f:
            f.write(response.content)

        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            zip_ref.extractall(OUTPUT_DIR)
            excel_file = [f for f in zip_ref.namelist() if f.endswith('.xls') or f.endswith('.xlsx')][0]
        
        cot_data = pd.read_excel(os.path.join(OUTPUT_DIR, excel_file))
        relevant_columns = [
            "Market_and_Exchange_Names",
            "NonComm_Positions_Long_All",
            "NonComm_Positions_Short_All",
            "Comm_Positions_Long_All",
            "Comm_Positions_Short_All",
            "Open_Interest_All"
        ]
        cot_data = cot_data[relevant_columns]
        cot_data["Net_NonComm"] = cot_data["NonComm_Positions_Long_All"] - cot_data["NonComm_Positions_Short_All"]
        cot_data["Net_Comm"] = cot_data["Comm_Positions_Long_All"] - cot_data["Comm_Positions_Short_All"]
        cot_data.to_csv(cache_path, index=False)
        logger.info(f"Отчет COT сохранен в {cache_path}")
        return cot_data
    except Exception as e:
        logger.error(f"Ошибка при загрузке данных COT: {e}")
        return pd.DataFrame()

Para os relatórios TFF, aplica-se um processo semelhante, com filtragem por futuros de moedas e cálculo das posições líquidas para fundos alavancados e gestores de ativos. O cache de dados minimiza requisições de rede, acelerando o reprocessamento.

Integração com MetaTrader 5

Os preços históricos são carregados por meio da biblioteca MetaTrader 5, que fornece acesso aos dados de mercado. O código abaixo obtém preços horários dos últimos 30 dias:

def get_historical_prices(pair: str, days_history: int = 30) -> pd.DataFrame:
    if not mt5.initialize():
        logger.error("MT5 initialization failed")
        return pd.DataFrame()

    timeframe = mt5.TIMEFRAME_H1
    utc_from = datetime.now() - timedelta(days=days_history)
    rates = mt5.copy_rates_from(pair, timeframe, utc_from, 24 * days_history)
    
    if rates is None or len(rates) == 0:
        logger.warning(f"Нет исторических данных для {pair}")
        return pd.DataFrame()

    df = pd.DataFrame(rates)
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.set_index('time', inplace=True)
    df['price_change_24h'] = df['close'].shift(-24) / df['close'] - 1
    df.dropna(inplace=True)
    return df[['open', 'high', 'low', 'close', 'tick_volume', 'price_change_24h']]

Tratamento e união dos dados

Os dados COT, TFF e os preços históricos são combinados, e são adicionadas características derivadas: volatilidade (diferença entre o preço máximo e mínimo, normalizada pelo preço de fechamento), médias móveis de 24 horas para volume e preço, bem como defasagens e variações percentuais para as posições COT e TFF.

Código de preparação das características:

def prepare_features(pair: str, cot_data: pd.DataFrame, tff_data: pd.DataFrame) -> pd.DataFrame:
    df_prices = get_historical_prices(pair)
    if df_prices.empty:
        logger.warning(f"Нет ценовых данных для {pair}")
        df = pd.DataFrame(index=[datetime.now()], columns=['close', 'price_change_24h'])
        df['close'] = 1.0
        df['price_change_24h'] = 0.0
    else:
        df = df_prices.copy()

    df['volatility'] = (df['high'] - df['low']) / df['close']
    df['volume_sma_24'] = df['tick_volume'].rolling(window=24).mean()
    df['price_sma_24'] = df['close'].rolling(window=24).mean()
    df['price_change_1h'] = df['close'].pct_change()

    market = map_pair_to_cot_tff(pair)
    if market and not cot_data.empty:
        cot_subset = cot_data[cot_data["Market_and_Exchange_Names"].str.contains(market, case=False, na=False)]
        if not cot_subset.empty:
            cot_features = cot_subset[['Net_NonComm', 'Net_Comm']].mean().to_frame().T
            for col in cot_features.columns:
                df[col] = cot_features[col].iloc[0]

    if market and not tff_data.empty:
        tff_subset = tff_data[tff_data["Market_and_Exchange_Names"].str.contains(market, case=False, na=False)]
        if not tff_subset.empty:
            tff_features = tff_subset[['Net_Lev_Money', 'Net_Asset_Mgr']].mean().to_frame().T
            for col in tff_features.columns:
                df[col] = tff_features[col].iloc[0]

    for col in ['Net_NonComm', 'Net_Comm', 'Net_Lev_Money', 'Net_Asset_Mgr']:
        if col in df.columns:
            df[f'{col}_lag1'] = df[col].shift(1)
            df[f'{col}_change'] = df[col].pct_change().fillna(0)

    df.dropna(inplace=True)
    return df

def map_pair_to_cot_tff(pair: str) -> str:
    mapping = {
        'EURUSD': 'EURO FX',
        'GBPUSD': 'BRITISH POUND',
        'USDJPY': 'JAPANESE YEN',
        'AUDUSD': 'AUSTRALIAN DOLLAR',
        'USDCAD': 'CANADIAN DOLLAR',
        'USDCHF': 'SWISS FRANC',
        'NZDUSD': 'NEW ZEALAND DOLLAR'
    }
    base_pair = pair.replace('.ecn', '')[:6]
    return mapping.get(base_pair, '')

Para aumentar a precisão, é possível otimizar hiperparâmetros, como o número de árvores ou a profundidade máxima, além de aplicar validação cruzada para avaliar a robustez do modelo. A importância das características é salva em um arquivo CSV para análise de sua influência nas previsões.



Previsão e visualização

Previsão de preços

A previsão é realizada com base nos dados mais recentes, estimando a variação percentual do preço em 24 horas, que é aplicada ao preço de mercado atual. Código de previsão:

async def get_price_forecast(pair: str, model, scaler) -> dict:
    df = prepare_features(pair, cot_data, tff_data)
    if df.empty:
        logger.warning(f"Нет данных для прогнозирования для {pair}")
        return {'pair': pair, 'forecast_price': None, 'confidence': 0.0}

    X_latest = df.drop(columns=['price_change_24h']).iloc[-1:]
    X_scaled = scaler.transform(X_latest)
    
    price_change_pred = model.predict(X_scaled)[0]
    confidence = model.score(X_scaled, df['price_change_24h'].iloc[-1:]) if len(df) > 1 else 0.6
    
    tick = mt5.symbol_info_tick(pair)
    if not tick:
        logger.warning(f"Нет текущих данных для {pair}")
        return {'pair': pair, 'forecast_price': None, 'confidence': 0.0}
    
    current_price = (tick.bid + tick.ask) / 2
    forecast_price = current_price * (1 + price_change_pred)
    
    forecast_df = pd.DataFrame([{
        'forecast_price': forecast_price,
        'confidence': confidence,
        'current_price': current_price,
        'price_change_pred': price_change_pred,
        'timestamp': datetime.now()
    }])
    output_path = os.path.join(OUTPUT_DIR, f"forecast_{pair}.csv")
    forecast_df.to_csv(output_path, index=False)
    logger.info(f"Прогноз для {pair} сохранен в {output_path}")
    
    visualize_forecast(pair, current_price, forecast_price, confidence)
    
    return {
        'pair': pair,
        'forecast_price': forecast_price,
        'confidence': max(0.0, min(1.0, confidence))
    }

Visualização dos resultados

Para análise, são criados gráficos do preço atual e do preço previsto, bem como das posições líquidas COT e TFF. Código de visualização:

def visualize_cot_data(cot_data: pd.DataFrame):
    if cot_data.empty or "Net_NonComm" not in cot_data.columns:
        logger.warning("Нет данных COT для визуализации")
        return

    plt.figure(figsize=(14, 8))
    for market in cot_data["Market_and_Exchange_Names"].unique():
        market_data = cot_data[cot_data["Market_and_Exchange_Names"] == market]
        plt.plot(range(len(market_data)), market_data["Net_NonComm"], label=market, alpha=0.7)
    
    plt.title("Чистые позиции Non-Commercial для валютных фьючерсов")
    plt.xlabel("Запись")
    plt.ylabel("Чистые позиции")
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    output_path = os.path.join(OUTPUT_DIR, "cot_net_positions.png")
    plt.savefig(output_path, dpi=150)
    plt.close()
    logger.info(f"График чистых позиций COT сохранен в {output_path}")

def visualize_tff_data(tff_data: pd.DataFrame):
    if tff_data.empty or "Net_Lev_Money" not in tff_data.columns:
        logger.warning("Нет данных TFF для визуализации")
        return

    plt.figure(figsize=(14, 8))
    for market in tff_data["Market_and_Exchange_Names"].unique():
        market_data = tff_data[tff_data["Market_and_Exchange_Names"] == market]
        plt.plot(range(len(market_data)), market_data["Net_Lev_Money"], label=market, alpha=0.7)

    plt.title("Чистые позиции Leveraged Funds для валютных фьючерсов (TFF)")
    plt.xlabel("Запись")
    plt.ylabel("Чистые позиции")
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    output_path = os.path.join(OUTPUT_DIR, "tff_net_positions.png")
    plt.savefig(output_path, dpi=150)
    plt.close()
    logger.info(f"График чистых позиций TFF сохранен в {output_path}")

def visualize_forecast(pair: str, current_price: float, forecast_price: float, confidence: float):
    plt.figure(figsize=(8, 5))
    plt.bar(['Current Price', 'Forecast Price'], [current_price, forecast_price], color=['blue', 'green'], alpha=0.7)
    plt.title(f"Прогноз цены через 24 часа для {pair} (Confidence: {confidence:.2f})")
    plt.ylabel('Цена')
    plt.tight_layout()
    output_path = os.path.join(OUTPUT_DIR, f"forecast_{pair}_plot.png")
    plt.savefig(output_path, dpi=150)
    plt.close()
    logger.info(f"График прогноза сохранен в {output_path}")

Os gráficos ajudam a avaliar visualmente o sentimento do mercado e a precisão das previsões, fornecendo aos traders uma representação clara dos dados.


Otimização e tratamento de erros

Cache de dados

Para minimizar requisições de rede, os dados COT e TFF são armazenados em cache em arquivos CSV, permitindo reutilizar dados atualizados e acelerar o processamento. O cache é verificado antes do carregamento de novos dados e, somente na ausência ou desatualização, uma nova requisição é realizada.

Verificação de dependências

Antes da execução, é verificada a presença das bibliotecas xlrd e openpyxl, necessárias para a leitura de arquivos Excel:

def check_dependencies():
    dependencies = ['xlrd', 'openpyxl']
    for dep in dependencies:
        if not importlib.util.find_spec(dep):
            logger.error(f"Missing dependency: {dep}. Install it using 'pip install {dep}'.")
            raise ImportError(f"Missing dependency: {dep}")

Tratamento de erros

O código inclui tratamento de exceções para todas as operações críticas: carregamento de dados, conexão com o MetaTrader 5 e treinamento do modelo. Isso garante a robustez do sistema contra falhas, por exemplo, na ausência de dados ou em problemas de conexão.



Aplicação prática

Teste do modelo

Para avaliar o modelo, recomenda-se o teste com dados históricos de 2024. As métricas R² e a importância das características são salvas em arquivos CSV para análise. O teste permite avaliar a precisão das previsões e identificar as características mais relevantes, como as posições líquidas de traders não comerciais ou a volatilidade.

Integração na estratégia de trading

As previsões podem ser usadas para negociação automática por meio da biblioteca MetaTrader 5. Por exemplo, quando a variação prevista do preço é superior a 0,5% e a confiança do modelo é alta (acima de 0,7), é possível abrir posições longas ou curtas. Código para negociação automática:

def execute_trade(pair: str, forecast_price: float, confidence: float):
    if not mt5.initialize():
        logger.error("MT5 initialization failed")
        return

    symbol_info = mt5.symbol_info(pair)
    if not symbol_info:
        logger.warning(f"Символ {pair} не найден")
        return

    current_price = (mt5.symbol_info_tick(pair).bid + mt5.symbol_info_tick(pair).ask) / 2
    if confidence > 0.7 and forecast_price > current_price * 1.005:
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": pair,
            "volume": 0.1,
            "type": mt5.ORDER_TYPE_BUY,
            "price": mt5.symbol_info_tick(pair).ask,
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        result = mt5.order_send(request)
        logger.info(f"Открыта длинная позиция для {pair}: {result}")
    elif confidence > 0.7 and forecast_price < current_price * 0.995:
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": pair,
            "volume": 0.1,
            "type": mt5.ORDER_TYPE_SELL,
            "price": mt5.symbol_info_tick(pair).bid,
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        result = mt5.order_send(request)
        logger.info(f"Открыта короткая позиция для {pair}: {result}")

Expansão de funcionalidades

Para melhorar o modelo, podem ser adicionados indicadores técnicos, como RSI ou MACD, para considerar sinais adicionais de mercado. Algoritmos alternativos, como gradient boosting (XGBoost) ou redes neurais, podem aumentar a precisão das previsões. A atualização dinâmica dos dados COT e TFF pode ser implementada por meio de um agendador de tarefas, por exemplo, a biblioteca schedule, para o recebimento automático de novos relatórios à medida que são publicados. Também é possível expandir a solução para a análise de outros ativos, como commodities ou índices, com a devida adaptação das características.

Implementação completa: CurrencyForecastModule

Para facilitar a integração, todas as funções são unificadas na classe CurrencyForecastModule, que encapsula o carregamento de dados, o treinamento do modelo, a previsão e a visualização:

class CurrencyForecastModule:
    def __init__(self, pairs: list, days_history: int = 30):
        self.pairs = pairs
        self.days_history = days_history
        self.models = {}
        self.scalers = {}
        self.forecasts = {}

        check_dependencies()
        if not mt5.initialize():
            logger.error("MT5 initialization failed. Ensure MT5 terminal is running and connected.")
            raise RuntimeError("MT5 initialization failed")

        self._validate_symbols()
        self._initialize_data()

    def _validate_symbols(self):
        available_symbols = [s.name for s in mt5.symbols_get()]
        logger.info(f"Доступные символы в MT5: {available_symbols}")
        self.symbol_mapping = {}
        for pair in self.pairs[:]:
            if pair in available_symbols:
                self.symbol_mapping[pair] = pair
            else:
                base_pair = pair.split('.')[0]
                if base_pair in available_symbols:
                    self.symbol_mapping[pair] = base_pair
                    logger.info(f"Сопоставлено: {pair} -> {base_pair}")
                else:
                    logger.warning(f"Символ {pair} не найден в MT5. Пропускается.")
                    self.pairs.remove(pair)

    def _initialize_data(self):
        logger.info("Инициализация данных для CurrencyForecastModule...")
        self.cot_data = load_cot_reports()
        self.tff_data = self._load_tff_reports()
        for pair in self.pairs:
            self._train_model(pair)

    def _load_tff_reports(self) -> pd.DataFrame:
        cache_path = os.path.join(OUTPUT_DIR, "tff_report.csv")
        if os.path.exists(cache_path):
            logger.info(f"Загрузка TFF данных из кэша: {cache_path}")
            return pd.read_csv(cache_path)

        try:
            response = requests.get(TFF_URL)
            response.raise_for_status()
            zip_path = os.path.join(OUTPUT_DIR, "tff_data.zip")
            with open(zip_path, "wb") as f:
                f.write(response.content)

            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
                zip_ref.extractall(OUTPUT_DIR)
                logger.info(f"Содержимое TFF архива: {zip_ref.namelist()}")

            excel_files = glob.glob(os.path.join(OUTPUT_DIR, "**", "*.xls*"), recursive=True)
            tff_files = [f for f in excel_files if 'FinFut' in f or 'fin' in f.lower()]
            if not tff_files:
                logger.error("Excel-файл TFF не найден в извлеченных файлах")
                return pd.DataFrame()

            excel_file = tff_files[0]
            logger.info(f"Обработка TFF файла: {excel_file}")

            relevant_columns = [
                "Market_and_Exchange_Names",
                "Lev_Money_Positions_Long_All",
                "Lev_Money_Positions_Short_All",
                "Asset_Mgr_Positions_Long_All",
                "Asset_Mgr_Positions_Short_All",
                "Open_Interest_All"
            ]
            tff_data = pd.read_excel(excel_file, engine='xlrd' if excel_file.endswith('.xls') else 'openpyxl')
            available_columns = [col for col in relevant_columns if col in tff_data.columns]
            if not available_columns:
                logger.error("Не найдены ожидаемые столбцы в данных TFF")
                return pd.DataFrame()

            tff_data = tff_data[available_columns]
            forex_markets = ["EURO FX", "JAPANESE YEN", "BRITISH POUND", "AUSTRALIAN DOLLAR",
                             "CANADIAN DOLLAR", "SWISS FRANC", "MEXICAN PESO", "NEW ZEALAND DOLLAR"]
            tff_data = tff_data[tff_data["Market_and_Exchange_Names"].str.contains('|'.join(forex_markets), case=False, na=False)]
            if "Lev_Money_Positions_Long_All" in tff_data.columns:
                tff_data["Net_Lev_Money"] = tff_data["Lev_Money_Positions_Long_All"] - tff_data["Lev_Money_Positions_Short_All"]
            if "Asset_Mgr_Positions_Long_All" in tff_data.columns:
                tff_data["Net_Asset_Mgr"] = tff_data["Asset_Mgr_Positions_Long_All"] - tff_data["Asset_Mgr_Positions_Short_All"]

            tff_data.to_csv(cache_path, index=False)
            logger.info(f"Отчет TFF сохранен в {cache_path}")
            visualize_tff_data(tff_data)
            return tff_data
        except Exception as e:
            logger.error(f"Ошибка при загрузке данных TFF: {e}")
            return pd.DataFrame()

    def _train_model(self, pair: str):
        df = prepare_features(pair, self.cot_data, self.tff_data)
        model, scaler = train_model(pair, df)
        if model and scaler:
            self.models[pair] = model
            self.scalers[pair] = scaler

    async def update_forecasts(self):
        logger.info("Обновление прогнозов цен...")
        for pair in self.pairs:
            forecast = await get_price_forecast(pair, self.models.get(pair), self.scalers.get(pair))
            logger.info(f"Прогноз для {pair}: Цена={forecast['forecast_price']}, Уверенность={forecast['confidence']:.2f}")

    def __del__(self):
        mt5.shutdown()

Essa classe fornece uma estrutura modular para carregamento de dados, treinamento de modelos e execução de previsões, simplificando a integração em sistemas de trading.

Como resultado, obtemos previsões e vários gráficos. Por exemplo, o gráfico das posições COT versus TFF:

Como resultado final da execução do código, obtemos a previsão de preços de um grupo de símbolos em 24 horas:

Embora, naturalmente, seja mais lógico utilizar como previsão exatamente o fechamento da noite de sexta-feira, pois assim isso estará alinhado com a periodicidade de publicação dos relatórios COT e TFF. 



Considerações finais

O uso de dados COT e TFF juntamente com preços históricos por meio da biblioteca MetaTrader 5 em Python permite criar modelos eficazes de previsão de preços, integráveis a estratégias de trading. A solução implementada automatiza o carregamento de dados, o treinamento do modelo e a execução de operações de trading, oferecendo aos traders uma base robusta para análise e tomada de decisões nos mercados financeiros. O código pode ser expandido com a adição de novos indicadores ou algoritmos, bem como com a automação da atualização de dados para manter as previsões sempre atualizadas.

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

Arquivos anexados |
COT_TFF_Predict.py (37.75 KB)
Últimos Comentários | Ir para discussão (1)
Aliaksandr Kazunka
Aliaksandr Kazunka | 9 jun. 2025 em 04:07
Você já analisou o significado dos sinais? Algo me diz que
Net_NonComm,0.0,0.0.
Net_Comm,0.0,0.0.
Net_Lev_Money,0.0,0.0.
Patrimônio líquido, 0,0,0,0
Net_NonComm_lag1,0.0,0.0
Net_NonComm_change,0.0,0.0
Net_Comm_lag1,0.0,0.0
Net_Comm_change,0.0,0.0
Net_Lev_Money_lag1,0.0,0.0
Mudança_de_dinheiro_da_rede,0,0,0
Net_Asset_Mgr_lag1,0.0,0.0
Mudança_de_Ativo_Líquido,0,0,0
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Mineração de dados dos balanços dos bancos centrais e obtenção de um panorama da liquidez global Mineração de dados dos balanços dos bancos centrais e obtenção de um panorama da liquidez global
A mineração de dados dos balanços dos bancos centrais permite obter um panorama da liquidez global do mercado Forex e das principais moedas. Nós unificamos dados do Fed, do BCE, do BOJ e do PBoC em um índice composto e aplicamos aprendizado de máquina para identificar padrões ocultos. Essa abordagem transforma um fluxo bruto de dados em sinais reais de trading, conectando a análise fundamentalista e a análise técnica.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Desenvolvendo um EA multimoeda (Parte 27): Componente para exibição de texto multilinha Desenvolvendo um EA multimoeda (Parte 27): Componente para exibição de texto multilinha
Quando surge a necessidade de exibir informações textuais no gráfico, podemos utilizar a função Comment(). Porém, suas possibilidades são bastante limitadas. Por isso, no âmbito deste artigo, criaremos nosso próprio componente, uma janela de diálogo em tela cheia, capaz de exibir texto multilinha com configurações flexíveis de fonte e suporte a rolagem.