”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 完整指南:在 Telegram 和 MetaTraderm Python 之间构建安全集成机器人

完整指南:在 Telegram 和 MetaTraderm Python 之间构建安全集成机器人

发布于2024-11-08
浏览:520

Guia Completo: Construindo um Bot Seguro de Integração entre Telegram e MetaTraderm Python

Bem-vindo! Este guia é projetado desenvolvedores intusiastas em Python que desejam criar um bot que monitora mensagens no Telegram e interage com o MetaTrader5 (MT5) para executar ordens de negociação com base nos sinais recebidos. Vamos guiá-lo por todo o processo, desde a configuração do ambiente até a compreensão detalhada de cada parte do código.


Índice

  1. Introdução
  2. Pré-requisitos
  3. Configurando o Ambiente
    • 1. Criar um Diretório para o Projeto
    • 2. Configurar um Ambiente Virtual (Opcional, mas Recomendado)
    • 3. Instalar Dependências Necessárias
  4. Criando o Arquivo .env
  5. Entendendo o Script Python
    • Imports e Variáveis de Ambiente
    • Configuração de Logging
    • Configuração das Contas MT5
    • Função de Reconexão com MT5
    • Função para Enviar Ordens para MT5
    • Processando Sinais do Telegram
    • Monitoramento de Conexões
    • Manipulação de Sinais para Encerramento Suave
    • Função Principal (main)
  6. Executando o Script
  7. Boas Práticas e Dicas
  8. Conclusão

Introdução

Neste projeto, você criará um bot em Python que realiza as seguintes tarefas:

  1. Monitora um Grupo no Telegram: O bot monitora mensagens em um grupo específico do Telegram em busca de sinais de negociação (por exemplo, "buy US30").

  2. Processa Sinais: Quando um sinal é detectado, o bot interpreta para determinar qual ativo negociar e se deve comprar ou vender.

  3. Interage com o MetaTrader5 (MT5): Com base no sinal, o bot envia ordens de negociação para sua conta MT5.

  4. Mantém Práticas de Segurança: Informações sensíveis, como chaves de API e senhas, são gerenciadas de forma segura usando variáveis de ambiente.

Ao final deste guia, você terá um bot funcional e seguro que automatiza ações de negociação com base em mensagens do Telegram.


Pré-requisitos

Antes de começar, certifique-se de ter o seguinte:

  1. Conhecimento Básico de Python: Familiaridade com a sintaxe do Python e conceitos como funções, loops e módulos.

  2. Python Instalado: Verifique se você tem o Python 3.7 ou posterior instalado em seu computador. Você pode baixá-lo do site oficial do Python.

  3. Conta no Telegram: Você precisará acessar a API do Telegram. Registre sua aplicação aqui para obter o API_ID e o API_HASH.

  4. Conta no MetaTrader5: Acesse uma conta MT5, incluindo credenciais de login e informações do servidor.

  5. Entendimento de Ambientes Virtuais: Embora opcional, usar ambientes virtuais é recomendado para gerenciar dependências.


Configurando o Ambiente

1. Criar um Diretório para o Projeto

Escolha um local em seu computador e crie um novo diretório para o seu projeto. Por exemplo:

mkdir telegram_mt5_bot
cd telegram_mt5_bot

2. Configurar um Ambiente Virtual (Opcional, mas Recomendado)

Um ambiente virtual isola as dependências do seu projeto das de outros projetos Python em seu sistema.

  • Criar um Ambiente Virtual:

    python -m venv venv
    

    Este comando cria um ambiente virtual chamado venv dentro do diretório do seu projeto.

  • Ativar o Ambiente Virtual:

    • No Windows:

      venv\Scripts\activate
      
    • No macOS e Linux:

      source venv/bin/activate
      

    Após a ativação, o nome do ambiente virtual aparecerá no prompt do terminal, indicando que as dependências instaladas agora serão isoladas para este projeto.

3. Instalar Dependências Necessárias

Com o ambiente virtual ativado, instale as bibliotecas necessárias usando o pip:

pip install telethon MetaTrader5 python-dotenv
  • telethon: Biblioteca para interagir com a API do Telegram.
  • MetaTrader5: Biblioteca para interagir com o MetaTrader5.
  • python-dotenv: Biblioteca para carregar variáveis de ambiente a partir de um arquivo .env.

Além disso, para facilitar o gerenciamento de pacotes, é recomendável criar um arquivo requirements.txt:

pip freeze > requirements.txt

Este arquivo registra todas as dependências do projeto, permitindo que outras pessoas (ou você mesmo em outra máquina) instalem facilmente as mesmas versões com:

pip install -r requirements.txt

Criando o Arquivo .env

Para gerenciar informações sensíveis de forma segura, usaremos um arquivo .env que armazenará variáveis de ambiente. Este arquivo não deve ser versionado ou compartilhado.

1. Criar o Arquivo .env

No diretório raiz do seu projeto (telegram_mt5_bot), crie um arquivo chamado .env e adicione as seguintes linhas, substituindo os valores pelos seus próprios:

# Credenciais do Telegram
TELEGRAM_API_ID=seu_api_id
TELEGRAM_API_HASH=seu_api_hash
TELEGRAM_PHONE_NUMBER=seu_numero_de_telefone
TELEGRAM_GROUP_USERNAME=@superus30

# Credenciais do MetaTrader5 (MT5)
MT5_LOGIN=seu_login_mt5
MT5_PASSWORD=sua_senha_mt5
MT5_SERVER=seu_servidor_mt5
MT5_PATH=C:\Caminho\Para\Seu\MetaTrader5\terminal64.exe

# Configuração de Logging
LOG_FILE=app.log

Notas Importantes:

  • TELEGRAM_API_ID e TELEGRAM_API_HASH: Obtidos ao registrar sua aplicação no Telegram.
  • TELEGRAM_PHONE_NUMBER: Número de telefone associado à sua conta do Telegram.
  • TELEGRAM_GROUP_USERNAME: Nome de usuário do grupo Telegram que o bot irá monitorar.
  • MT5_LOGIN, MT5_PASSWORD, MT5_SERVER: Informações da sua conta MT5.
  • MT5_PATH: Caminho para o executável do MetaTrader5 no seu sistema.

2. Atualizar o Arquivo .gitignore

