Melhor linguagem de programação para sistemas de negociação algorítmica?

Autora:Bem-estar, Criado: 2019-02-12 10:33:36, Atualizado:

Uma das perguntas mais frequentes que recebo no mailbag é Qual é a melhor linguagem de programação para negociação algorítmica?. A resposta curta é que não existe uma linguagem melhor. Parâmetros de estratégia, desempenho, modularidade, desenvolvimento, resiliência e custo devem ser considerados.

Em primeiro lugar, serão considerados os principais componentes de um sistema de negociação algorítmica, tais como as ferramentas de pesquisa, otimizador de carteira, gerenciador de risco e motor de execução. Posteriormente, diferentes estratégias de negociação serão examinadas e como elas afetam o design do sistema. Em particular, a frequência de negociação e o volume provável de negociação serão discutidos.

Uma vez selecionada a estratégia de negociação, é necessário arquitetar todo o sistema. Isso inclui a escolha de hardware, o sistema operacional e a resiliência do sistema contra eventos raros e potencialmente catastróficos. Enquanto a arquitetura está sendo considerada, deve ser dada a devida atenção ao desempenho - tanto às ferramentas de pesquisa quanto ao ambiente de execução ao vivo.

O que o sistema comercial está tentando fazer?

Antes de decidir sobre a melhor linguagem para escrever um sistema de negociação automatizado, é necessário definir os requisitos. O sistema será puramente baseado em execução? O sistema exigirá um módulo de gerenciamento de risco ou construção de carteira? O sistema exigirá um backtester de alto desempenho? Para a maioria das estratégias, o sistema de negociação pode ser dividido em duas categorias: Pesquisa e geração de sinal.

A pesquisa está preocupada com a avaliação do desempenho de uma estratégia sobre dados históricos. O processo de avaliação de uma estratégia de negociação sobre dados de mercado anteriores é conhecido como backtesting. O tamanho dos dados e a complexidade algorítmica terão um grande impacto na intensidade computacional do backtester.

A geração de sinais está relacionada com a geração de um conjunto de sinais de negociação a partir de um algoritmo e o envio de tais ordens para o mercado, geralmente através de uma corretora.

Tipo, frequência e volume da estratégia

O tipo de estratégia algorítmica empregada terá um impacto substancial no projeto do sistema. Será necessário considerar os mercados negociados, a conectividade com fornecedores externos de dados, a frequência e o volume da estratégia, o compromisso entre a facilidade de desenvolvimento e a otimização do desempenho, bem como qualquer hardware personalizado, incluindo servidores personalizados co-locados, GPUs ou FPGAs que possam ser necessários.

As escolhas tecnológicas para uma estratégia de ações dos EUA de baixa frequência serão muito diferentes das de uma estratégia de arbitragem estatística de alta frequência de negociação no mercado de futuros.

É necessário considerar a conectividade com o fornecedor, a estrutura de quaisquer APIs, a atualidade dos dados, os requisitos de armazenamento e a resiliência diante de um fornecedor desconectado. Também é sábio possuir acesso rápido a vários fornecedores! Vários instrumentos têm suas próprias peculiaridades de armazenamento, exemplos dos quais incluem símbolos de ticker múltiplos para ações e datas de expiração para futuros (para não mencionar qualquer dado específico de OTC).

A frequência da estratégia é provavelmente um dos principais fatores que determinam como a pilha de tecnologia será definida.

Uma estratégia que exceda as barras secundárias (ou seja, dados de tick) leva a um projeto orientado ao desempenho como o requisito principal.

Para processar os grandes volumes de dados necessários para aplicações HFT, um backtester e sistema de execução amplamente otimizados devem ser usados. C / C ++ (possivelmente com algum assembler) é provavelmente o candidato de linguagem mais forte.

Sistemas de investigação

Os sistemas de pesquisa geralmente envolvem uma mistura de desenvolvimento interativo e scripting automatizado. O primeiro geralmente ocorre dentro de um IDE como Visual Studio, MatLab ou R Studio. Este último envolve extensos cálculos numéricos em vários parâmetros e pontos de dados. Isso leva a uma escolha de linguagem que fornece um ambiente direto para testar código, mas também fornece desempenho suficiente para avaliar estratégias em várias dimensões de parâmetros.

