Criando Seu Próprio Conector
O mecanismo de mensagens é uma camada lógica interna da arquitetura StockSharp, que fornece a interação entre vários elementos da plataforma usando um protocolo padrão.
Existem duas classes principais:
- Message - uma mensagem que carrega informações.
- AsyncMessageAdapter - um adaptador de mensagens (=conversor).
Uma mensagem atua como um agente que transmite informações. As mensagens têm seu próprio tipo MessageTypes. Cada tipo de mensagem corresponde a uma classe específica. Por sua vez, todas as classes de mensagens herdam da classe abstrata Message, que dota os descendentes de propriedades como o tipo de mensagem Message.Type e Message.LocalTime - a hora local de criação/recebimento da mensagem.
As mensagens podem ser de entrada e de saída:
- Mensagens de entrada - mensagens que são enviadas para um sistema externo. Geralmente, são comandos gerados pelo programa, por exemplo, a mensagem ConnectMessage - um comando que solicita uma conexão com o servidor.
- Mensagens de saída - mensagens provenientes de um sistema externo. São mensagens que transmitem informações sobre dados de mercado, transações, portfólios, eventos de conexão, etc. Por exemplo, a mensagem QuoteChangeMessage transmite informações sobre mudanças no livro de ofertas.
O adaptador de mensagens desempenha o papel de intermediário entre o sistema de negociação e o programa. Para cada tipo de conector, existe uma classe adaptadora separada que herda da classe abstrata AsyncMessageAdapter.
O adaptador executa duas funções principais:
- Converte mensagens de entrada em comandos de um sistema de negociação específico.
- Converte informações recebidas do sistema de negociação (conexão, dados de mercado, transações, etc.) em mensagens de saída.
Abaixo está uma descrição do processo de criação de seu próprio adaptador para o Coinbase (todos os conectores com código-fonte estão disponíveis no repositório StockSharp e são fornecidos como um tutorial).
Exemplo de Criação de um Adaptador de Mensagens Coinbase
1. Criando uma Classe de Adaptador
Primeiro, criamos a classe adaptadora de mensagens CoinbaseMessageAdapter, herdada da classe abstrata AsyncMessageAdapter.
public partial class CoinbaseMessageAdapter : AsyncMessageAdapter
{
private Authenticator _authenticator;
private HttpClient _restClient;
private SocketClient _socketClient;
// Outros campos e propriedades do adaptador
}
2. Construtor do Adaptador
No construtor do adaptador, você precisa executar as seguintes ações:
Passar o gerador de ID de transação que será usado para criar IDs de mensagem.
Especificar os tipos de mensagem suportados usando os métodos:
- AddMarketDataSupport - suporte para mensagens de assinatura de dados de mercado.
- AddTransactionalSupport - suporte para mensagens transacionais.
- Especificar os tipos específicos de dados de mercado suportados pelo adaptador usando o método AddSupportedMarketDataType.
public CoinbaseMessageAdapter(IdGenerator transactionIdGenerator)
: base(transactionIdGenerator)
{
HeartbeatInterval = TimeSpan.FromSeconds(5);
// Adicionar suporte a dados de mercado e transações
this.AddMarketDataSupport();
this.AddTransactionalSupport();
// Remover tipos de mensagem não suportados
this.RemoveSupportedMessage(MessageTypes.Portfolio);
this.RemoveSupportedMessage(MessageTypes.OrderGroupCancel);
// Adicionar tipos de dados de mercado suportados
this.AddSupportedMarketDataType(DataType.Ticks);
this.AddSupportedMarketDataType(DataType.MarketDepth);
this.AddSupportedMarketDataType(DataType.Level1);
this.AddSupportedMarketDataType(DataType.CandleTimeFrame);
}
3. Conectando e Desconectando o Adaptador
Para conectar o adaptador ao sistema de negociação, o método AsyncMessageAdapter.ConnectAsync é chamado. A ele é passada a mensagem de entrada ConnectMessage. Se a conexão for bem-sucedida, o adaptador envia uma mensagem de saída ConnectMessage.
public override async ValueTask ConnectAsync(ConnectMessage connectMsg, CancellationToken cancellationToken)
{
// Verificar a presença de chaves para o modo transacional
if (this.IsTransactional())
{
if (Key.IsEmpty())
throw new InvalidOperationException(LocalizedStrings.KeyNotSpecified);
if (Secret.IsEmpty())
throw new InvalidOperationException(LocalizedStrings.SecretNotSpecified);
}
// Inicializar autenticador
_authenticator = new(this.IsTransactional(), Key, Secret, Passphrase);
// Verificar que os clientes ainda não foram criados
if (_restClient != null)
throw new InvalidOperationException(LocalizedStrings.NotDisconnectPrevTime);
if (_socketClient != null)
throw new InvalidOperationException(LocalizedStrings.NotDisconnectPrevTime);
// Criar cliente REST
_restClient = new(_authenticator) { Parent = this };
// Criar e configurar cliente WebSocket
_socketClient = new(_authenticator, ReConnectionSettings.ReAttemptCount) { Parent = this };
SubscribePusherClient();
// Conectar cliente WebSocket
await _socketClient.Connect(cancellationToken);
// Enviar mensagem de conexão bem-sucedida
SendOutMessage(new ConnectMessage());
}
Para desconectar o adaptador do sistema de negociação, o método AsyncMessageAdapter.DisconnectAsync é chamado. Se a desconexão for bem-sucedida, o adaptador envia uma mensagem de saída DisconnectMessage.
public override ValueTask DisconnectAsync(DisconnectMessage disconnectMsg, CancellationToken cancellationToken)
{
// Verificar que os clientes foram criados
if (_restClient == null)
throw new InvalidOperationException(LocalizedStrings.ConnectionNotOk);
if (_socketClient == null)
throw new InvalidOperationException(LocalizedStrings.ConnectionNotOk);
// Liberar recursos do cliente REST
_restClient.Dispose();
_restClient = null;
// Desconectar cliente WebSocket
_socketClient.Disconnect();
// Enviar mensagem de desconexão
SendOutDisconnectMessage(true);
return default;
}
Além disso, o adaptador fornece o método AsyncMessageAdapter.ResetAsync para redefinir o estado, que fecha a conexão e retorna o adaptador ao seu estado inicial.
public override ValueTask ResetAsync(ResetMessage resetMsg, CancellationToken cancellationToken)
{
// Liberar recursos do cliente REST
if (_restClient != null)
{
try
{
_restClient.Dispose();
}
catch (Exception ex)
{
SendOutError(ex);
}
_restClient = null;
}
// Desconectar e limpar cliente WebSocket
if (_socketClient != null)
{
try
{
UnsubscribePusherClient();
_socketClient.Disconnect();
}
catch (Exception ex)
{
SendOutError(ex);
}
_socketClient = null;
}
// Liberar recursos do autenticador
if (_authenticator != null)
{
try
{
_authenticator.Dispose();
}
catch (Exception ex)
{
SendOutError(ex);
}
_authenticator = null;
}
// Limpar dados adicionais
_candlesTransIds.Clear();
// Enviar mensagem de redefinição
SendOutMessage(new ResetMessage());
return default;
}
Após a Conclusão do Desenvolvimento
Assim que o conector estiver implementado, existem duas opções para usá-lo:
Publicá-lo na StockSharp Store como um produto pago ou gratuito. Nesse caso, os usuários instalam o conector automaticamente através do Installer.
Para uso pessoal, copie o arquivo .dll do conector compilado para a pasta de sua aplicação (ou qualquer produto StockSharp). Na inicialização, a aplicação verifica o diretório atual em busca de adaptadores usando os seguintes critérios:
- Somente arquivos com a extensão .dll cujos nomes comecem com
StockSharp.são considerados. - Cada arquivo restante é verificado para garantir que seja um assembly .NET válido.
- O assembly é carregado e todos os tipos que implementam
IMessageAdaptersão coletados. - Quaisquer erros encontrados durante a verificação ou o carregamento são gravados no log e não interrompem a busca. Se o carregamento falhar, abra a janela de log da aplicação ou o arquivo de log para ver os detalhes do erro.
- Somente arquivos com a extensão .dll cujos nomes comecem com
Este documento descreve os princípios gerais de funcionamento do adaptador, sua criação e o gerenciamento da conexão com o sistema de negociação. Os documentos a seguir serão dedicados à implementação da funcionalidade do adaptador: