Thursday 5 April 2018

Tutorial do sistema de negociação c


Codificação de sistemas de negociação.
Por Justin Kuepper.
Como são criados sistemas de negociação automatizados?
Este tutorial se concentrará nas segunda e terceira partes deste processo, onde suas regras são convertidas em um código que seu software comercial pode entender e usar.
Vantagens e desvantagens.
Um sistema automatizado leva a emoção e ocupado - trabalhe fora da negociação, o que permite que você se concentre em melhorar sua estratégia e regras de gerenciamento de dinheiro. Uma vez que um sistema lucrativo é desenvolvido, não requer nenhum trabalho de sua parte até que ele quebre, ou as condições do mercado exigem uma mudança. Desvantagens:
Se o sistema não estiver corretamente codificado e testado, grandes perdas podem ocorrer muito rapidamente. Às vezes, é impossível colocar certas regras em código, o que dificulta o desenvolvimento de um sistema de negociação automatizado. Neste tutorial, você aprenderá como planejar e projetar um sistema de negociação automatizado, como traduzir esse design para o código que seu computador irá entender, como testar seu plano para garantir um desempenho ótimo e, finalmente, como colocar seu sistema em uso.

Tutorial do sistema de negociação C ++
Obter através da App Store Leia esta publicação em nosso aplicativo!
Um simples demo do sistema de negociação C ++.
Preciso do meu sistema de negociação demo revisado. Ele implementou um sistema simples que analisa o fluxo de negociação (arquivo logado) de comerciante diferente e calcula algumas características importantes.
Eu encontrei um par de coisas que poderiam ajudá-lo a melhorar o seu código.
Não abuse usando namespace std.
Colocar usando namespace std no topo de cada programa é um mau hábito que você faria bem em evitar. Em particular, você nunca deve usá-lo em um arquivo de cabeçalho.
Use os cabeçalhos apropriados.
Em vez de usar stdint. h você deve usar:
Isso coloca as coisas desse cabeçalho no namespace std :: em vez de apenas no espaço para nome global e salvará as dores de cabeça mais tarde. (Note-se que também pode colocar itens no espaço de nomes global, mas, como programador, você deve evitar confiar nesse comportamento definido pela implementação).
Elimine as variáveis ​​não utilizadas.
Este código declara uma série de variáveis ​​(termo, qty, nread), mas depois não faz nada com eles. Seu compilador é inteligente o suficiente para ajudá-lo a encontrar esse tipo de problema se você sabe como pedir isso para fazê-lo.
Evite números mágicos.
As linhas que incluem números sem explicação são um problema de manutenção à espera de acontecer. Por exemplo, o código inclui esta linha sem comentários:
É provável que esses não sejam realmente aleatórios, mas não há indícios quanto ao significado desses números.
Não use enquanto (! Fin. eof ())
É quase sempre um erro para escrever o código que usa enquanto (! Fin. eof ()) ou o equivalente, porque o que você está interessado em determinar é se há algum dado e não se o fim do fluxo . Veja esta pergunta para obter mais detalhes sobre isso.
Não proliferar variáveis ​​inúteis.
O código atualmente inclui esse par de linhas:
A corda do instrumento nunca é usada novamente. Por que não apenas escrever isso em vez disso?
Use estruturas de fluxo de controle adequadas.
Dentro do main, o código decide como lidar com os dados com base no campo msg_type. Tem uma conexão em cascata se. senão com uma cláusula final final vazia. No entanto, isso seria muito mais claro escrito como uma declaração de switch com cada caso representando um tipo de mensagem diferente.
Use algoritmos padrão.
O código atual inclui esta seqüência:
O objetivo parece ser identificar a maior quantidade de negociação e o comerciante associado. No entanto, já existe um algoritmo para isso, que é std :: max_element.
Omitir retorno 0.
Quando um programa C ++ chega ao final do main, o compilador gerará automaticamente o código para retornar 0, portanto, não há motivo para colocar o retorno 0; explicitamente no final do principal.
Use objetos mais completamente.
Seu código possui aulas, mas eles quase sempre usam um simples contentor, como OrderEntry e OrderAck. Isso tornaria seu código mais simples e fácil de entender e manter se você também adicionasse funções de membros para eles fazer as coisas que estão sendo feitas atualmente para essas estruturas de dentro do principal.