IDEs típicas neste espaço incluem Microsoft Visual C ++ / C #, que contém extensos utilitários de depuração, capacidades de conclusão de código (via Intellisense) e visões gerais diretas de toda a pilha de projetos (via o banco de dados ORM, LINQ); MatLab, que é projetado para extensas operações de álgebra linear numérica e vetoriais, mas de maneira interativa; R Studio, que envolve o console de linguagem Rstatistical em um IDE completo; Eclipse IDE para Java Linux e C ++; e IDEs semi-proprietários como Enthought Canopy para Python, que incluem bibliotecas de análise de dados como NumPy, SciPy, scikit-learn e pandas em um único ambiente interativo (console).

Para backtesting numérico, todas as linguagens acima são adequadas, embora não seja necessário utilizar uma GUI/IDE, pois o código será executado em segundo plano. A principal consideração nesta fase é a da velocidade de execução. Uma linguagem compilada (como C++) é muitas vezes útil se as dimensões dos parâmetros de backtesting forem grandes. Lembre-se de que é necessário ter cuidado com esses sistemas se esse for o caso!

As linguagens interpretadas, como Python, muitas vezes fazem uso de bibliotecas de alto desempenho, como NumPy / pandas, para a etapa de backtesting, a fim de manter um grau razoável de competitividade com equivalentes compilados.

Construção de carteira e gestão de riscos

A construção de portfólio e os componentes de gerenciamento de risco são muitas vezes negligenciados pelos traders algoritmicos de varejo. Isso é quase sempre um erro. Essas ferramentas fornecem o mecanismo pelo qual o capital será preservado. Eles não apenas tentam aliviar o número de apostas de risco, mas também minimizam o deslocamento dos próprios negócios, reduzindo os custos de transação.

As versões sofisticadas desses componentes podem ter um efeito significativo na qualidade e consistência da lucratividade. É simples criar uma estratégia estável, pois o mecanismo de construção de carteira e o gerenciador de risco podem ser facilmente modificados para lidar com vários sistemas.

A função do sistema de construção de carteira é tomar um conjunto de operações desejadas e produzir o conjunto de operações reais que minimizam o deslocamento, mantêm as exposições a vários fatores (como setores, classes de ativos, volatilidade, etc.) e otimizam a alocação de capital para várias estratégias de uma carteira.

A construção de portfólio geralmente se reduz a um problema de álgebra linear (como uma fatorização de matriz) e, portanto, o desempenho é altamente dependente da eficácia da implementação de álgebra linear numérica disponível. As bibliotecas comuns incluem uBLAS, LAPACK e NAG para C ++. O MatLab também possui operações de matriz amplamente otimizadas. O Python utiliza NumPy / SciPy para tais cálculos.

A gestão de risco é outra parte extremamente importante de um sistema de negociação algorítmica. O risco pode vir de muitas formas: aumento da volatilidade (embora isso possa ser visto como desejável para certas estratégias!), aumento das correlações entre as classes de ativos, inadimplência da contraparte, interrupções de servidores, eventos de cisne negro e bugs não detectados no código de negociação, para citar alguns.

Os componentes de gerenciamento de risco tentam antecipar os efeitos da volatilidade excessiva e da correlação entre as classes de ativos e seus efeitos subsequentes sobre o capital de negociação. Muitas vezes, isso se reduz a um conjunto de cálculos estatísticos, como testes de estresse de Monte Carlo. Isso é muito semelhante às necessidades computacionais de um mecanismo de preços de derivados e, como tal, estará vinculado à CPU. Essas simulações são altamente paralelizáveis (veja abaixo) e, até certo ponto, é possível "lançar hardware no problema".

Sistemas de execução

O trabalho do sistema de execução é receber sinais de negociação filtrados dos componentes de construção de carteira e gerenciamento de risco e enviá-los para uma corretora ou outros meios de acesso ao mercado. Para a maioria das estratégias de negociação algorítmica de varejo, isso envolve uma conexão API ou FIX com uma corretora, como Interactive Brokers. As considerações primárias ao decidir sobre uma linguagem incluem a qualidade da API, a disponibilidade de linguagem para uma API, a frequência de execução e o deslizamento antecipado.