Para garantir que o arquivo .env não seja versionado (especialmente se você estiver usando o Git), crie ou atualize o arquivo .gitignore no diretório raiz com o seguinte conteúdo:

# Arquivo de variáveis de ambiente
.env

# Diretório do ambiente virtual
venv/

Isso impede que informações sensíveis sejam acidentalmente compartilhadas em repositórios públicos ou privados.


Entendendo o Script Python

Agora, vamos criar o script Python que integrará o Telegram com o MetaTrader5. Este script realizará as seguintes funções:

  1. Carregar Variáveis de Ambiente: Utiliza o python-dotenv para carregar credenciais e configurações do arquivo .env.

  2. Configurar Logging: Define como e onde os logs serão armazenados, facilitando o monitoramento e a depuração.

  3. Configurar Contas MT5: Define as contas MT5 que serão utilizadas pelo bot.

  4. Funções de Reconexão e Envio de Ordens: Gerencia a conexão com o MT5 e envia ordens de negociação com base nos sinais recebidos.

  5. Processar Sinais do Telegram: Interpreta mensagens do Telegram para determinar as ações de negociação.

  6. Monitorar Conexões: Verifica periodicamente se as conexões com o MT5 estão ativas e tenta reconectar se necessário.

  7. Manipular Sinais de Encerramento: Garante que o bot encerre suas operações de forma suave ao receber sinais de interrupção.

  8. Função Principal (main): Orquestra todas as operações acima, iniciando o cliente Telegram e gerenciando as tarefas assíncronas.

Vamos explorar cada parte do código com detalhes.

1. Imports e Variáveis de Ambiente

Primeiro, importamos todas as bibliotecas necessárias e carregamos as variáveis de ambiente.

import os
import sys
import asyncio
import logging
import signal
import pkg_resources
from datetime import datetime
from dotenv import load_dotenv
from telethon import TelegramClient, events
import MetaTrader5 as mt5

Explicação dos Imports:

  • os: Interage com o sistema operacional, acessando variáveis de ambiente e caminhos de arquivos.
  • sys: Fornece acesso a variáveis e funções que interagem com o interpretador Python.
  • asyncio: Facilita a escrita de código assíncrono, permitindo que múltiplas tarefas sejam executadas concorrentemente.
  • logging: Gerencia o registro de mensagens de log para monitoramento e depuração.
  • signal: Permite a captura de sinais do sistema (como interrupções) para realizar ações específicas.
  • pkg_resources: Gerencia recursos de pacotes Python, aqui utilizado para listar pacotes instalados.
  • datetime: Trabalha com datas e horas.
  • dotenv: Carrega variáveis de ambiente de um arquivo .env.
  • Telethon: Biblioteca para interagir com a API do Telegram de forma assíncrona.
  • MetaTrader5: Biblioteca para interagir com o MetaTrader5.

Carregando Variáveis de Ambiente:

# Carrega variáveis de ambiente do arquivo .env
load_dotenv()

Esta linha lê o arquivo .env e carrega as variáveis de ambiente nele definidas, permitindo que sejam acessadas via os.getenv().

2. Configuração de Logging

O logging é essencial para monitorar o funcionamento do seu bot e depurar problemas. Vamos configurar o logging para registrar mensagens tanto no console quanto em um arquivo.

# Acessa as variáveis de ambiente para configuração
LOG_FILE = os.getenv('LOG_FILE', 'app.log')

# Configura o logging
logging.basicConfig(
    level=logging.INFO,  # Nível mínimo de severidade para registrar
    format='%(asctime)s - %(levelname)s - %(message)s',  # Formato das mensagens de log
    handlers=[
        logging.FileHandler(LOG_FILE),  # Registra logs em um arquivo
        logging.StreamHandler(sys.stdout)  # Exibe logs no console
    ]
)
logger = logging.getLogger(__name__)

Detalhes da Configuração:

  • level: Define o nível mínimo de mensagens que serão registradas. INFO inclui INFO, WARNING, ERROR e CRITICAL.
  • format: Define como cada mensagem de log será formatada, incluindo o timestamp, o nível de severidade e a mensagem.
  • handlers: Define onde as mensagens de log serão enviadas. Aqui, estão sendo enviadas para um arquivo (app.log) e para o console.

3. Configuração das Contas MT5

Definimos as contas MT5 que o bot utilizará para enviar ordens de negociação.

# Configurações das contas MT5
CONTAS_MT5 = [
    {
        "login": os.getenv('MT5_LOGIN'),
        "senha": os.getenv('MT5_PASSWORD'),
        "servidor": os.getenv('MT5_SERVER'),
        "us30": "US30.cash",
        "nas100": "US100.cash",
        "lote": 0.01
    }
]

contas_ativas = []  # Lista para armazenar contas ativas
shutdown_event = asyncio.Event()  # Evento para sinalizar o encerramento do programa

Explicação dos Campos:

  • login: Número de login da conta MT5.
  • senha: Senha da conta MT5.
  • servidor: Nome do servidor MT5.
  • us30 e nas100: Símbolos dos ativos que serão negociados.
  • lote: Volume padrão das ordens a serem enviadas.

4. Função de Reconexão com MT5

Esta função tenta reconectar à conta MT5 caso a conexão seja perdida.

async def reconectar_mt5(conta, max_tentativas=3):
    """
    Tenta reconectar à conta MT5 com um número máximo de tentativas.

    Args:
        conta (dict): Informações da conta MT5.
        max_tentativas (int): Número máximo de tentativas de reconexão.

    Returns:
        bool: True se a reconexão for bem-sucedida, False caso contrário.
    """
    for tentativa in range(max_tentativas):
        try:
            # Tenta inicializar a conexão com MT5
            if mt5.initialize(path=os.getenv('MT5_PATH'), login=int(conta['login']), server=conta['servidor'], password=conta['senha']):
                logger.info(f"Reconexão bem-sucedida para conta {conta['login']}")
                return True
            else:
                erro = mt5.last_error()
                logger.warning(f"Tentativa {tentativa   1} de reconexão falhou para conta {conta['login']}: {erro}")
        except Exception as e:
            logger.error(f"Erro durante a tentativa {tentativa   1} de reconexão para conta {conta['login']}: {e}")
        await asyncio.sleep(5)  # Espera 5 segundos antes de tentar novamente
    logger.error(f"Falha ao reconectar à conta {conta['login']} após {max_tentativas} tentativas")
    return False