Usando o C ++ para sistemas de baixa latência.
Esta aula foi ministrada em 2016 e está online apenas para fins históricos.
& # 8220; Usando o C ++ para sistemas de baixa latência & # 8221; é um curso de treinamento de dois dias ministrado por Patrice Roy da Universidade de Sherbrooke. É oferecido no Meydenbauer das 9h às 17h nos sábados e domingos, 17 e 17 de setembro (imediatamente antes da conferência). O almoço está incluído.
Descrição do Curso.
Para obter o tipo de desempenho exigido por algumas das aplicações mais exigentes, como jogos e negociação de alta freqüência, requer o domínio das técnicas de baixa latência não encontradas no C ++ convencional.
Esta classe lhe dará as habilidades necessárias para criar sistemas de baixa latência em C ++:
Como desenvolver componentes para sistemas com restrições de baixa latência Como desenvolver sistemas com desempenho previsível, particularmente onde o tempo de execução do pior caso entra em jogo Como executar computação em tempo de compilação em vez de em tempo de execução quando esta é uma opção Como reduzir o sobrecarga espacial de seus programas Como tornar o gerenciamento de memória mais eficiente, de várias maneiras Como tirar o máximo proveito da memória cache Como tirar o máximo proveito de ponteiros inteligentes Como medir o desempenho de seus programas de forma portátil.
A ênfase será colocada em código portátil e usará recursos C ++ 11 / C ++ 14. Os exemplos serão apoiados por medições e a discussão aberta será encorajada.
Pré-requisitos.
Os participantes devem ter conhecimento intermediário da linguagem C ++; A ênfase será colocada em código C ++ robusto com previsão & # 8212; e rápido & # 8212; comportamento de tempo de execução.
Este curso inclui exercícios, portanto, traga seu laptop e seu ambiente de desenvolvimento C ++ 11/14 favorito.
Tópicos do curso.
Este curso se concentrará em técnicas que os programadores podem usar para obter um desempenho melhor ou mais estável de sistemas com restrições de baixa latência. É subdividido em seções que cobrem subconjuntos selecionados deste tópico importante. Cada seção discute recursos C ++ que ajudam a alcançar os objetivos da seção, com ênfase em recursos C ++ 11/14, onde quer que isso faça sentido.
Definimos o que queremos dizer com "baixa latência"; discutir as semelhanças e diferenças com os sistemas em tempo real; introduzir os conceitos do tempo de execução do pior caso e discutir as utilidades e técnicas de medição. Os aspectos orientados para a resiliência da programação em C ++ serão abordados aqui, mas isso será um tema recorrente ao longo do curso.
Os recursos C ++ utilizados incluirão static_assert, utilitários, modelos variadic e mecanismos de dedução automática do tipo.
Alguns recursos do C ++ têm altos níveis e poucas ou nenhuma desvantagem para o desenvolvimento de sistemas de baixa latência. Nesta seção do curso, exploraremos e usaremos alguns dos mais relevantes.
Os recursos de C ++ usados ​​incluirão unique_ptr e make_unique, constexpr, mecanismos de dedução de tipos automáticos, tipos de traços, enable_if, usos interessantes da palavra-chave usada e semântica de movimento.
Recursos C ++ para usar com cuidado em sistemas de baixa latência.
Existem recursos C ++ que podem ser usados ​​para sistemas de baixa latência, mas com particular cuidado, pois eles têm custos que podem ser superiores aos seus benefícios. Tomaremos uma abordagem fundamentada, baseada em medição, para construir um julgamento informado.
Os recursos C ++ usados ​​incluirão shared_ptr e make_shared, exceções, herança múltipla, RTTI e substituições usadas-definidas. Também discutiremos o papel que não pode assumir nos sistemas.
Alavancando recipientes e algoritmos padrão em sistemas de baixa latência.
Algumas empresas reescrevem alguns ou todos os recipientes de padrões devido à crença de que suas necessidades não podem ser satisfeitas pelas ferramentas que esta biblioteca oferece. Exploraremos maneiras de tirar o máximo proveito dos contêineres e os algoritmos fornecidos pela biblioteca padrão e examinar maneiras de aprimorá-los quando apropriado.
Concorrência e Programação Paralela.
Os problemas de sistemas de baixa latência sobrepõem as de sistemas paralelos e concorrentes de diferentes maneiras: reduzir a dependência de operações de bloqueio e instalações de sincronização, por exemplo, é uma forte tendência nessas duas áreas.
Os recursos de C ++ usados ​​incluirão ferramentas de encadeamento e atômica C ++ 11/14, mas com ênfase nos padrões de uso que permitem aos componentes reagir em tempo hábil aos eventos.
O C ++ permite que os programadores gerenciem a alocação de memória manualmente de maneiras diversas e interessantes. Nós exploraremos maneiras de usar esses mecanismos para nossa vantagem ao construir sistemas de baixa latência.
Os recursos C ++ utilizados incluirão operadores especializados novos e excluídos de várias maneiras, entendendo posicionamento novo e como escrever alocadores antes e desde C ++ 11.
Houve uma série de apresentações interessantes sobre o uso da memória cache e seu impacto no desempenho do programa. Exploraremos as nuances desta questão com exemplos.
Os recursos C ++ utilizados incluirão contêineres STL e algoritmos, mecanismos de controle de alinhamento, bem como utilitários de programação paralelos e concorrentes.
Claro, quando é prático fazê-lo, os programas mais rápidos são aqueles que não fazem nada. Exploraremos algumas maneiras de combinar técnicas de metaprogramação com pequenos programas, a fim de mover a computação para compilar o tempo quando há benefícios ao fazê-lo.
Instrutor do curso.
Patrice Roy jogou com C ++, profissionalmente, por prazer ou (na maioria das vezes) tanto por mais de 20 anos. Depois de alguns anos, fazendo R & D e trabalhando em simuladores de vôo militares, ele passou a acadêmicos e tem ensinado ciência da computação desde 1998. Desde 2005, ele participou mais especificamente para ajudar estudantes de pós-graduação e profissionais dos campos de sistemas em tempo real e programação de jogos desenvolvem as habilidades de que precisam para enfrentar os desafios de hoje. A evolução rápida do C ++ nos últimos anos tornou seu trabalho ainda mais agradável.
Ele foi um membro participante no Comitê de Padrões ISO C ++ desde o final de 2014 e esteve envolvido com as Vulnerabilidades de Linguagem de Programação ISO desde o final de 2015. Ele tem cinco filhos e sua esposa assegura que sua casa abriga um número continuamente em mudança de gatos, cachorros e outros animais.