A qualidade da API refere-se a quão bem documentada ela é, que tipo de desempenho ela fornece, se precisa de software autônomo para ser acessado ou se um gateway pode ser estabelecido de forma sem cabeça (ou seja, sem GUI). No caso dos Interactive Brokers, a ferramenta Trader WorkStation precisa ser executada em um ambiente GUI para acessar sua API.

A maioria das APIs fornecerá uma interface C ++ e / ou Java. Normalmente cabe à comunidade desenvolver envelopes específicos de linguagem para C #, Python, R, Excel e MatLab. Observe que, com cada plugin adicional utilizado (especialmente envelopes API), há espaço para bugs se infiltrar no sistema. Sempre teste plugins desse tipo e certifique-se de que eles sejam mantidos ativamente.

A frequência de execução é de extrema importância no algoritmo de execução. Observe que centenas de ordens podem ser enviadas a cada minuto e, como tal, o desempenho é crítico.

As linguagens de tipo estático (ver abaixo) como C ++ / Java são geralmente ideais para execução, mas há um trade-off em tempo de desenvolvimento, teste e facilidade de manutenção.

Processo de planejamento e desenvolvimento arquitetônico

Os componentes de um sistema de negociação, seus requisitos de frequência e volume foram discutidos acima, mas a infraestrutura do sistema ainda não foi coberta. Aqueles que atuam como comerciantes de varejo ou trabalham em um pequeno fundo provavelmente estarão "usando muitos chapéus". Será necessário cobrir o modelo alfa, os parâmetros de gerenciamento de risco e execução, e também a implementação final do sistema. Antes de aprofundar em linguagens específicas, será discutido o projeto de uma arquitetura de sistema ideal.

Separação das preocupações

Uma das decisões mais importantes que devem ser tomadas desde o início é como separar as preocupações de um sistema de negociação.

Ao expor interfaces em cada um dos componentes, é fácil trocar partes do sistema por outras versões que auxiliem o desempenho, a confiabilidade ou a manutenção, sem modificar nenhum código de dependência externa. Esta é a "melhor prática" para tais sistemas. Para estratégias em frequências mais baixas, tais práticas são aconselhadas.

A criação de um mapa de componentes de um sistema de negociação algorítmica vale um artigo em si. No entanto, uma abordagem ideal é garantir que haja componentes separados para as entradas de dados de mercado históricos e em tempo real, armazenamento de dados, API de acesso a dados, backtester, parâmetros de estratégia, construção de portfólio, gerenciamento de riscos e sistemas de execução automatizados.

Por exemplo, se o armazenamento de dados que está sendo usado estiver atualmente com desempenho inferior, mesmo em níveis significativos de otimização, ele pode ser substituído com reescrituras mínimas na API de ingestão de dados ou acesso a dados.

Outro benefício dos componentes separados é que permite que uma variedade de linguagens de programação sejam usadas no sistema geral. Não há necessidade de se restringir a uma única linguagem se o método de comunicação dos componentes for independente da linguagem.

Como exemplo concreto, considere o caso de um sistema de backtesting sendo escrito em C ++ para o desempenho de number crunching, enquanto o gerenciador de portfólio e os sistemas de execução são escritos em Python usando SciPy e IBPy.

Considerações de desempenho

O desempenho é uma consideração significativa para a maioria das estratégias de negociação. Para estratégias de frequência mais alta, é o fator mais importante. O desempenho abrange uma ampla gama de questões, como velocidade de execução algorítmica, latência da rede, largura de banda, dados I / O, concurência / paralelismo e escalonamento. Cada uma dessas áreas é coberta individualmente por grandes livros didáticos, portanto, este artigo apenas raspará a superfície de cada tópico.

A sabedoria predominante, conforme declarado por Donald Knuth, um dos pais da Ciência da Computação, é que a otimização prematura é a raiz de todo mal. Isso é quase sempre o caso - exceto quando se constrói um algoritmo de negociação de alta frequência!

