14 minutos de leitura

Ordens no MetaTrader 5: Posições e Histórico

Por Rodrigo Vanzelotti
Conteúdos do artigo

Como um trader quantitativo, é necessário saber analisar séries temporais, extrair valor de dados, enviar ordens de compra e venda, verificar os parâmetros necessários, entre outros aspectos.

No entanto, tão importante quanto todos esses atributos é a habilidade de checar as ordens já realizadas, as posições abertas e abduzir de maneira conclusiva a qualidade de uma série de trades para validar uma estratégia.

Funções básicas – Contagens

Existem algumas funções básicas que podem auxiliar no processo de análise de ordens roteadas pelo MT5 utilizando Python. São elas:

  • orders_total(): Sem parâmetros
  • positions_total(): Sem parâmetros
  • history_orders_total(date_from, date_to): Parametrização por data inicial e data final
  • history_deals_total(date_from, date_to): Parametrização por data inicial e data final

Essas funções com o sufixo “total”, dado alguns parâmetros diferentes para cada, retornam apenas um valor inteiro, computando todas as situações específicas requeridas a partir do nome da função, algo bem intuitivo. Apenas as funções que contêm “history” necessitam dos parâmetros de data no formato datetime.

Segue abaixo um exemplo básico de como utilizar cada uma das funções, utilizando as variáveis “date_from” e “date_to” previamente definidas:

import MetaTrader5 as mt5
import datetime
import pandas as pd
date_from = datetime(2020,1,1) 
date_to = datetime.now()
# Todas as funções aqui retornarão um inteiro
mt5.orders_total()                              # Total de ordens
mt5.positions_total()                           # Total de posições abertas
mt5.history_orders_total(date_from, date_to)    # Total de ordens no histórico de negociação
mt5.history_deals_total(date_from, date_to)     # Total de transações no histórico de negociação (deals)

Como consultar posições específicas

Há quatro formas diferentes de consultar as posições abertas, e é importante observar que há um padrão que se repete nas requisições seguintes:

  • Sem parâmetros: retorna posições abertas de todos os símbolos
  • Symbol: consulta por ação específica
  • Group: consulta por agrupamento de ações e partir de um filtro aplicado
  • Ticket: consulta pelo número de ordem

Utilizando a função mt5.positions_get() com a parametrização escolhida, teremos o retorno das posições abertas na estrutura de tuplas nomeadas. Em caso de erro, a função deve retornar None, mas é sempre bom lembrar que podemos extrair o último erro do programa utilizando a função mt5.last_error().

Seguem alguns exemplos da utilização da função:

# definimos o ativo de análise
ativo = "ITUB4"
# chamamos a função e checamos se há retorno em um teste de pesquisa por ativo
positions=mt5.positions_get(symbol=symbol)
if positions == None:
    print(f"Sem positions em {symbol}, error code={mt5.last_error()}")
else:
    # imprimimos todas as posições abertas
    print(f"Total de positions com ITUB4 = {len(positions)}")
    for position in positions:
        print(position)

Primeiro, um exemplo de pesquisa por nome de ativo; na sequência, um exemplo de pesquisa por grupo de ativos. Nesse caso queremos achar uma lista de posições com base em ativos cujos nomes contenham “USD”.

# definimos o grupo de pesquisa
group_search = "*USD*"
# obtemos uma lista de posições com base em símbolos cujos nomes contenham "*USD*"
usd_positions=mt5.positions_get(group="group_search")
if usd_positions==None:
    print(f"Sem positions com o parâmetro group={group_search}, error code={mt5.last_error()}")
else:
    print(f"positions_get(group={group_search})={len(usd_positions)}")
    # exibimos essas posições como uma tabela usando pandas.DataFrame
    df=pd.DataFrame(list(usd_positions),columns=usd_positions[0]._asdict().keys())
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.drop(['time_update', 'time_msc', 'time_update_msc', 'external_id'], axis=1, inplace=True)

Como conclusão, geramos um DataFrame para armazenar os dados.

Lembrando que a pesquisa por grupo permite várias condições separadas por vírgulas. A condição pode ser especificada como uma máscara usando ‘*’, e para exclusões, pode-se usar o símbolo de negação lógica ‘!’. Nesse caso, todas as condições são aplicadas sequencialmente, ou seja, primeiro deve-se especificar as condições para inclusão no grupo e, em seguida, a condição de exclusão. Por exemplo, *group*=”*, !ITUB” significa que primeiro é necessário selecionar as posições de todos os símbolos e, em seguida, excluir as que contêm o símbolo “ITUB” no nome.

A outra maneira possível de pesquisa é por número de ordem, o que necessita de um número específico de operação, porém o padrão seria:

numero_do_ticket = 0000000       # número coletado da ordem  mt5.positions_get(ticket=numero_do_ticket)

Como consultar ordens a partir de datas e grupos

A consulta de ordens segue o mesmo padrão de pesquisa apresentada nas posições: por symbol, group ou ticket. Os padrões de códigos também são extremamente semelhantes.

A principal diferença é que, para isso, utilizaremos a função mt5.orders_get(), que junto aos principais parâmetros, retorna as informações das ordens filtradas em uma estrutura de tuplas nomeadas. Em caso de erro, deve retornar None (o que devemos verificar no nosso código).

# definimos o ativo de análise
ativo = "ITUB4"
# exibimos informações sobre ordens ativas do símbolo ITUB4
orders=mt5.orders_get(symbol="ITUB4")
if orders is None:
    print(f"Sem orders em ITUB4, error code={mt5.last_error()}")