Detalhes da Função:

  • Objetivo: Garantir que o bot mantenha a conexão com o MT5, tentando reconectar em caso de falha.
  • Parâmetros:
    • conta: Dicionário contendo as informações da conta MT5.
    • max_tentativas: Número máximo de tentativas de reconexão antes de desistir.
  • Processo:
    • Tenta inicializar a conexão com MT5 usando as credenciais fornecidas.
    • Se falhar, registra um aviso e aguarda 5 segundos antes de tentar novamente.
    • Após exceder o número máximo de tentativas, registra um erro e retorna False.

5. Função para Enviar Ordens para MT5

Esta função envia ordens de negociação para o MT5 com base nos sinais processados.

async def enviar_ordem(conta, simbolo, acao, lote):
    """
    Envia uma ordem de negociação para o MT5.

    Args:
        conta (dict): Informações da conta MT5.
        simbolo (str): Símbolo do ativo a ser negociado.
        acao (int): Tipo de ação (compra ou venda).
        lote (float): Volume da ordem.

    Returns:
        bool: True se a ordem for enviada com sucesso, False caso contrário.
    """
    # Tenta reconectar à conta MT5 antes de enviar a ordem
    if not await reconectar_mt5(conta):
        logger.error(f"Não foi possível enviar ordem para {conta['login']} devido a falha na reconexão")
        return False

    # Obtém informações do símbolo
    symbol_info = mt5.symbol_info(simbolo)
    if symbol_info is None:
        logger.error(f"Símbolo {simbolo} não encontrado")
        return False

    # Verifica se o símbolo está disponível para trading
    if not symbol_info.visible:
        logger.warning(f"Símbolo {simbolo} não está visível, tentando habilitá-lo")
        if not mt5.symbol_select(simbolo, True):
            logger.error(f"Falha ao selecionar o símbolo {simbolo}")
            return False

    # Obtém o tick atual do símbolo
    tick = mt5.symbol_info_tick(simbolo)
    if tick is None:
        logger.error(f"Não foi possível obter o tick para o símbolo {simbolo}")
        return False

    # Define o preço baseado na ação (compra ou venda)
    price = tick.ask if acao == mt5.ORDER_TYPE_BUY else tick.bid

    # Prepara a estrutura do pedido
    pedido = {
        "action": mt5.TRADE_ACTION_DEAL,  # Tipo de ação de negociação
        "symbol": simbolo,                # Símbolo do ativo
        "volume": float(lote),            # Volume da ordem
        "type": acao,                     # Tipo de ordem (compra ou venda)
        "price": price,                   # Preço da ordem
        "deviation": 20,                  # Desvio permitido no preço
        "magic": 234000,                   # Identificador único para a ordem
        "comment": "python script order",  # Comentário para a ordem
        "type_time": mt5.ORDER_TIME_GTC,   # Tipo de tempo da ordem (Good Till Cancelled)
        "type_filling": mt5.ORDER_FILLING_IOC,  # Tipo de preenchimento (Immediate or Cancel)
    }

    # Envia a ordem para o MT5
    resultado = mt5.order_send(pedido)
    if resultado.retcode != mt5.TRADE_RETCODE_DONE:
        logger.error(f"Erro ao enviar ordem para {conta['login']}: {resultado.comment}")
        logger.debug(f"Detalhes do pedido: {pedido}")
        logger.debug(f"Código de retorno: {resultado.retcode}")
        return False
    else:
        logger.info(f"Ordem enviada com sucesso para {conta['login']} com lote {lote}")
        logger.debug(f"Detalhes da ordem: {resultado}")
        return True

Detalhes da Função:

  • Objetivo: Enviar uma ordem de compra ou venda para o MT5 com base nos sinais recebidos.
  • Parâmetros:
    • conta: Informações da conta MT5.
    • simbolo: Símbolo do ativo a ser negociado (por exemplo, "US30.cash").
    • acao: Tipo de ação (mt5.ORDER_TYPE_BUY para compra ou mt5.ORDER_TYPE_SELL para venda).
    • lote: Volume da ordem (por exemplo, 0.01).
  • Processo:
    • Reconecta à conta MT5 se necessário.
    • Verifica se o símbolo está disponível e visível para negociação.
    • Obtém o preço atual do símbolo (ask para compra, bid para venda).
    • Prepara a estrutura do pedido com todos os parâmetros necessários.
    • Envia a ordem para o MT5 e verifica se foi bem-sucedida.

6. Processando Sinais do Telegram

Esta função interpreta mensagens recebidas no Telegram para determinar quais ações de negociação devem ser executadas.

async def processar_sinal(mensagem):
    """
    Processa uma mensagem recebida do Telegram para determinar a ação de negociação.

    Args:
        mensagem (str): Texto da mensagem recebida.

    """
    logger.info(f"Mensagem recebida do Telegram: {mensagem}")

    palavras = mensagem.lower().split()

    ativo = None
    acao = None

    # Verifica o ativo na mensagem
    if 'us30' in palavras:
        ativo = 'us30'
    elif 'nas100' in palavras:
        ativo = 'nas100'

    # Verifica a ação na mensagem
    if 'buy' in palavras:
        acao = mt5.ORDER_TYPE_BUY
    elif 'sell' in palavras:
        acao = mt5.ORDER_TYPE_SELL

    # Se nenhum ativo for reconhecido, encerra a função
    if not ativo:
        logger.info("Nenhum ativo reconhecido na mensagem.")
        return

    # Se nenhuma ação for reconhecida, encerra a função
    if acao is None:
        logger.info("Nenhuma ação (compra/venda) reconhecida na mensagem.")
        return

    acao_str = "COMPRA" se acao == mt5.ORDER_TYPE_BUY else "VENDA"
    logger.info(f"Interpretação: Ativo: {ativo.upper()}, Ação: {acao_str}")

    # Itera sobre todas as contas ativas para enviar a ordem
    for conta in contas_ativas[:]:  # Cria uma cópia da lista para iteração segura
        try:
            simbolo = conta.get(ativo)
            if not simbolo:
                logger.warning(f"Ativo {ativo} não configurado para a conta {conta['login']}. Pulando.")
                continue
            sucesso = await enviar_ordem(conta, simbolo, acao, conta['lote'])
            if not sucesso:
                logger.warning(f"Falha ao processar sinal para conta {conta['login']}. Removendo da lista de contas ativas.")
                contas_ativas.remove(conta)
        except Exception as e:
            logger.error(f"Erro ao processar sinal para conta {conta['login']}: {e}")
            logger.warning(f"Removendo conta {conta['login']} da lista de contas ativas devido a erro")
            contas_ativas.remove(conta)