As ferramentas de perfil são usadas para determinar onde surgem gargalos. Os perfis podem ser feitos para todos os fatores listados acima, seja em um ambiente MS Windows ou Linux. Existem muitas ferramentas de sistema operacional e linguagem disponíveis para isso, bem como utilitários de terceiros.

C++, Java, Python, R e MatLab contêm bibliotecas de alto desempenho (como parte de seu padrão ou externamente) para estrutura de dados básica e trabalho algorítmico.

Uma exceção é se uma arquitetura de hardware altamente personalizada for necessária e um algoritmo estiver fazendo extensivo uso de extensões proprietárias (como caches personalizados).

A latência é frequentemente uma questão do sistema de execução, pois as ferramentas de pesquisa geralmente estão localizadas na mesma máquina. Para o primeiro, a latência pode ocorrer em vários pontos ao longo do caminho de execução. Os bancos de dados devem ser consultados (latência de disco / rede), os sinais devem ser gerados (sistema operacional, latência de mensagens do kernel), os sinais comerciais enviados (latência do NIC) e as ordens processadas (latência interna dos sistemas de troca).

Para operações de frequência mais alta, é necessário se familiarizar intimamente com a otimização do núcleo, bem como com a otimização da transmissão de rede.

O cache é muito útil no kit de ferramentas de um desenvolvedor de negociação quantitativa. O cache refere-se ao conceito de armazenar dados frequentemente acessados de uma forma que permite um acesso de maior desempenho, às custas da estalenidade potencial dos dados. Um caso de uso comum ocorre no desenvolvimento web quando se tomam dados de um banco de dados relacional com suporte de disco e são colocados na memória.

Para situações de negociação, o cache pode ser extremamente benéfico. Por exemplo, o estado atual de uma carteira de estratégia pode ser armazenado em um cache até que seja reequilibrado, de modo que a lista não precise ser regenerada em cada ciclo do algoritmo de negociação.

No entanto, o cache não está isento de seus próprios problemas. A regeneração de dados do cache de uma só vez, devido à natureza volátil do armazenamento do cache, pode colocar uma demanda significativa na infraestrutura. Outro problema é a pilha de cães, onde várias gerações de uma nova cópia do cache são realizadas sob carga extremamente alta, o que leva à falha da cascata.

A alocação de memória dinâmica é uma operação cara na execução de software. Assim, é imperativo que as aplicações de comércio de alto desempenho estejam bem cientes de como a memória está sendo alocada e desalocada durante o fluxo do programa.

A coleta de lixo é extremamente útil durante o desenvolvimento, pois reduz erros e ajuda a legibilidade. No entanto, muitas vezes é sub-óptima para certas estratégias de negociação de alta frequência. A coleta de lixo personalizada é frequentemente desejada para esses casos.

O C++ não fornece um coletor de lixo nativo e, portanto, é necessário lidar com toda a alocação / desalocação de memória como parte da implementação de um objeto. Embora potencialmente propenso a erros (potencialmente levando a ponteiros pendurados), é extremamente útil ter um controle de grãos finos de como os objetos aparecem no monte para certas aplicações. Ao escolher uma linguagem, certifique-se de estudar como o coletor de lixo funciona e se pode ser modificado para otimizar para um caso de uso particular.

Muitas operações em sistemas de negociação algorítmicos são suscetíveis a paraleletização. Isso se refere ao conceito de realizar várias operações programáticas ao mesmo tempo, ou seja, em paralelo. Os chamados algoritmos paralelamente embaraçosos incluem etapas que podem ser calculadas completamente independentemente de outras etapas. Certas operações estatísticas, como simulações de Monte Carlo, são um bom exemplo de algoritmos paralelamente embaraçosos, pois cada sorteio aleatório e subsequente operação de caminho podem ser calculados sem conhecimento de outros caminhos.