else:
    print(f"Total orders em ITUB4: {len(orders)}")
    # exibimos todas as ordens ativas
    for order in orders:
        print(order)
# definimos o grupo de pesquisa
group_search = "*USD*"
# obtemos uma lista de ordens com base em símbolos cujos nomes contenham "*BRL*"
gbp_orders=mt5.orders_get(group=group_search)
if gbp_orders is None:
    print(f"No orders with group={group_search}, error code={mt5.last_error()}")
else:
    print(f"orders_get(group={group_search})={len(gbp_orders)}")
    # exibimos essas posições como uma tabela usando pandas.DataFrame
    df=pd.DataFrame(list(gbp_orders),columns=gbp_orders[0]._asdict().keys())
    df.drop(['time_done', 'time_done_msc', 'position_id', 'position_by_id', 'reason', 'volume_initial', 'price_stoplimit'], axis=1, inplace=True)
    df['time_setup'] = pd.to_datetime(df['time_setup'], unit='s')

Como consultar Ordens Abertas

Para solicitar ordens que estejam abertas (ou somente ordens), é necessário utilizar a função mt5.history_orders_get(), que obtém o histórico de negociação com a capacidade de filtrar por número de ordem ou posição.

Nesse caso, temos três variantes de chamada da função, sendo que uma delas indica o intervalo de tempo mais um filtro de group, no formato:

history_orders_get(
   date_from,           # data a partir da qual são solicitadas as ordens [datetime]
   date_to,             # data segundo a qual são solicitados os ticks [datetime]
   group="GROUP"        # filtro para selecionar ordens por símbolos
   )

Outra chamada que requer o número da position da ordem:

history_orders_get(
   position=POSITION    # posição
)

E a última que indica o ticket da ordem requerida:

history_orders_get(
   ticket=TICKET        # número da ordem
)

E a última por grupo de ativos:

# definimos o grupo de pesquisa
group_search = "*USD*"
history_orders=mt5.history_orders_get(from_date, to_date, group=group_search)
if history_orders==None:
    print(f"Sem history orders com o group={group_search}, error code={mt5.last_error()}")
elif len(history_orders)>0:
    print(f"history_orders_get({from_date}, {to_date}, group={group_search})={len(history_orders)}")

Como consultar Negociações Executadas

Consultar suas negociações executadas (deals) é um importante passo para identificar seu desempenho passado.

Como o nome da função mt5.history_deals_get() indica, o retorno que teremos nessa operação é um registro de todas as negociações anteriores que foram feitas em uma determinada conta no MetaTrader5. A mesma função permite filtrar por intervalo de tempo especificado, por número de ordem, posição e agrupamento.

As lógicas de filtros e agrupamentos seguem o mesmo padrão de todas funções apresentadas aqui e assim como no anterior, nosso retorno será uma namedtuple ou tupla nomeada. Segue um retrato do uso da função, filtrando por deals que não envolvam “EUR” ou “GBP”, realizando o filtro por agrupamento e data.

# definimos o grupo de pesquisa
group_search = "*,!*EUR*,!*GBP*"
# obtemos transações cujos símbolos não contêm "EUR" nem "GBP"
deals = mt5.history_deals_get(from_date, to_date, group=group_search)
if deals == None:
    print(f"Sem deals, error code={mt5.last_error()}")
else:
    print(f"history_deals_get(from_date, to_date, group={group_search}) = {len(deals)}")
    # exibimos todas as transações recebidos como estão
    for deal in deals:
        print("t", deal)
    # exibimos essas transações como uma tabela usando DataFrame
    df=pd.DataFrame(list(deals),columns=deals[0]._asdict().keys())
    df['time'] = pd.to_datetime(df['time'], unit='s')
    print(df)

É possível também verificar nossas negociações utilizando uma position específica, requerida anteriormente pela função mt5.positions_get().

# obtemos todas as transações que pertencem à posição 530218319
position_id=530218319
position_deals = mt5.history_deals_get(position=position_id)
# checando se existem position_deals
if position_deals == None:
    print(f"Sem deals com a position #{position_id}")
    print(f"error code = {mt5.last_error()}")
elif len(position_deals) > 0:
    print(f"Deals com a position id #{position_id}: {len(position_deals)}")
    # exibimos essas transações como uma tabela usando DataFrame
          df=pd.DataFrame(list(position_deals),columns=position_deals[0]._asdict().keys())
    df['time'] = pd.to_datetime(df['time'], unit='s')
    print(df)

Position x Deal x Order

Até aqui, é possível que exista uma certa confusão em relação aos termos apresentados. Inclusive, é bem comum que haja um conflito breve sobre três termos principais apresentados até aqui: Position, deal e order. Vamos a um breve resumo de cada um deles.

  • ORDER: A ordem é usada apenas para enviar a solicitação ao mercado. Será uma ordem até que a plataforma a abra. Você ordenou à plataforma que comprasse um ativo X, não significa que ela iniciou o processo de compra.
  • POSITION: Depois, o pedido de abertura se torna uma posição (um para conta de compensação [netting account] ou muitos para conta de cobertura [hedging account])
  • DEAL: Após o fechamento da posição (por mercado ou manualmente), ela se torna um negócio e pode ser recuperada do histórico de negócios [mt5.history_deals_get()].

Ordens pendentes fechadas antes de atingir as condições de mercado também se tornam negócios (deals).

Inscreva-se gratuitamente e fique atualizado

Receba toda semana um resumo dos principais conteúdos da Asimov direto no seu e-mail. 100% livre de spam.

Áreas de interesse:
Conteúdos do tutorial