Detalhes da Função:

  • Objetivo: Interpretar a mensagem recebida do Telegram para determinar qual ativo negociar e se deve comprar ou vender.
  • Parâmetros:
    • mensagem: Texto da mensagem recebida no Telegram.
  • Processo:
    • Converte a mensagem para letras minúsculas e divide em palavras.
    • Identifica o ativo mencionado (us30 ou nas100).
    • Identifica a ação (buy para compra ou sell para venda).
    • Itera sobre todas as contas ativas e envia a ordem correspondente.
    • Se a ordem falhar, remove a conta da lista de contas ativas para evitar tentativas futuras.

7. Monitoramento de Conexões

Esta função verifica periodicamente se as conexões com as contas MT5 estão ativas e tenta reconectar se necessário.

async def verificar_conexoes():
    """
    Verifica periodicamente se as contas MT5 estão conectadas e tenta reconectar se necessário.
    """
    while not shutdown_event.is_set():
        for conta in contas_ativas[:]:
            if shutdown_event.is_set():
                break
            if not await reconectar_mt5(conta):
                logger.warning(f"Conta {conta['login']} removida da lista de contas ativas devido a falha na conexão")
                contas_ativas.remove(conta)
        await asyncio.sleep(60)  # Verifica a cada 60 segundos

Detalhes da Função:

  • Objetivo: Garantir que todas as contas MT5 ativas mantenham uma conexão estável.
  • Processo:
    • Enquanto o evento de encerramento não for sinalizado, itera sobre todas as contas ativas.
    • Para cada conta, tenta reconectar.
    • Se a reconexão falhar após as tentativas definidas, remove a conta da lista de contas ativas.
    • Aguarda 60 segundos antes da próxima verificação.

8. Manipulação de Sinais para Encerramento Suave

Esta função lida com sinais de interrupção (como Ctrl C) para encerrar o programa de forma limpa.

def signal_handler(signum, frame):
    """
    Manipula sinais de interrupção para encerrar o programa de forma suave.

    Args:
        signum: Número do sinal.
        frame: Frame atual.
    """
    logger.info("Sinal de interrupção recebido. Encerrando o programa...")
    asyncio.get_event_loop().call_soon_threadsafe(shutdown_event.set)

Detalhes da Função:

  • Objetivo: Capturar sinais de interrupção e iniciar o processo de encerramento do bot de forma ordenada.
  • Processo:
    • Quando um sinal de interrupção é recebido (como SIGINT ou SIGTERM), registra uma mensagem de log.
    • Sinaliza o evento de encerramento para que todas as tarefas assíncronas possam finalizar adequadamente.

9. Função Principal (main)

Esta é a função central que coordena todas as operações do bot.

async def main():
    """
    Função principal que inicializa o bot e gerencia suas operações.
    """
    # Configurar o manipulador de sinais
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    # Inicializar contas MT5
    for conta in CONTAS_MT5:
        if await reconectar_mt5(conta):
            contas_ativas.append(conta)

    if not contas_ativas:
        logger.error("Nenhuma conta pôde ser inicializada. Encerrando o programa.")
        return

    logger.info(f"Programa continuando com {len(contas_ativas)} conta(s) ativa(s)")

    # Inicializar o cliente Telegram
    client = TelegramClient('session', os.getenv('TELEGRAM_API_ID'), os.getenv('TELEGRAM_API_HASH'))

    @client.on(events.NewMessage(chats=os.getenv('TELEGRAM_GROUP_USERNAME')))
    async def handler(event):
        """
        Manipulador de eventos para novas mensagens no Telegram.
        """
        if not shutdown_event.is_set():
            try:
                logger.info(f"Nova mensagem recebida do grupo {os.getenv('TELEGRAM_GROUP_USERNAME')}")
                await processar_sinal(event.message.text)
            except Exception as e:
                logger.error(f"Erro ao processar mensagem do Telegram: {e}")

    # Iniciar a tarefa de verificação de conexões
    verificar_task = asyncio.create_task(verificar_conexoes())

    try:
        await client.start(phone=os.getenv('TELEGRAM_PHONE_NUMBER'))
        logger.info("Bot Telegram iniciado. Aguardando mensagens...")
        await shutdown_event.wait()  # Aguarda até que o evento de encerramento seja sinalizado
    except Exception as e:
        logger.error(f"Erro no cliente Telegram: {e}")
    finally:
        await client.disconnect()
        verificar_task.cancel()
        for conta in contas_ativas:
            if mt5.shutdown():
                logger.info(f"MT5 desligado para a conta {conta['login']}")
            else:
                logger.warning(f"Falha ao desligar MT5 para a conta {conta['login']}")
        logger.info("Programa encerrado.")

Detalhes da Função:

  • Configuração de Sinais:

    • Associa os sinais de interrupção (SIGINT e SIGTERM) à função signal_handler para garantir um encerramento suave.
  • Inicialização das Contas MT5:

    • Itera sobre todas as contas definidas em CONTAS_MT5.
    • Tenta reconectar a cada conta e adiciona à lista de contas_ativas se bem-sucedido.
    • Se nenhuma conta puder ser inicializada, registra um erro e encerra o programa.
  • Inicialização do Cliente Telegram:

    • Cria uma instância do TelegramClient usando as credenciais do Telegram.
    • Define um manipulador de eventos (handler) que será chamado sempre que uma nova mensagem for recebida no grupo especificado.
    • O manipulador chama a função processar_sinal para interpretar e agir sobre a mensagem.
  • Iniciar Tarefas Assíncronas:

    • Cria uma tarefa assíncrona para verificar periodicamente as conexões MT5 (verificar_conexoes).
    • Inicia o cliente Telegram e aguarda até que o evento de encerramento seja sinalizado.
  • Encerramento:

    • Ao receber um sinal de encerramento, desconecta o cliente Telegram.
    • Cancela a tarefa de verificação de conexões.
    • Desliga o MT5 para todas as contas ativas.
    • Registra que o programa foi encerrado.

10. Executando o Script