Outros algoritmos são apenas parcialmente paralelizáveis. As simulações de dinâmica de fluidos são um exemplo, onde o domínio de computação pode ser subdividido, mas, em última análise, esses domínios devem se comunicar entre si e, portanto, as operações são parcialmente sequenciais. Os algoritmos paralelizáveis estão sujeitos à Lei de Amdahl, que fornece um limite superior teórico para o aumento do desempenho de um algoritmo paralelizado quando sujeito a processos separados NN (por exemplo, em um núcleo ou thread da CPU).

A paraleletização tornou-se cada vez mais importante como um meio de otimização desde que as velocidades de clock do processador estagnaram, já que os processadores mais novos contêm muitos núcleos com os quais executar cálculos paralelos.

O hardware de GPU é geralmente adequado apenas para o aspecto de pesquisa da finança quantitativa, enquanto que outro hardware mais especializado (incluindo Field-Programmable Gate Arrays - FPGA) é usado para (U) HFT. Hoje em dia, a maioria dos linguagens modernas suportam um grau de concurência/multithreading.

A escalabilidade em engenharia de software e operações refere-se à capacidade do sistema de lidar com cargas crescentes de forma consistente na forma de maiores solicitações, maior uso do processador e mais alocação de memória.

Embora os sistemas devem ser projetados para escalar, muitas vezes é difícil prever de antemão onde um gargalo ocorrerá. Registros rigorosos, testes, perfis e monitoramento ajudarão muito a permitir que um sistema se escale. As próprias linguagens são frequentemente descritas como "não escaláveis".

Uma maneira de gerenciar a escala é separar as preocupações, como mencionado acima. A fim de introduzir ainda mais a capacidade de lidar com spikes no sistema (ou seja, volatilidade súbita que desencadeia uma série de negócios), é útil criar uma arquitetura de fila de mensagens. Isso simplesmente significa colocar um sistema de fila de mensagens entre os componentes para que as ordens sejam empilhadas se um determinado componente não puder processar muitos pedidos.

Em vez de pedidos serem perdidos, eles são simplesmente mantidos em uma pilha até que a mensagem seja processada. Isso é particularmente útil para enviar negociações para um mecanismo de execução. Se o mecanismo estiver sofrendo de latência pesada, então ele fará backup de negociações. Uma fila entre o gerador de sinal comercial e a API de execução aliviará esse problema à custa de potencial deslizamento comercial. Um corretor de fila de mensagens de código aberto bem respeitado é o RabbitMQ.

Hardware e sistemas operacionais

O hardware que executa sua estratégia pode ter um impacto significativo na lucratividade do seu algoritmo. Esta não é uma questão restrita aos traders de alta frequência também. Uma escolha ruim no hardware e sistema operacional pode levar a uma falha da máquina ou reiniciar no momento mais inoportuno. Assim, é necessário considerar onde seu aplicativo residirá. A escolha é geralmente entre uma máquina de desktop pessoal, um servidor remoto, um provedor de cloud ou um servidor co-localizado na troca.

As máquinas desktop são simples de instalar e administrar, especialmente com os sistemas operacionais mais novos, como Windows 7/8, Mac OSX e Ubuntu. Os sistemas desktop possuem algumas desvantagens significativas, no entanto.

O uso de hardware em um ambiente doméstico (ou local de escritório) pode levar a problemas de conectividade à Internet e tempo de atividade da energia.

Um servidor dedicado ou máquina baseada em nuvem, embora muitas vezes mais caro do que uma opção de desktop, permite infraestrutura de redundância mais significativa, como backups automatizados de dados, a capacidade de garantir mais diretamente o tempo de atividade e o monitoramento remoto.

No Windows, isso geralmente é feito através do GUI Remote Desktop Protocol (RDP). Nos sistemas baseados no Unix, a linha de comando Secure SHell (SSH) é usada. A infraestrutura do servidor baseada no Unix é quase sempre baseada em linha de comando, o que torna imediatamente as ferramentas de programação baseadas em GUI (como o MatLab ou o Excel) inutilizáveis.

Um servidor co-localizado, como a frase é usada nos mercados de capitais, é simplesmente um servidor dedicado que reside dentro de uma troca, a fim de reduzir a latência do algoritmo de negociação.