Um exemplo de uma estratégia de negociação codificada em C ++
Qualquer estratégia comercial pode ser dividida em um conjunto de eventos e a reação a esses eventos. As reações podem ficar infinitamente complexas e variáveis, mas essencialmente a escrita de estratégias é simplesmente colocar exatamente isso. O tipo de eventos e a sua frequência dependeriam dos mercados e dos instrumentos em que esta estratégia estaria funcionando no entanto, em termos gerais a maioria dos mercados teria diferentes sabores do seguinte,
TIPO DE EVENTOS.
Mudança de dados do mercado e # 8211; Isso pode significar que os preços mudam ou os tamanhos mudam. Também pode ser o último preço negociado. Relatórios da troca & # 8211; Agradecimentos de trocas, rejeições, etc. Execução de ordens e # 8211; Parcial de execução completa de ordens que foram colocadas anteriormente. Pedidos enviados para a troca & # 8211; Algumas reservas de livros que talvez precisem ser feitas logo após o envio de uma ordem para a troca, talvez para gerenciamento de riscos. Eventos de intervalo e # 8211; Este não é um evento relacionado ao mercado, mas mais como uma lógica que precisa ser executada em intervalos regulares. Por exemplo, a formação de velas. Novo portfólio sendo carregado & # 8211; Um novo portfólio a ser carregado pode alterar os limites de risco de outras carteiras que já estão sendo executadas e, portanto, a necessidade de reduzir os tamanhos de pedidos, etc. Os parâmetros do usuário mudam & # 8211; Cada estratégia requer um certo conjunto de entradas de usuários ou parâmetros que definem a estrutura dentro da qual a estratégia opera. Isso pode variar desde a citação do tamanho da ordem, até a exposição máxima que a estratégia pode tomar, etc. Qualquer um desses parâmetros que mudam pode e geralmente garante uma quantidade de recálculo.
Como um exercício, podemos observar uma estratégia muito simples e ver como dividimos uma premissa em reação a eventos. Consideremos uma estratégia de arbitragem pura que se baseia essencialmente no fato de que o mesmo instrumento que está sendo citado em diferentes destinos deve, idealmente, ter o mesmo valor. Se houver alguma discrepância no valor suficientemente grande para justificar a compra em uma troca e venda no outro, fazemos isso. Então, digamos que queremos fazer uma propagação de cada compra e venda. Portanto, a estratégia proposta seria citar a instr1 a um preço.
SellPrice = peça 2 + s.
Onde preço de compra e preço de venda são os preços do pedido de compra e da ordem de venda, respectivamente, na instr1.
Bid1 e ask1 são preços de instr1.
Bid2 e ask2 são preços de instr2.
A lógica básica seria consistentemente manter a ordem de compra em bid2 - s e vender a pedido em ask2 + s. Sempre que o pedido de compra é executado, enviamos uma ordem de venda no instr2 no bid2. Então, de fato,
Compramos em bid2 - s e vendemos em bid2 = & gt; Saindo dessa transação.
Claramente, como podemos ver, a lógica onMarketData realmente depende apenas dos dados de mercado do instr2 e nada mais.
Da mesma forma, a lógica onExecution depende da execução de pedidos no instr1.
Parece bom até agora. Isso seria perfeito em um mundo ideal onde as coisas aconteçam instantaneamente. Mas no mundo real, operamos sob certas restrições. Algumas dessas restrições são.
Demora uma quantidade limitada de tempo para uma ordem para alcançar a troca. É preciso um período finito de tempo para que a troca confirme uma ordem. Nenhuma solicitação de substituição pode ser enviada por pedido, a menos que esteja em um estado reconhecido.
Claramente isso muda as coisas. Considere a seguinte linha de tempo.
T0: comprar pedido enviado no preço b1 (= bid2 - s)
T1: instr2 move para marcar.
T2: Reconheceu o pedido enviado no T0.
T10: novos dados de mercado no instrumento 2.
Na T1, nosso pedido de compra em instr1 deveria ter sido substituído para bid2 - 1 - s. No entanto, uma vez que o pedido não foi reconhecido, não poderíamos substituí-lo e, portanto, a ordem ainda está em bid2 - s e permanece lá até que os novos dados do mercado cheguem ao T10. Observe que o reconhecimento chegou ao T2. No entanto, não substituímos o nosso pedido (que estava em pé no preço errado) porque decidimos que a cotação no instr1 depende apenas dos dados de mercado da instr2. Isso significa que se essa ordem for executada em dizer T3, nós faríamos.
Compre instr1 no bid2-s.
Vender instr2 em bid2 -1 = & gt; fizemos s-1 (em vez de s).
Para evitar isso, você também pode querer reagir aos relatórios de reconhecimento.
Então, o novo pseudocódigo seria.
Parece bom novamente. Até, é claro, cavamos um pouco mais fundo. Considere a seguinte linha de tempo.
T0: comprar pedido O1 enviado no preço b1 (= bid2 - s)
T1: Reconheceu o pedido enviado no T0.
T2: execução do pedido original O1. Cobrir a ordem de venda enviada no instr2 no bid2.
T3: execução da ordem instr2. Nada feito desde a execução está em instr2.
T10: novos dados de mercado no instrumento 2. Nova ordem de compra O2 enviada em instr1.
Tenha em atenção que, a partir de T2 e T10, não há pedido de compra em instr1. O que significa que podemos estar perdendo oportunidades. Nós apenas entramos com uma ordem de compra na T10, pois os eventos que estávamos ouvindo eram dados de mercado em instr2, reconhecimento de instr1 e execução de instr1. Para evitar perder a oportunidade, adicionaremos outro evento à nossa lista. Execuções de instr2. Como resultado, nós modificaremos nosso pseudo código como.
Até agora estamos assumindo que nossas execuções acontecem completamente ou nenhuma. As execuções parciais introduzem uma lata de vermes em nossa lógica limpa. Isso ocorre porque isso acrescenta outra restrição que devemos respeitar:
Ao substituir, temos que dizer ao intercâmbio qual era o último tempo de transação. O último tempo de transação refere-se ao timestamp que cada troca atribui sempre que uma ordem é alterada (reconhecida, substituída, negociada, etc.)
Agora isso leva ao seguinte cenário.
T0: comprar pedido O1 enviado no preço b1 (= bid2 - s)
T1: Reconheceu o pedido enviado no T0. Último tempo de transação atualizado para T1.
T2: MarketData para instr2 alterações para bid2 - 1. Substituir solicitação (R1 com o último tempo de transação como T1) enviado para alterar o preço para bid2-1-s.
T3: execução parcial do pedido original O1 antes que R1 atinja a troca. O último tempo de transação atualizado no final de troca para T3. Cobrir a ordem de venda enviada no instr2 no bid2. Nenhuma solicitação de substituição enviada no instr1, pois o pedido está em estado não reconhecido.
T4: ordem rejeitada porque troca acha que o último tempo de transação é T3, mas a solicitação de substituição é enviada com T1.
T10: novos dados do mercado no instrumento 2. Substitua a solicitação enviado R2 enviado no instr1.
Entre T4 e T10, a ordem de compra em instr1 ainda está em bid2 - s (em vez de bid2-1-s). Isso poderia levar a uma derrapagem se ver uma outra execução. Não o substituímos pelo preço certo porque estamos reagindo apenas.
dados de mercado em instr2, reconhecimento de instr1, execuções.
Agora, podemos adicionar rejeitos ao algoritmo também.
Até agora, fizemos dois grandes pressupostos. Um, que os eventos acontecem um a um e dois, que nossa reação a um evento é instantânea. Na realidade, no entanto, os eventos podem acontecer simultaneamente, por exemplo, os dados do mercado e a execução de uma de nossas ordens podem nos alcançar ao mesmo tempo. Isso significa que a estratégia seria executar dois tópicos diferentes em paralelo. Da mesma forma, uma execução pode chegar enquanto estamos processando nossa reação a um evento de dados de mercado. Se alguém processar eventos em paralelo, devemos ter cuidado com a implementação, uma vez que variáveis ​​como buyPosition e sellPosition podem estar em um estado inconsistente. Se você quiser evitar a complexidade das implementações multi-threaded, então sempre pode-se processar os eventos de maneira seqüencial, então o custo seria a latência. Examinaremos os casos de ponta que surgiram com a implementação multi-threaded e como eles podem ser ignorados em outro post.
Mesmo em implementações de thread único, ainda não cuidamos os eventos gerados pelo usuário, como mudanças nos parâmetros. Por exemplo, e se o usuário decidir mudar o valor de s. Devemos reagir a isso também, em vez de esperar o próximo evento de mercado para substituir nossas cotações pelo preço certo. A essência deste post é apresentar a abordagem de desintegração e eventos e cavar mais fundo no fluxo da lógica antes de implementar uma estratégia de negociação algorítmica.
Posts Relacionados:
4 pensamentos sobre "Um exemplo de uma estratégia de negociação codificada em C ++"
& # 8220; Note que, a partir de T2 e T10, não há pedido de compra em instr1. O que significa que podemos estar perdendo oportunidades. Nós apenas entramos com uma ordem de compra na T10, pois os eventos que estávamos ouvindo eram dados de mercado em instr2, reconhecimento de instr1 e execução de instr1. Para evitar perder a oportunidade, adicionaremos outro evento à nossa lista. Execuções de instr2. & # 8221;
Você está tentando dizer aqui que precisamos executar o instr1, mesmo que a ordem da capa em troca 2 não tenha sido executada?
Se o reconhecimento for para instr1.
buyPrice = tick2.bid-s.
se buyorder presente na instr1.
substitua-o para comprar o preço.
envie um novo pedido no buyPrice.
SellPrice = tick2.ask + s.
se vendedor presente na instr2.
substitua-o para vender o preço.
envie uma nova ordem no preço de venda.
se a execução da compra acontecesse na instr1.
envie uma ordem de venda na instr2.
senão se a execução da venda aconteceu no isntr1.
envie um pedido de compra em instr2.
senão se a execução estiver em instr2.
Não deveria ser esta a primeira condição? Se a execução estiver em instr2, então não deve comprar ou vender instr1, correto?
A função OnExecution só seria chamada de execuções. Como resultado, esta verificação de se a execução da capa aconteceu ou não está implícita.
Poderia ser que obtivéssemos preencher o preenchimento da instr1 e enviamos um pedido de cobertura de venda e um preenchimento de vendas na instr1 e enviamos um pedido de compra de cobertura. Agora, neste cenário, quando conseguimos um preenchimento para a ordem de cobertura de venda, pode ser que o preenchimento da capa de compra não tenha chegado. Nosso algoritmo ainda chamaria OnMarketdata e essa função verificaria as encomendas de cobertura preenchidas. Mesmo neste caso, a função onExecution não mudaria. Nós elaboramos sobre isso na próxima publicação.

No comments:

Post a Comment