Para executar o script, crie um arquivo chamado bot.py no diretório do seu projeto e cole o seguinte código completo, que integra todas as partes que discutimos:

import os
import sys
import asyncio
import logging
import signal
import pkg_resources
from datetime import datetime
from dotenv import load_dotenv
from telethon import TelegramClient, events
import MetaTrader5 as mt5

# Carrega variáveis de ambiente do arquivo .env
load_dotenv()

# Acessa as variáveis de ambiente para configuração
API_ID = os.getenv('TELEGRAM_API_ID')
API_HASH = os.getenv('TELEGRAM_API_HASH')
PHONE_NUMBER = os.getenv('TELEGRAM_PHONE_NUMBER')
GROUP_USERNAME = os.getenv('TELEGRAM_GROUP_USERNAME')

MT5_LOGIN = os.getenv('MT5_LOGIN')
MT5_PASSWORD = os.getenv('MT5_PASSWORD')
MT5_SERVER = os.getenv('MT5_SERVER')
MT5_PATH = os.getenv('MT5_PATH')

LOG_FILE = os.getenv('LOG_FILE', 'app.log')

# Configura logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_FILE),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# Configurações das contas MT5
CONTAS_MT5 = [
    {
        "login": MT5_LOGIN,
        "senha": MT5_PASSWORD,
        "servidor": MT5_SERVER,
        "us30": "US30.cash",
        "nas100": "US100.cash",
        "lote": 0.01
    }
]

contas_ativas = []
shutdown_event = asyncio.Event()

async def reconectar_mt5(conta, max_tentativas=3):
    """
    Tenta reconectar à conta MT5 com um número máximo de tentativas.

    Args:
        conta (dict): Informações da conta MT5.
        max_tentativas (int): Número máximo de tentativas de reconexão.

    Returns:
        bool: True se a reconexão for bem-sucedida, False caso contrário.
    """
    for tentativa in range(max_tentativas):
        try:
            # Tenta inicializar a conexão com MT5
            if mt5.initialize(path=MT5_PATH, login=int(conta['login']), server=conta['servidor'], password=conta['senha']):
                logger.info(f"Reconexão bem-sucedida para conta {conta['login']}")
                return True
            else:
                erro = mt5.last_error()
                logger.warning(f"Tentativa {tentativa   1} de reconexão falhou para conta {conta['login']}: {erro}")
        except Exception as e:
            logger.error(f"Erro durante a tentativa {tentativa   1} de reconexão para conta {conta['login']}: {e}")
        await asyncio.sleep(5)  # Espera 5 segundos antes de tentar novamente
    logger.error(f"Falha ao reconectar à conta {conta['login']} após {max_tentativas} tentativas")
    return False

async def enviar_ordem(conta, simbolo, acao, lote):
    """
    Envia uma ordem de negociação para o MT5.

    Args:
        conta (dict): Informações da conta MT5.
        simbolo (str): Símbolo do ativo a ser negociado.
        acao (int): Tipo de ação (compra ou venda).
        lote (float): Volume da ordem.

    Returns:
        bool: True se a ordem for enviada com sucesso, False caso contrário.
    """
    # Tenta reconectar à conta MT5 antes de enviar a ordem
    if not await reconectar_mt5(conta):
        logger.error(f"Não foi possível enviar ordem para {conta['login']} devido a falha na reconexão")
        return False

    # Obtém informações do símbolo
    symbol_info = mt5.symbol_info(simbolo)
    if symbol_info is None:
        logger.error(f"Símbolo {simbolo} não encontrado")
        return False

    # Verifica se o símbolo está disponível para trading
    if not symbol_info.visible:
        logger.warning(f"Símbolo {simbolo} não está visível, tentando habilitá-lo")
        if not mt5.symbol_select(simbolo, True):
            logger.error(f"Falha ao selecionar o símbolo {simbolo}")
            return False

    # Obtém o tick atual do símbolo
    tick = mt5.symbol_info_tick(simbolo)
    if tick is None:
        logger.error(f"Não foi possível obter o tick para o símbolo {simbolo}")
        return False

    # Define o preço baseado na ação (compra ou venda)
    price = tick.ask if acao == mt5.ORDER_TYPE_BUY else tick.bid

    # Prepara a estrutura do pedido
    pedido = {
        "action": mt5.TRADE_ACTION_DEAL,  # Tipo de ação de negociação
        "symbol": simbolo,                # Símbolo do ativo
        "volume": float(lote),            # Volume da ordem
        "type": acao,                     # Tipo de ordem (compra ou venda)
        "price": price,                   # Preço da ordem
        "deviation": 20,                  # Desvio permitido no preço
        "magic": 234000,                   # Identificador único para a ordem
        "comment": "python script order",  # Comentário para a ordem
        "type_time": mt5.ORDER_TIME_GTC,   # Tipo de tempo da ordem (Good Till Cancelled)
        "type_filling": mt5.ORDER_FILLING_IOC,  # Tipo de preenchimento (Immediate or Cancel)
    }

    # Envia a ordem para o MT5
    resultado = mt5.order_send(pedido)
    if resultado.retcode != mt5.TRADE_RETCODE_DONE:
        logger.error(f"Erro ao enviar ordem para {conta['login']}: {resultado.comment}")
        logger.debug(f"Detalhes do pedido: {pedido}")
        logger.debug(f"Código de retorno: {resultado.retcode}")
        return False
    else:
        logger.info(f"Ordem enviada com sucesso para {conta['login']} com lote {lote}")
        logger.debug(f"Detalhes da ordem: {resultado}")
        return True