O aspecto final para a escolha de hardware e a escolha da linguagem de programação é a independência da plataforma. Existe a necessidade de o código ser executado em vários sistemas operacionais diferentes? O código é projetado para ser executado em um determinado tipo de arquitetura de processador, como o Intel x86/x64 ou será possível executá-lo em processadores RISC, como os fabricados pela ARM?

Resiliência e Teste

Uma das melhores maneiras de perder muito dinheiro em negociação algorítmica é criar um sistema sem resiliência. Isso se refere à durabilidade do sistema quando sujeito a eventos raros, como falências de corretoras, volatilidade súbita excessiva, tempo de inatividade em toda a região para um provedor de servidor de nuvem ou a exclusão acidental de um banco de dados de negociação inteiro. Anos de lucros podem ser eliminados em segundos com uma arquitetura mal projetada. É absolutamente essencial considerar questões como depuração, teste, registro, backups, alta disponibilidade e monitoramento como componentes principais do seu sistema.

É provável que, em qualquer aplicação quantitativa de negociação personalizada razoavelmente complicada, pelo menos 50% do tempo de desenvolvimento seja gasto em depuração, teste e manutenção.

Quase todas as linguagens de programação são fornecidas com um depurador associado ou possuem alternativas de terceiros bem respeitadas. Em essência, um depurador permite a execução de um programa com a inserção de pontos de interrupção arbitrários no caminho do código, que interrompem temporariamente a execução para investigar o estado do sistema.

A depuração é um componente essencial na caixa de ferramentas para analisar erros de programação. No entanto, eles são mais amplamente usados em linguagens compiladas como C ++ ou Java, pois linguagens interpretadas como Python são muitas vezes mais fáceis de depurar devido a menos LOC e menos declarações verbosas. Apesar dessa tendência, o Python é enviado com o pdb, que é uma ferramenta de depuração sofisticada.

O teste no desenvolvimento de software refere-se ao processo de aplicação de parâmetros e resultados conhecidos a funções, métodos e objetos específicos dentro de uma base de código, a fim de simular o comportamento e avaliar vários caminhos de código, ajudando a garantir que um sistema se comporte como deveria. Um paradigma mais recente é conhecido como Test Driven Development (TDD), onde o código de teste é desenvolvido contra uma interface especificada sem implementação.

O TDD requer um extenso design de especificações iniciais, bem como um nível saudável de disciplina para ser executado com sucesso. No C++, o Boost fornece uma estrutura de teste unitário. No Java, a biblioteca JUnit existe para cumprir o mesmo propósito. O Python também possui o módulo unittest como parte da biblioteca padrão. Muitas outras linguagens possuem estruturas de teste unitário e muitas vezes há várias opções.

Em um ambiente de produção, o logging sofisticado é absolutamente essencial. O logging refere-se ao processo de saída de mensagens, com vários graus de gravidade, sobre o comportamento de execução de um sistema para um arquivo ou banco de dados plano. Os logs são uma "primeira linha de ataque" quando se procura um comportamento inesperado no tempo de execução do programa.

Tanto o Microsoft Windows quanto o Linux vêm com ampla capacidade de registro do sistema e as linguagens de programação tendem a ser fornecidas com bibliotecas de registro padrão que cobrem a maioria dos casos de uso.

Enquanto o registro de um sistema fornecerá informações sobre o que aconteceu no passado, o monitoramento de um aplicativo fornecerá informações sobre o que está acontecendo agora. Todos os aspectos do sistema devem ser considerados para monitoramento. Métricas de nível do sistema, como uso de disco, memória disponível, largura de banda da rede e uso da CPU, fornecem informações básicas de carga.

As métricas de negociação, tais como preços/volumes anormais, retiradas súbitas e rápidas e exposição da conta para diferentes setores/mercados, devem também ser monitorizadas continuamente.

O monitoramento do sistema é muitas vezes o domínio do administrador do sistema ou gerente de operações. No entanto, como um único desenvolvedor de negociação, essas métricas devem ser estabelecidas como parte do projeto maior.

