Noções básicas de Python para negociação algorítmica
Os traders usam Python para criar robôs de negociação, indicadores técnicos, plugins e outras ferramentas para auxiliar a negociação algorítmica ou operações manuais, e este artigo explica os fundamentos de programação em Python.
Python é uma linguagem de programação popular, de alto nível e de uso geral, utilizada para desenvolvimento web, ciência de dados, automação e, mais recentemente, negociação algorítmica no cTrader. Quer esteja a criar robôs de negociação simples baseados em sinais ou estratégias complexas com múltiplos indicadores, o Python torna o processo mais rápido, mais eficiente e mais fácil de gerir.
Algoritmos Python em um minuto!
- Experimente o suporte integrado de Python e o acesso perfeito à API do cTrader Algo, sendo o cTrader a única plataforma importante a oferecer integração nativa de origem. Não são necessários plugins, adaptadores ou configurações complexas.
- Concentre-se mais no que a sua estratégia deve alcançar, pois a lógica torna-se mais fácil de montar. Desfrute de iteração rápida, componentes reutilizáveis e desempenho escalável.
- Desenvolva rapidamente, depure de forma mais inteligente e colabore sem barreiras. O seu código será sempre adaptável, fiável e fácil de manter.
- Aceda e beneficie de milhares de bibliotecas gratuitas/open-source, tutoriais detalhados, exemplos de código e forte apoio da comunidade em todo o mundo.
Variáveis e tipos de dados
Em Python, as variáveis são tipadas dinamicamente, o que significa que não é necessário declarar explicitamente os seus tipos de dados. O interpretador determina o tipo em tempo de execução com base no valor atribuído.
Cria variáveis simplesmente atribuindo-lhes um valor:
1 2 3 4 | |
Tipos de dados comuns
| Tipo | Descrição | Exemplo |
|---|---|---|
int | Números inteiros | 5, 100, api.StepPips |
float | Números decimais | 1.1234, 100.5, api.Symbol.Ask |
bool | Valores booleanos | True, False |
str | Strings | "EURUSD", api.Label |
list | Coleção de itens | [1, 2, 3], [p for p in api.Positions] |
Nos algoritmos do cTrader, as variáveis armazenam dados importantes relacionados com informações de mercado, decisões de negociação e configuração de cBots. Estas variáveis frequentemente representam volumes de negociação calculados, valores de indicadores, sinalizadores booleanos, nomes de símbolos, etiquetas e muito mais.
Aqui está um exemplo:
1 2 3 4 | |
Neste caso, self.volumeInUnits é um float usado para colocar ordens, enquanto self.enoughMoney é um bool que controla se deve continuar a abrir posições numa estratégia de grelha.
Classes e objetos
Python é uma linguagem de programação orientada a objetos (POO), fornecendo ferramentas para organizar o código através de classes e objetos que modelam entidades e comportamentos do mundo real. Uma classe define um modelo para criar objetos, que são instâncias dessa classe com os seus próprios dados e comportamentos únicos. Os conceitos-chave são descritos abaixo:
- Uma classe é definida usando a palavra-chave
class. - O método
__init__(construtor) é comummente usado para inicializar o estado do objeto. - Os métodos de instância definem o comportamento.
- Os atributos contêm dados específicos de cada objeto.
Por exemplo, pode criar uma classe Carro:
1 2 3 4 5 6 7 | |
Em seguida, pode criar objetos da classe Carro e interagir com eles:
1 2 3 | |
No contexto do cTrader
No cTrader, cBots, indicadores e plugins são implementados como classes que encapsulam toda a sua lógica. Os algoritmos interagem com a plataforma cTrader usando um objeto api especial que fornece acesso a símbolos, gráficos, ordens, indicadores e muito mais.
Pode criar uma classe SimplecBot no cTrader desta forma:
1 2 3 | |
A classe SimplecBot inclui um único método (on_start(self)) que é executado uma vez quando o robô de negociação é iniciado. A função api.Print escreve uma mensagem no registo, demonstrando como os métodos do objeto encapsulam o comportamento de negociação.
Cada instância de uma classe representa efetivamente um algoritmo de negociação autónomo que gere o seu próprio ciclo de vida e decisões de negociação usando princípios de POO. Num cBot padrão do cTrader, uma classe pode armazenar dados de estado interno, como volume, resultados de indicadores, etc., e usar vários métodos para gerir a lógica de negociação.
Considere este exemplo de cruzamento MACD que inicializa o indicador MACD quando iniciado e coloca uma ordem de compra quando ocorre um sinal de cruzamento MACD:
1 2 3 4 5 6 7 | |
A palavra-chave self
Dentro de uma classe, self refere-se à instância da classe e fornece acesso às suas variáveis e métodos. self é utilizado para:
- Armazenar dados como resultados de indicadores, volumes de posição e valores de configuração.
- Acompanhar o estado interno em diferentes chamadas de métodos, como
on_start(),on_tick()ouon_bar_closed().
Este exemplo demonstra como self é utilizado:
1 2 3 4 | |
Neste caso, self.volume armazena o volume calculado a ser utilizado para negociações, enquanto self.macd armazena o objeto do indicador MACD, permitindo o acesso aos seus valores ao longo do ciclo de vida do cBot. Sem self, estas variáveis seriam locais para on_start() e inacessíveis em on_bar_closed(), onde as decisões de negociação podem ser tomadas.
Métodos e funções
As funções são blocos de código reutilizáveis utilizados para executar uma tarefa específica. Quando as funções são definidas dentro de uma classe, são chamadas de métodos e operam no estado interno da classe através do parâmetro self. No contexto da negociação algorítmica com o cTrader, os métodos definem como o seu algoritmo de negociação se comporta sob diferentes condições, como ticks de mercado, fechamentos de barras ou inicialização.
A plataforma chama automaticamente métodos especiais (conhecidos como manipuladores de eventos) em momentos apropriados, tais como:
on_start(self) – chamado uma vez quando o bot é inicializado.
1 2 | |
on_tick(self) – chamado a cada tick de mercado recebido.
1 2 | |
on_bar_closed(self) – chamado quando uma nova vela/barra fecha (ideal para estratégias baseadas no tempo).
1 2 3 4 | |
Métodos personalizados ou auxiliares
Para evitar reescrever e duplicar código, pode definir os seus próprios métodos. Tais métodos personalizados devem encapsular lógica comum que o seu robô de negociação possa reutilizar.
O método abaixo retorna todas as posições abertas associadas à etiqueta do cBot atual, facilitando o acompanhamento ou o fecho de posições de forma consistente.
1 2 | |
Considere outro método que calcula a distância em pips entre o preço atual e a entrada da posição, o que é crítico para decisões em estratégias baseadas em grelha.
1 2 | |
Uma vez que um método tenha sido definido, pode chamá-lo de dentro da mesma classe usando a palavra-chave self. Esta abordagem permite-lhe reutilizar a lógica em qualquer parte do seu bot sem duplicar código.
Por exemplo, após definir get_bot_positions(), pode chamá-lo dentro de outro método para fechar todas as posições:
1 2 3 4 | |
Aqui, self.get_bot_positions() invoca o método auxiliar, retornando apenas as posições ligadas à etiqueta do bot atual.
Da mesma forma, o método get_distance_in_pips() pode ser reutilizado para tomar decisões de negociação. Por exemplo, numa estratégia de grelha, pode querer abrir uma nova ordem apenas se o mercado se tiver movido o suficiente desde a última posição:
1 2 3 4 5 6 7 | |
Outros conceitos
Namespaces e importações
Os namespaces em Python ajudam a organizar o código e evitar colisões de nomes agrupando identificadores relacionados (variáveis, funções, classes). As importações permitem-lhe trazer módulos externos, bibliotecas ou pacotes para estender a funcionalidade além dos recursos padrão do Python.
Em Python, pode importar módulos padrão ou pacotes personalizados:
1 2 | |
Também pode importar funções ou classes específicas:
1 2 | |
Ao escrever algoritmos para o cTrader em Python, as importações funcionam um pouco diferente porque o cTrader integra-se com a API cTrader Algo baseada em .NET. Esta configuração envolve uma ponte que permite que o código Python interaja com assemblies .NET, e isso explica por que um cBot típico começa com:
1 2 3 4 5 6 7 8 9 | |
Onde:
import clrcarrega o Common Language Runtime (CLR), permitindo que o Python interopere com bibliotecas .NET.clr.AddReference("cAlgo.API")referencia o assembly da API cAlgo, que contém todas as classes, métodos e objetos relacionados à negociação.from cAlgo.API import *traz todos os tipos da API (por exemplo,TradeType,Color,Position).from robot_wrapper import *carrega funções auxiliares e wrappers que simplificam operações comuns de negociação.
O sistema de namespace garante que:
- Os nomes integrados do Python (como
print) evitam conflitos com os nomes do cTrader (comoapi.Print). - Todos os objetos específicos de negociação (
api.Symbol,api.Indicators,api.ExecuteMarketOrder) vêm do namespace da API cTrader Algo, mantendo-os organizados e distintos. - Pode estender a funcionalidade importando os seus próprios pacotes personalizados para trabalhar junto com os tipos integrados do cTrader.
Loops
Os loops permitem-lhe repetir operações sobre uma sequência de valores ou até que uma condição seja atendida. Na negociação algorítmica, os loops são frequentemente usados para processar posições (por exemplo, fechar, filtrar ou atualizá-las), verificar condições em vários ativos ou indicadores, implementar estratégias de grelha ou martingale onde é necessária a colocação repetida de ordens e muito mais.
Em Python, a iteração é simples e suporta tanto loops for (para iterar através de coleções) quanto loops while (para repetir até que uma condição mude).
Pode escrever um loop para fechar posições:
1 2 3 4 | |
Neste caso:
self.get_bot_positions()retorna todas as posições pertencentes ao cBot atual.- O loop
forpercorre cada posição. - As posições correspondentes são fechadas com
api.ClosePosition.
Considere um loop diferente que itera sobre todas as posições de grelha abertas, fecha-as uma a uma e verifica recursivamente se restam posições (segurança em caso de fechamentos parciais).
1 2 3 4 5 6 | |
Declarações condicionais
As declarações condicionais controlam o fluxo de execução em Python, permitindo que o seu algoritmo tome decisões com base em expressões lógicas. Os condicionais são a espinha dorsal da lógica da estratégia, determinando quando entrar, sair ou gerir posições.
O Python suporta três construções condicionais principais:
if– executa o código quando a condição é verdadeira.elif(else if) – verifica outra condição se a primeira for falsa.else– fornece uma alternativa quando nenhuma condição é satisfeita.
Considere as condições de cruzamento do MACD expressas neste código:
1 2 3 4 | |
Esta estrutura:
- Coloca uma ordem de compra quando a linha MACD está acima da linha de sinal.
- Coloca uma ordem de venda quando a linha MACD está abaixo da linha de sinal.
- Ignora a negociação se não houver um sinal claro.
Listas
O Python fornece ferramentas poderosas e concisas para trabalhar com coleções de dados, como negociações, preços ou indicadores. Duas das mais comuns são as compreensões de lista e as funções de agregação incorporadas, como sum().
Por exemplo, pode escrever um código que itera sobre numbers e mantém apenas números pares desta forma:
1 2 | |
Pode usar uma compreensão de lista para selecionar apenas posições para o símbolo atual, produzindo uma lista filtrada que é útil em ambientes multi-símbolo.
1 | |
Agregar lucro ou volume usando sum() é uma abordagem padrão em estratégias de negociação em grelha para determinar quando o lucro total atinge o objetivo.
1 | |
Pode combinar filtragem e agregação desta forma:
1 2 | |
Operações síncronas e assíncronas
O Python segue um modelo de execução síncrono por padrão. Os métodos do ciclo de vida do seu algoritmo, como on_start, on_tick e on_bar_closed, são acionados pelo loop de eventos da plataforma, um de cada vez.
Aqui está uma representação básica de um fluxo de negociação síncrono:
graph TD
A(Encontrar um sinal) ==> B(Executar uma ordem)
B ==> C(A posição atinge um TP/SL)
C ==> D(Fechar a posição)
D ==> A Em fluxos síncronos, qualquer operação de longa duração pode bloquear o thread, potencialmente atrasando o próximo evento. No entanto, em estratégias do mundo real, os algoritmos normalmente iniciam ações não bloqueantes, como submeter uma ordem ou definir stop-loss e take-profit, e depois esperam por eventos futuros (como um novo tick ou barra) para lidar com os resultados. Esta configuração resulta numa orquestração semelhante à assíncrona, mesmo que as construções async/await do Python não sejam utilizadas.
Nota
Para a maioria dos algoritmos de negociação, a programação assíncrona explícita é desnecessária.
O cTrader gere a concorrência serializando os seus callbacks baseados em eventos. Cada método é invocado independentemente e nunca em paralelo, eliminando a necessidade de salvaguardas de multithreading. Este design permite que as estratégias respondam a múltiplas condições de negociação ao mesmo tempo, num sentido lógico, sem bloqueio.
No exemplo abaixo, a estratégia avalia sinais de compra e venda independentemente e responde em conformidade, sem qualquer sobreposição no contexto de execução.
graph TD
A([Detectar um sinal]) ==> B([Abrir uma ordem de compra]) & C([Abrir uma ordem de venda <br>para hedge]) ==> D([Uma ordem atinge o<br>take profit ou stop loss])
D ==> E([Fechar a posição])
E ==> A Embora as decisões possam parecer estar em paralelo, são tratadas sequencialmente pelo sistema de fila interno do cTrader. A arquitetura da plataforma visa prevenir problemas de concorrência, mantendo os robôs de negociação responsivos às mudanças do mercado.