async def processar_sinal(mensagem):
    """
    Processa uma mensagem recebida do Telegram para determinar a ação de negociação.

    Args:
        mensagem (str): Texto da mensagem recebida.
    """
    logger.info(f"Mensagem recebida do Telegram: {mensagem}")

    palavras = mensagem.lower().split()

    ativo = None
    acao = None

    # Verifica o ativo na mensagem
    if 'us30' in palavras:
        ativo = 'us30'
    elif 'nas100' in palavras:
        ativo = 'nas100'

    # Verifica a ação na mensagem
    if 'buy' in palavras:
        acao = mt5.ORDER_TYPE_BUY
    elif 'sell' in palavras:
        acao = mt5.ORDER_TYPE_SELL

    # Se nenhum ativo for reconhecido, encerra a função
    if not ativo:
        logger.info("Nenhum ativo reconhecido na mensagem.")
        return

    # Se nenhuma ação for reconhecida, encerra a função
    if acao is None:
        logger.info("Nenhuma ação (compra/venda) reconhecida na mensagem.")
        return

    acao_str = "COMPRA" se acao == mt5.ORDER_TYPE_BUY else "VENDA"
    logger.info(f"Interpretação: Ativo: {ativo.upper()}, Ação: {acao_str}")

    # Itera sobre todas as contas ativas para enviar a ordem
    for conta in contas_ativas[:]:  # Cria uma cópia da lista para iteração segura
        try:
            simbolo = conta.get(ativo)
            if not simbolo:
                logger.warning(f"Ativo {ativo} não configurado para a conta {conta['login']}. Pulando.")
                continue
            sucesso = await enviar_ordem(conta, simbolo, acao, conta['lote'])
            if not sucesso:
                logger.warning(f"Falha ao processar sinal para conta {conta['login']}. Removendo da lista de contas ativas.")
                contas_ativas.remove(conta)
        except Exception as e:
            logger.error(f"Erro ao processar sinal para conta {conta['login']}: {e}")
            logger.warning(f"Removendo conta {conta['login']} da lista de contas ativas devido a erro")
            contas_ativas.remove(conta)

async def verificar_conexoes():
    """
    Verifica periodicamente se as contas MT5 estão conectadas e tenta reconectar se necessário.
    """
    while not shutdown_event.is_set():
        for conta in contas_ativas[:]:
            if shutdown_event.is_set():
                break
            if not await reconectar_mt5(conta):
                logger.warning(f"Conta {conta['login']} removida da lista de contas ativas devido a falha na conexão")
                contas_ativas.remove(conta)
        await asyncio.sleep(60)  # Verifica a cada 60 segundos

def signal_handler(signum, frame):
    """
    Manipula sinais de interrupção para encerrar o programa de forma suave.

    Args:
        signum: Número do sinal.
        frame: Frame atual.
    """
    logger.info("Sinal de interrupção recebido. Encerrando o programa...")
    asyncio.get_event_loop().call_soon_threadsafe(shutdown_event.set)

async def main():
    """
    Função principal que inicializa o bot e gerencia suas operações.
    """
    # Configurar o manipulador de sinais
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    # Inicializar contas MT5
    for conta in CONTAS_MT5:
        if await reconectar_mt5(conta):
            contas_ativas.append(conta)

    if not contas_ativas:
        logger.error("Nenhuma conta pôde ser inicializada. Encerrando o programa.")
        return

    logger.info(f"Programa continuando com {len(contas_ativas)} conta(s) ativa(s)")

    # Inicializar o cliente Telegram
    client = TelegramClient('session', API_ID, API_HASH)

    @client.on(events.NewMessage(chats=GROUP_USERNAME))
    async def handler(event):
        """
        Manipulador de eventos para novas mensagens no Telegram.
        """
        if not shutdown_event.is_set():
            try:
                logger.info(f"Nova mensagem recebida do grupo {GROUP_USERNAME}")
                await processar_sinal(event.message.text)
            except Exception as e:
                logger.error(f"Erro ao processar mensagem do Telegram: {e}")

    # Iniciar a tarefa de verificação de conexões
    verificar_task = asyncio.create_task(verificar_conexoes())

    try:
        await client.start(phone=PHONE_NUMBER)
        logger.info("Bot Telegram iniciado. Aguardando mensagens...")
        await shutdown_event.wait()  # Aguarda até que o evento de encerramento seja sinalizado
    except Exception as e:
        logger.error(f"Erro no cliente Telegram: {e}")
    finally:
        await client.disconnect()
        verificar_task.cancel()
        for conta in contas_ativas:
            if mt5.shutdown():
                logger.info(f"MT5 desligado para a conta {conta['login']}")
            else:
                logger.warning(f"Falha ao desligar MT5 para a conta {conta['login']}")
        logger.info("Programa encerrado.")

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except Exception as e:
        logger.critical(f"Erro crítico no programa: {e}")
        sys.exit(1)

Explicação Completa do Código:

  1. Carregamento das Variáveis de Ambiente:

    • Usa load_dotenv() para carregar as variáveis definidas no arquivo .env.
    • Acessa essas variáveis usando os.getenv() para configurar o Telegram e MT5.
  2. Configuração de Logging:

    • Configura o logging para registrar mensagens tanto em um arquivo (app.log) quanto no console.
    • Define o nível mínimo de registro como INFO.
  3. Configuração das Contas MT5:

    • Define uma lista CONTAS_MT5 contendo dicionários com as informações necessárias para cada conta MT5.
    • Inicializa uma lista vazia contas_ativas para armazenar contas que estão conectadas.
  4. Função de Reconexão (reconectar_mt5):

    • Tenta reconectar à conta MT5 até um número máximo de tentativas.
    • Registra mensagens de sucesso ou falha no log.
  5. Função para Enviar Ordens (enviar_ordem):

    • Garante que a conexão com MT5 está ativa.
    • Verifica se o símbolo está disponível e visível.
    • Obtém o preço atual do símbolo (ask para compra, bid para venda).
    • Prepara a ordem com os parâmetros necessários e a envia para o MT5.
    • Registra o resultado da ordem no log.
  6. Função para Processar Sinais (processar_sinal):

    • Interpreta a mensagem recebida no Telegram para determinar qual ativo negociar e qual ação (compra ou venda) executar.
    • Itera sobre todas as contas ativas e envia a ordem correspondente.
    • Se uma ordem falhar, remove a conta da lista de contas ativas para evitar tentativas futuras.
  7. Função de Monitoramento de Conexões (verificar_conexoes):

    • Executa em um loop contínuo, verificando a conexão de cada conta MT5 ativa a cada 60 segundos.
    • Tenta reconectar se a conexão estiver perdida e remove contas que não puderam ser reconectadas.
  8. Manipulador de Sinais (signal_handler):

    • Captura sinais de interrupção (como Ctrl C) e sinaliza o encerramento do programa.
    • Garante que todas as tarefas assíncronas sejam finalizadas corretamente.
  9. Função Principal (main):

    • Configura os manipuladores de sinais.
    • Inicializa as contas MT5 e adiciona as contas bem-sucedidas à lista de contas ativas.
    • Inicializa o cliente Telegram e define um manipulador de eventos para novas mensagens.
    • Inicia a tarefa assíncrona de monitoramento de conexões.
    • Aguarda até que um sinal de encerramento seja recebido.
    • Ao encerrar, desconecta o cliente Telegram, cancela a tarefa de monitoramento e desliga o MT5 para todas as contas ativas.
  10. Execução do Script:

    • Verifica se o script está sendo executado diretamente.
    • Executa a função principal usando asyncio.run().
    • Captura quaisquer exceções críticas, registra no log e encerra o programa com um código de erro.