Os backups e a alta disponibilidade devem ser as principais preocupações de um sistema de negociação. Considere as seguintes duas perguntas: 1) Se um banco de dados de produção inteiro de dados de mercado e histórico de negociação fosse excluído (sem backups), como o algoritmo de pesquisa e execução seria afetado? 2) Se o sistema de negociação sofrer uma interrupção por um período prolongado (com posições abertas), como o patrimônio da conta e a lucratividade contínua seriam afetados?

É imperativo colocar em prática um sistema para fazer backup de dados e também para testar a restauração de tais dados. Muitos indivíduos não testam uma estratégia de restauração.

De forma semelhante, a alta disponibilidade deve ser incorporada desde o início. A infraestrutura redundante (mesmo com custos adicionais) deve sempre ser considerada, pois o custo do tempo de inatividade provavelmente superará em muito o custo de manutenção contínua de tais sistemas.

Escolhendo um idioma

A próxima etapa é discutir como as linguagens de programação são geralmente categorizadas.

Sistemas de tipo

Quando se escolhe uma linguagem para uma pilha de negociação, é necessário considerar o sistema de tipos. As linguagens que são de interesse para a negociação algorítmica são tipadas estáticamente ou dinamicamente. Uma linguagem tipada estáticamente executa verificações dos tipos (por exemplo, números inteiros, flutuantes, classes personalizadas etc.) durante o processo de compilação. Tais linguagens incluem C ++ e Java. Uma linguagem tipada dinamicamente executa a maioria de sua verificação de tipos no tempo de execução. Tais linguagens incluem Python, Perl e JavaScript.

Para um sistema altamente numérico, como um mecanismo de negociação algorítmico, a verificação de tipo no tempo de compilação pode ser extremamente benéfica, pois pode eliminar muitos bugs que, de outra forma, levariam a erros numéricos. No entanto, a verificação de tipo não capta tudo, e é aqui que o manuseio de exceções entra em jogo devido à necessidade de lidar com operações inesperadas. As linguagens dinâmicas (ou seja, aquelas que são tipadas dinamicamente) muitas vezes podem levar a erros de tempo de execução que, de outra forma, seriam capturados com uma verificação de tipo no tempo de compilação.

Outro benefício das linguagens de tipo estático é que o compilador é capaz de fazer muitas otimizações que de outra forma não estão disponíveis para a linguagem de tipo dinâmico, simplesmente porque o tipo (e, portanto, os requisitos de memória) são conhecidos no momento da compilação.

Open Source ou Proprietário?

Uma das maiores escolhas disponíveis para um desenvolvedor de negociação algorítmica é usar tecnologias proprietárias (comerciais) ou de código aberto. Existem vantagens e desvantagens para ambas as abordagens. É necessário considerar o quão bem uma linguagem é suportada, a atividade da comunidade em torno de uma linguagem, a facilidade de instalação e manutenção, a qualidade da documentação e quaisquer custos de licenciamento / manutenção.

A pilha Microsoft.NET (incluindo Visual C++, Visual C#) e MathWorks MatLab são duas das maiores opções proprietárias para o desenvolvimento de software de negociação algorítmica personalizado.

A Microsoft e a MathWorks fornecem extensa documentação de alta qualidade para seus produtos. Além disso, as comunidades em torno de cada ferramenta são muito grandes, com fóruns web ativos para ambos. O software.NET permite integração coesa com várias linguagens, como C ++, C # e VB, bem como fácil ligação a outros produtos da Microsoft, como o banco de dados SQL Server via LINQ. A MatLab também tem muitos plugins / bibliotecas (alguns gratuitos, alguns comerciais) para quase qualquer domínio de pesquisa quantitativa.

O Visual Studio é um software que é executado no Microsoft Windows, que é sem dúvida muito menos performante do que um servidor Linux equivalente que é ajustado de forma ideal.

O MatLab também carece de alguns plugins-chave, como um bom envoltório em torno da API Interactive Brokers, um dos poucos corretores suscetíveis a negociação algorítmica de alto desempenho.

As ferramentas de código aberto têm sido de qualidade industrial por algum tempo. Grande parte do espaço de ativos alternativos faz uso extensivo do Linux de código aberto, MySQL / PostgreSQL, Python, R, C ++ e Java em funções de produção de alto desempenho. No entanto, eles estão longe de se restringir a esse domínio. Python e R, em particular, contêm uma riqueza de extensas bibliotecas numéricas para realizar quase qualquer tipo de análise de dados imaginável, muitas vezes em velocidades de execução comparáveis a linguagens compiladas, com certas advertências.

O principal benefício do uso de linguagens interpretadas é a velocidade do tempo de desenvolvimento. Python e R exigem muito menos linhas de código (LOC) para alcançar funcionalidades semelhantes, principalmente devido às extensas bibliotecas. Além disso, muitas vezes permitem o desenvolvimento interativo baseado em console, reduzindo rapidamente o processo de desenvolvimento iterativo.

Dado que o tempo como desenvolvedor é extremamente valioso, e a velocidade de execução muitas vezes menos (exceto no espaço HFT), vale a pena dar uma consideração extensa a uma pilha de tecnologia de código aberto. Python e R possuem comunidades de desenvolvimento significativas e são extremamente bem suportadas, devido à sua popularidade.

As ferramentas de código aberto geralmente sofrem com a falta de um contrato de suporte comercial dedicado e funcionam de forma ideal em sistemas com interfaces de usuário menos tolerantes. Um servidor Linux típico (como o Ubuntu) geralmente será totalmente orientado à linha de comando. Além disso, Python e R podem ser lentos para certas tarefas de execução.

Embora o software proprietário não seja imune a problemas de dependência / versão, é muito menos comum ter que lidar com versões incorretas de bibliotecas em tais ambientes.

Eu vou arriscar minha opinião pessoal aqui e afirmar que eu construo todas as minhas ferramentas de negociação com tecnologias de código aberto. Em particular, eu uso: Ubuntu, MySQL, Python, C ++ e R. A maturidade, o tamanho da comunidade, a capacidade de cavar fundo se ocorrerem problemas e reduzir o custo total de propriedade (TCO) superam em muito a simplicidade das GUI proprietárias e instalações mais fáceis.

Baterias incluídas?

O cabeçalho desta seção refere-se às capacidades "out of the box" da linguagem - que bibliotecas ela contém e quão boas são?

O Python é conhecido por ser capaz de se comunicar com quase qualquer outro tipo de sistema/protocolo (especialmente a web), principalmente através de sua própria biblioteca padrão. O R tem uma riqueza de ferramentas estatísticas e econômicas embutidas, enquanto o MatLab é extremamente otimizado para qualquer código de álgebra linear numérica (que pode ser encontrado na otimização de portfólios e no preço de derivados, por exemplo).

Fora das bibliotecas padrão, o C++ faz uso da biblioteca Boost, que preenche as partes faltantes da biblioteca padrão.

O Python possui a combinação de biblioteca de análise de dados NumPy / SciPy / Panda de alto desempenho, que ganhou ampla aceitação para pesquisa de negociação algorítmica. Além disso, existem plugins de alto desempenho para acesso aos principais bancos de dados relacionais, como MySQL ++ (MySQL / C ++), JDBC (Java / MatLab), MySQLdb (MySQL / Python) e psychopg2 (PostgreSQL / Python).

Um aspecto frequentemente negligenciado de um sistema de negociação, enquanto na fase inicial de pesquisa e design é a conectividade com uma API de corretor. A maioria das APIs suporta nativamente C ++ e Java, mas algumas também suportam C # e Python, diretamente ou com código de envolvimento fornecido pela comunidade para as APIs C ++. Em particular, os corretores interativos podem ser conectados através do plugin IBPy. Se for necessário alto desempenho, as corretoras suportarão o protocolo FIX.

Conclusão

Como é agora evidente, a escolha da linguagem de programação para um sistema de negociação algorítmica não é simples e requer um profundo pensamento. As principais considerações são desempenho, facilidade de desenvolvimento, resiliência e teste, separação de preocupações, familiaridade, manutenção, disponibilidade de código fonte, custos de licenciamento e maturidade das bibliotecas.

O benefício de uma arquitetura separada é que permite que as linguagens sejam "ligadas" para diferentes aspectos de uma pilha de negociação, conforme e quando os requisitos mudam.


Mais.