Executando o Script

Após configurar o ambiente e criar o arquivo bot.py, siga os passos abaixo para executar o bot.

1. Ativar o Ambiente Virtual

Se você configurou um ambiente virtual, ative-o:

  • No Windows:

    venv\Scripts\activate
    
  • No macOS e Linux:

    source venv/bin/activate
    

2. Executar o Script

No diretório do seu projeto, execute o seguinte comando:

python bot.py

O que esperar:

  • Logs no Console: Você verá mensagens informando sobre o status da conexão com o MT5 e do cliente Telegram.
  • Arquivo de Log: Todas as mensagens de log também serão gravadas no arquivo app.log (ou outro definido em LOG_FILE).

Interagindo com o Bot:

  • Envie mensagens no grupo do Telegram especificado (@superus30) com comandos como "buy US30" ou "sell NAS100".
  • O bot interpretará esses sinais e enviará ordens de negociação correspondentes para a conta MT5 configurada.

3. Encerrando o Bot

Para encerrar o bot de forma segura, pressione Ctrl C no terminal onde o script está sendo executado. Isso acionará o manipulador de sinais, que garantirá que todas as conexões sejam fechadas corretamente antes de encerrar o programa.


Boas Práticas e Dicas

  1. Manutenção da Segurança:

    • Nunca compartilhe seu arquivo .env ou exponha suas credenciais em repositórios públicos.
    • Use Ambientes Virtuais para isolar as dependências do projeto.
  2. Monitoramento e Logs:

    • Revise regularmente os logs (app.log) para identificar e resolver possíveis problemas.
    • Implementar Rotação de Logs: Para evitar que o arquivo de log cresça indefinidamente, considere implementar rotação usando bibliotecas como logging.handlers.
  3. Testes em Ambiente de Demonstração:

    • Antes de operar em contas reais, teste seu bot em ambientes de demonstração para garantir que tudo funcione conforme o esperado.
    • Verifique as Ordens: Assegure-se de que as ordens estão sendo enviadas corretamente e que o volume está adequado.
  4. Gerenciamento de Erros:

    • Tratamento Robusto de Exceções: Certifique-se de que todas as possíveis exceções sejam tratadas para evitar que o bot pare inesperadamente.
    • Alertas: Considere implementar alertas (por exemplo, enviando mensagens de log críticas para seu email) para notificá-lo sobre falhas graves.
  5. Atualizações de Dependências:

    • Mantenha suas bibliotecas atualizadas para aproveitar melhorias de segurança e correções de bugs.
    • Verifique as Documentações: Consulte as documentações oficiais das bibliotecas para entender mudanças ou atualizações.
  6. Escalabilidade:

    • Gerencie Múltiplas Contas: Se você pretende usar múltiplas contas MT5, expanda a configuração de CONTAS_MT5 conforme necessário.
    • Adicionar Mais Ativos: Atualize o script para suportar mais ativos além de "US30" e "NAS100" conforme sua estratégia de negociação.
  7. Documentação e Comentários:

    • Comente Seu Código: Mantenha comentários atualizados e relevantes para facilitar futuras manutenções.
    • Documente Configurações: Mantenha um documento com detalhes sobre como configurar e executar o bot.

Conclusão

Parabéns! Você criou um bot em Python que integra o Telegram com o MetaTrader5, capaz de automatizar ordens de negociação com base em sinais recebidos no Telegram. Ao seguir este guia, você não apenas implementou a funcionalidade desejada, mas também adotou práticas de segurança e organização de código que são fundamentais para projetos de software robustos.

Próximos Passos:

  • Expandir Funcionalidades: Adicione mais funcionalidades, como diferentes tipos de ordens, gerenciamento de riscos ou integração com outras plataformas.
  • Interface de Usuário: Considere criar uma interface gráfica ou um dashboard para monitorar o desempenho do bot.
  • Automatizar Deployments: Se desejar que o bot funcione continuamente, explore opções de deployment em servidores ou serviços de nuvem.

Recursos Adicionais:

  • Documentação do Telethon: Para aprofundar-se nas funcionalidades da biblioteca Telethon.
  • Documentação do MetaTrader5 Python: Para entender todas as possibilidades de interação com o MT5.
  • Python Logging Best Practices: Para aprimorar suas habilidades de logging.
  • Python Asyncio Documentation: Para dominar a programação assíncrona em Python.
  • Gerenciamento de Segredos em Python: Para aprender mais sobre como gerenciar configurações e segredos de forma segura.

? Fique Seguro e Boas Operações! ?

A segurança das suas credenciais é fundamental para proteger suas contas e dados. Sempre siga as melhores práticas para garantir a integridade e confidencialidade das suas informações.

版本声明 本文转载于:https://dev.to/vital7388/guia-completo-construindo-um-bot-seguro-de-integracao-entre-telegram-e-metatrader5-em-python-1lg1?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Cypress Web 测试深入指南
    Cypress Web 测试深入指南
    在 Web 开发领域,测试是确保 Web 应用程序的可靠性、性能和用户体验的关键步骤。随着应用程序变得越来越复杂,对有效、高效且易于使用的测试工具的需求变得更加明显。这就是现代端到端测试框架 Cypress 的闪光点。在本文中,我们将探讨什么是 Cypress Web 测试、为什么它在其他测试工具...
    编程 发布于2024-11-08
  • 如何在 PHP 中实现立即调用函数表达式 (IIFE)?
    如何在 PHP 中实现立即调用函数表达式 (IIFE)?
    PHP 的立即函数调用在 PHP 中,立即调用函数表达式 (IIFE) 在 PHP 7 中具有部分等价性,因为您可以在函数执行完后立即调用该函数。定义。但是,PHP 5.x 不支持此功能。对于 PHP 7,示例如下:(function() { echo "yes, this works i...
    编程 发布于2024-11-08
  • 如何在 JavaScript 中将字符串编码和解码为 Base64?
    如何在 JavaScript 中将字符串编码和解码为 Base64?
    在 JavaScript 中将字符串编码和解码为 Base64处理二进制数据时,通常需要将其编码为更方便的格式字符串表示。 Base64 是一种流行的编码方案,它将二进制数据表示为一串可打印字符。这使得在 Web 应用程序和其他场景中传输和存储数据变得更加容易。在 JavaScript 中将字符串编...
    编程 发布于2024-11-08
  • 为什么加载“GeoIP.dat”时 `Class.getResource()` 返回 Null 以及如何修复它?
    为什么加载“GeoIP.dat”时 `Class.getResource()` 返回 Null 以及如何修复它?
    URL资源加载失败:Class.getResource返回Null尝试使用getResource()方法检索资源的URL时,一些用户遇到该方法返回 null 的问题。当尝试加载“GeoIP.dat”文件时,会特别出现此问题。这里更深入地探讨了潜在原因和加载资源的替代方法。可能的原因getResour...
    编程 发布于2024-11-08
  • 了解 PHP 元编程:动态代码操作
    了解 PHP 元编程:动态代码操作
    PHP 元编程 是指编写可以生成或操作其他代码的代码。换句话说,它使程序能够在运行时检查、修改甚至生成新代码,从而具有更大的灵活性。它还可能涉及反射、动态代码生成和内省等技术。 在 PHP 中,元编程最常使用: Reflection API:允许在运行时检查类、方法、属性等。 魔法方法:特殊方法,如...
    编程 发布于2024-11-08
  • Python 日志记录
    Python 日志记录
    日志,记录。它是什么以及如何使用 Python 注册事件 使用日志记录创建日志使我们能够在代码中获得很多功能和灵活性。在这篇简短的文章中,我向您展示了基础知识和更多内容,以开始将其合并到您的项目中。 什么是日志记录?还有日志? 日志记录是监视事件的一种方式。这些事件通过描述性消息可见...
    编程 发布于2024-11-08
  • 字符串 - JavaScript 挑战
    字符串 - JavaScript 挑战
    您可以在 repo Github 上找到这篇文章中的所有代码。 字符串相关的挑战 是字母数字 /** * @param {any} char * @return {Boolean} */ function isAlphaNumeric(char) { ret...
    编程 发布于2024-11-08
  • 如何使用迁移在应用程序之间移动 Django 模型?
    如何使用迁移在应用程序之间移动 Django 模型?
    通过迁移在 Django 应用程序之间移动模型将模型组织到单独的 Django 应用程序结构中可以增强项目的可维护性和结构。虽然之前使用 South 的尝试可能被证明很困难,但 Django 1.7 的迁移系统提供了一个无缝的解决方案。过程使用迁移。SeparateDatabaseAndState ...
    编程 发布于2024-11-08
  • 人工智能中的分块 - 你缺少的秘密武器
    人工智能中的分块 - 你缺少的秘密武器
    大家好! ? 你知道是什么让我彻夜难眠吗?思考如何让我们的人工智能系统更智能、更高效。今天,我想谈谈一些听起来很基础但在构建强大的人工智能应用程序时至关重要的事情:分块 ✨. 到底什么是分块? ? 将分块视为人工智能将大量信息分解为可管理的小部分的方式。就像你不会尝试一次将整个披萨...
    编程 发布于2024-11-08
  • 如何使用Python高效地跨多个目录搜索文件?
    如何使用Python高效地跨多个目录搜索文件?
    在 Python 中查找文件当文件的位置在不同系统中不同时,在 Python 中查找文件可能是一个挑战。幸运的是,Python 提供了 os.walk 模块,使您能够轻松遍历目录并定位文件。os.walk 用于文件搜索os.walk 创建一个生成器迭代目录及其子目录的对象,每次迭代生成三个元组:ro...
    编程 发布于2024-11-08
  • 为什么会出现“getaddrinfo 失败”以及如何修复?
    为什么会出现“getaddrinfo 失败”以及如何修复?
    探索“getaddrinfo failed”错误名称解析过程中发生错误“getaddrinfo failed”,其中主机名被翻译转换为 IP 地址。它表明所提供的主机名的解析存在问题。深入研究错误上下文从提供的错误跟踪中,我们可以将原因追溯到套接字。 getaddrinfo(主机,端口)方法。当无法...
    编程 发布于2024-11-08
  • 如何将 React Hooks 集成到我现有的类组件中?
    如何将 React Hooks 集成到我现有的类组件中?
    将 React Hooks 集成到现有的 React 类组件中正如您所注意到的,React hooks 提供了另一种管理状态和逻辑的方法反应应用程序。然而,您可能希望逐步迁移现有的基于类的组件以接受钩子的优势。幸运的是,有一个解决方案可以解决这一挑战:高阶组件(HOC)。 HOC 提供了一种使用注入...
    编程 发布于2024-11-08
  • 如何使用 PHP 生成时区下拉列表?
    如何使用 PHP 生成时区下拉列表?
    用 PHP 生成时区下拉列表大多数网站需要一种方法来显示用户首选时区的日期。下面是可以使用的两个时区列表,以及一种使用 PHP 5 及更高版本中提供的内置 PHP DateTime 类的方法。使用硬编码时区列表此方法涉及手动创建时区列表,可以作为 HTML 元素中的值,也可以作为数组中的键。下面的...
    编程 发布于2024-11-08
  • 人工智能道德与监管:引领技术的未来
    人工智能道德与监管:引领技术的未来
    人工智能道德与监管:引领技术的未来 人工智能 (AI) 已迅速成为现代技术的基石,彻底改变了从医疗保健到金融等行业。然而,这种权力也伴随着重大的责任。随着人工智能系统越来越融入我们的日常生活,其使用的伦理影响引起了越来越多的关注。本文深入探讨了人工智能伦理与监管的关键交叉点,探讨了指导人工智能技术负...
    编程 发布于2024-11-08
  • 通过您的网站一键式付款:使用 Google Pay 让付款更轻松
    通过您的网站一键式付款:使用 Google Pay 让付款更轻松
    Integrating Google Pay with Your Website: A Step-by-Step Guide If you’re looking to integrate Google Pay into your website for seamless trans...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3