Análise de gráficos de Balanço/Capital líquido ("equity") de acordo com os símbolos e Expert Advisors ORDER_MAGIC
Vladimir Karputov | 29 maio, 2017
Conteúdo
- Estabelecimento de objetivos
- 1. Comissão, Swap, Lucro
- 2. Cálculo de Capital líquido ("equity") e balanço no histórico
- 2.1. Lista "Posições abertas"
- 2.2. Fórmula de lucro flutuante
- 2.3. Seguro: todos os símbolos disponíveis
- 2.4. Monitoramento de posições abertas e fechadas no histórico
- 2.5. Como calcular o lucro flutuante (Capital líquido ("equity"))
- 3. Integramos o Expert Advisor no painel de diálogo
- 3.1. Vista geral do painel de diálogo
- 3.2. Interação com o painel
- 3.3. Pequeno ajuste no monitoramento do magic selecionado
- 4. Gráficos de distribuição MFE e MAE
- Conclusão
Estabelecimento de objetivos
Introduzida a cobertura no MetaTrader 5, surgiu a grande possibilidade de negociar simultaneamente usando Expert Advisors (ou várias estratégias) numa só conta de negociação. No serviço Sinais, é possível monitorizar toda a conta de negociação e obter estatísticas graças a ele. Há uma questão muito importante para mim que ainda permanece sem solução, isto é, como visualizar a contribuição de cada estratégia para os gráficos de Balanço e Capital líquido?
Afinal, na negociação é muito provável de acontecer uma primeira estratégia rentável, uma segunda não-rentável, e, como resultado, o monitoramento exiba uma turbulência perto do zero. Nesse caso, é altamente desejável construir gráficos de Balanço e Capital líquido ("equity") para cada estratégia de negociação separadamente.
1. Comissão, Swap, Lucro
O resultado financeiro total da transação é gerado pela soma de três parâmetros:
Result=Deal commission +Cumulative swap on close+ Deal profit
Estas propriedades de transação são preparadas pelo HistoryDealGetDouble() com os seguintes identificadores:
DEAL_COMMISSION |
Deal commission |
double |
DEAL_SWAP |
Cumulative swap on close |
double |
DEAL_PROFIT |
Deal profit |
double |
Exemplo de obtenção de propriedades de transação a partir do histórico de negociação para o período especificado no script "HistoryDealGetTicket.mq5".
Resultados do script (excluídas as transações com o tipo DEAL_ENTRY_IN, já que não há resultado financeiro nelas):
... 4: deal #36774600 at 2017.02.15 10:17:50 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 1.52 NZDUSD.m (order #47802989, position ID 47770449) ... 12: deal #36798157 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.01 profit: 2.98 EURUSD.m (order #47827771, position ID 47685190) 13: deal #36798161 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.02 profit: 5.99 EURUSD.m (order #47827785, position ID 47665575) 14: deal #36798176 at 2017.02.15 16:44:17 Entry out, buy vol: 0.01 comm: 0 swap: -0.02 profit: 5.93 EURUSD.m (order #47827805, position ID 47605603) 15: deal #36798185 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.03 profit: 5.98 EURUSD.m (order #47827821, position ID 47502789) 16: deal #36798196 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.03 profit: 8.96 EURUSD.m (order #47827832, position ID 47419515) 17: deal #36798203 at 2017.02.15 16:44:18 Entry out, buy vol: 0.01 comm: 0 swap: -0.06 profit: 8.92 EURUSD.m (order #47827835, position ID 47130461) 18: deal #36798212 at 2017.02.15 16:44:19 Entry out, sell vol: 0.01 comm: 0 swap: -0.48 profit: -21.07 EURUSD.m (order #47827845, position ID 46868574) ... 25: deal #36824799 at 2017.02.15 19:57:57 Entry out, sell vol: 0.01 comm: 0 swap: 0 profit: 2.96 NZDUSD.m (order #47855548, position ID 47817757) 26: deal #36824800 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0 profit: 3.01 NZDUSD.m (order #47855549, position ID 47790966) 27: deal #36824801 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 3.07 NZDUSD.m (order #47855550, position ID 47777495) 28: deal #36824802 at 2017.02.15 19:57:58 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 3 NZDUSD.m (order #47855551, position ID 47759307) 29: deal #36824803 at 2017.02.15 19:57:59 Entry out, sell vol: 0.01 comm: 0 swap: 0.02 profit: 1.52 NZDUSD.m (order #47855552, position ID 47682775) ... 33: deal #36832775 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 2.96 NZDUSD.m (order #47863883, position ID 47826616) 34: deal #36832776 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 3.05 NZDUSD.m (order #47863884, position ID 47803010) 35: deal #36832777 at 2017.02.16 00:58:41 Entry out, sell vol: 0.01 comm: 0 swap: 0.05 profit: 2.98 NZDUSD.m (order #47863885, position ID 47792294) 36: deal #36832778 at 2017.02.16 00:58:42 Entry out, sell vol: 0.01 comm: 0 swap: 0.07 profit: 2.88 NZDUSD.m (order #47863886, position ID 47713741) ...
Como você pode ver, o swap e o lucro podem ter tanto o sinal "+" quanto o sinal "-". Portanto, na fórmula do resultado financeiro final, para o swap e lucro, são usados outros mais complicados.
2. Cálculo de Capital líquido ("equity") e balanço no histórico
Esquema de trabalho geral: geramos uma lista "posições abertas", dividimos o histórico de negociação em segmentos de 5-15 minutos (mais tarde, tiraremos dúvidas sobre esse parâmetro). Em seguida, sucessivamente, para cada segmento:
- buscamos transações de saída do mercado. Se forem encontrados esses tipos de transações, com base no resultado financeiro final delas, recalculamos o valor para os gráficos "Balanço" e "Capital líquido". Ajustamso a lista "Posições abertas".
- de acordo com as posições abertas calculamos o valor para o gráfico "Capital líquido".
Para realizar a classe de inventário de posições abertas no intervalo selecionado, é necessária uma classe de transações. Implementamos isto na classe "CHistoryDeal" — no arquivo anexado "HistoryDeal.mqh":
Método | Valor |
---|---|
TicketDeal | Obtém/define a propriedade de transação "Bilhete de transação" |
PosIDDeal | Obtém/define a propriedade de transação "Identificador de posição" |
SymbolDeal | Obtém/define a propriedade de transação "Símbolo de transação" |
TypeDeal | Obtém/define a propriedade de transação "Tipo de transação" a partir da enumeração ENUM_DEAL_TYPE |
EntryDeal | Obtém/define a propriedade de transação "Direção de transação" a partir da enumeração ENUM_DEAL_ENTRY |
VolumeDeal | Obtém/define a propriedade de transação "Volume de transação" |
PriceDeal | Obtém/define a propriedade de transação "Preço de abertura de transação" |
2.2. Fórmula de lucro flutuante
Tomamos a fórmula de lucro na descrição da enumeração ENUM_SYMBOL_CALC_MODE. Ao fazer isto, sempre é necessário lembrar em qual moeda é calculado o lucro para esse instrumento. A moeda na qual é calculado o lucro das transações pode ser obtida:
- através da classe de negociação CSymbolInfo::CurrencyProfit
- acessando a propriedade do símbolo SymbolInfoString:
SymbolInfoString(m_name,SYMBOL_CURRENCY_BASE);
- ou simplesmente abrindo a especificação do símbolo no terminal:
Fig. 1. Especificação RTS-3.17
2.3. Seguro: todos os símbolos disponíveis
Possíveis problemas:
- o símbolo do histórico de negociação não está na "Observação do mercado" (a pesquisa continua segundo a lista de símbolos geral);
- a moeda de lucro do símbolo não pode ser recalculada na moeda do depósito, ou seja, na "Observação do mercado" não há nenhum símbolo para a recálculo.
Para o monitoramento de possíveis erros, no EA, no nível das variáveis globais do programa (atenção do programa, e não do terminal!), é introduzida a matriz para os símbolos "maus" ausentes na "Observação do mercado" ou para os quais é impossível recalcular a moeda de lucro na moeda do depósito:
string m_arr_defective_symbols[]; // array for defective symbols
Sequência para passar pela cobertura de seguros (todas as fases ocorrem na função "SearchDefectiveSymbols"):
- criamos uma matriz temporária (auxiliar) a partir de todos os símbolos disponíveis na "Observação do mercado";
- criamos uma matriz temporária (auxiliar) a partir de todos os símbolos do histórico de negociação (no intervalo de datas especificado de ... a ... );
- procuramos os símbolos a partir do histórico de negociação na "Observação do mercado". Se qualquer um dos símbolos não existir, ele será armazenado numa matriz de símbolos "maus";
- adicionamos (exibimos) os símbolos do histórico de negociação à "Observação do mercado". Se a operação falhar, o símbolo será armazenado na matriz de símbolos "maus";
- a partir das propriedades do símbolo obtemos a moeda de lucro. Se a moeda de lucro do símbolo for diferente da moeda de depósito, passaremos para a subseção 5.1.
- Estamos tentando encontrar na "Observação do mercado" um símbolo - para recálculo - que corresponda à "moeda de depósito" + "moeda de lucro" ou "moeda de lucro" + "moeda depósito." Se a operação falhar, o símbolo será armazenado na matriz de símbolos "maus"
Processada a função "SearchDefectiveSymbols", será formada a matriz com símbolos "maus" a partir do histórico de negociação. Nos cálculos futuros (ao calcular o gráfico "Balanço" e o gráfico "Capital líquido"), os "maus" símbolos não participarão mais.
2.4. Monitoramento de posições abertas e fechadas no histórico
Exibimos na matriz bidimensional "m_arr_balance_equity" todas as alterações do balanço.
Pedimos o histórico no intervalo das datas "from date" e "to date" (trata-se do parâmetro de entrada do Expert Advisor) e dividimo-lo pelo número de ciclos cuja duração seja "timer (minutes)". O trabalho é realizado na função "CreateBalanceEquity". Registramos todas as transações na matriz dinâmica de ponteiros "ArrOpenPositions". Depois trabalhamos com esta matriz, isto é, adicionamos e excluímos transações.
Dependendo do parâmetro de transação de negociação "Direção da transação" — ENUM_DEAL_ENTRY — estimaremos de maneiras diferentes os gráficos "Balanço" e "Capital líquido" ("equity"). Se - nas contas de cobertura e de compensação - você quiser verificar o comportamento de abertura, fechamento, fechamento parcial ou inversão de posições, você pode executar o script "HistorySelect.mq5".
- DEAL_ENTRY_IN — Entrar no mercado. Registramos a transação na matriz "ArrOpenPositions"
- DEAL_ENTRY_OUT — Sair do mercado. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se a busca retornar false, não realizaremos alterações no gráficos "Balanço" e "Capital líquido ("equity")"
- se a busca retornar true, verificaremos o volume (em lotes)
- se os volumes forem iguais, removeremos a transação na matriz "ArrOpenPositions" e faremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
- se o volume da transação na matriz "ArrOpenPositions" for maior, ajustaremos o volume da transação na matriz "ArrOpenPositions" e realizaremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
- se o volume da transação na matriz "ArrOpenPositions" for menor, apagaremos a transação na matriz "ArrOpenPositions" e realizaremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
- DEAL_ENTRY_INOUT — Inversão. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se a busca retornar false, não realizaremos alterações no gráficos "Balanço" e "Capital líquido" ("equity")
- se a busca retornar true, ajustaremos o volume de transação na matriz "ArrOpenPositions", ajustaremos o tipo de transação na matriz "ArrOpenPositions" e realizaremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
- DEAL_ENTRY_OUT_BY — Fechamento usando a posição oposta. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se os volumes forem iguais, removeremos a transação na matriz "ArrOpenPositions" e realizaremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
- se os volumes forem diferentes, ajustaremos o volume de transação na matriz "ArrOpenPositions" e realizaremos alterações na coluna "Balanço" (matriz "m_arr_balance_equity")
2.5. Como calcular o lucro flutuante (Capital líquido ("equity"))
É necessário percorrer toda a matriz "ArrOpenPositions" e calcular o lucro flutuante de todas as transações na matriz. Se a transação se encontrar a matriz "ArrOpenPositions", teremos os seguintes dados para cada transação, dos quais precisaremos:
- símbolo
- tipo (BUY or SELL)
- volume
- preço (preço pelo qual a transação foi aberta)
Também temos uma data final em que pedido o histórico de negociação. Só faltam os preços do símbolo da transação para a data final, na qual solicitado o histórico de negociação. Obteremos o preço usando CopyTicks em "CalculationFloatingProfit". Lembre-se que tomaremos as formulas de lucro na descrição da enumeração ENUM_SYMBOL_CALC_MODE.
No processo de criação de perfis, descobriu-se que o método CopyTicks é muito demorado, especialmente quando na matriz "CalculationFloatingProfit" existem várias transações para um único símbolo. Nesses casos, verifica-se que serão solicitados os mesmos dados várias vezes, quer dizer, o símbolo é o mesmo e a data é a mesma. Para acelerar, foram introduzidos os resultados de cache CopyTicks
//--- caching results "CopyTicks" static string arr_name[]; static double arr_ask[]; static double arr_bid[]; static datetime prev_time=0; int number=-1; if(time>prev_time) { prev_time=time; ArrayFree(arr_name); ArrayFree(arr_ask); ArrayFree(arr_bid); } found=false; size=ArraySize(arr_name); if(size>0) for(int i=0;i<size;i++) { if(name==arr_name[i]) { number=i; found=true; break; } } if(found) { ArrayResize(ticks_array,1); ticks_array[0].ask=arr_ask[number]; ticks_array[0].bid=arr_bid[number]; } else { //--- int copy_ticks=-1; int count=0; while(copy_ticks==-1 && count<5) { copy_ticks=CopyTicks(name,ticks_array,COPY_TICKS_INFO,1000*(ulong)time,1); //if(copy_ticks==-1)
— os resultados bid e ask são armazenados nas matrizes locais: se, num intervalo de tempo, para o símbolo, forem obtidos os ticks, estes ticks são tomados a partir das matrizes locais. Esta abordagem permite acelerar o trabalho 10-15 vezes.
3. Integramos o Expert Advisor no painel de diálogo
Agora, que a base do Expert Advisor é operável, é possível proporcionar ao Expert Advisor uma interface fácil de usar. A partir do título do artigo "Análise de gráficos de Balanço/Capital líquido ("equity") de acordo com os símbolos e Expert Advisors ORDER_MAGIC", devem existir alguns recursos de filtragem:
- mostrar todos os símbolos/mostrar um ou mais dos símbolos selecionados;
- mostrar em todos os magics/mostrar apenas num ou vários dos símbolos selecionados.
Para cálculo de todos os símbolos de negociação, temos a matriz "m_arr_all_trade_symbols". Ela é declarada ao nível de programa global. É necessário introduzir mais uma matriz — "m_arr_all_magics" — para calcular todos os magics. Para fazer isto, atualizamos a função "FillArrayTradeSymbols", agora nela será preenchida mais uma matriz "m_arr_all_magics".
3.1. Vista geral do painel de diálogo
Fig. 2. Vista geral do painel
Após a formação de matrizes de símbolos "maus", de todos os símbolos de negociação e magics, no painel são preenchidas duas listas (elementos com base na classe CComboBox): a lista esquerda contém todos os símbolos de negociação, a lista da direita, todos os magics. No primeiro lugar das listas, aparece a escolha de todos os símbolos e todos os magics:
Fig. 3. Listas suspensas
O Expert Advisor no painel terá a seguinte lógica: só após pressionado o botão "Start", verificar-se-á se foi selecionado nas duas listas suspensas. Dependendo dos parâmetros selecionados, nestas listas será realizada a plotagem dos gráficos de Balanço / Capital líquido ("equity") com base no histórico de negociação.
Achei que a transferência de todo o código do Expert Advisor para a classe do painel ("APHDialog.mqh") leva muito tempo. A solução alternativa consiste em introduzir as variáveis internas m_ready, m_symbol e m_magic na classe do painel:
//+------------------------------------------------------------------+ //| Class CAPHDialog | //| Usage: main dialog of the Controls application | //+------------------------------------------------------------------+ class CAPHDialog : public CAppDialog { private: CLabel m_label_symbols; // the label object CComboBox m_combo_box_symbols; // the combo boxp object CLabel m_label_magics; // the label object CComboBox m_combo_box_magics; // the combo box object CButton m_button_start; // the button object //--- bool m_ready; // true -> you can build graphics string m_symbol; ulong m_magic; public:
Será durante o processamento de clique no botão "Start" que será tomada a decisão sobre o estado da variável m_ready:
//+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void CAPHDialog::OnClickButtonStart(void) { if(m_combo_box_symbols.Select()!=" " && m_combo_box_magics.Select()!=" ") m_ready=true; else m_ready=false; //Comment(__FUNCTION__+" ButtonStartclick"+"\n"+ // "Symbols: "+"\""+m_combo_box_symbols.Select()+"\""+"\n"+ // "Magic: "+"\""+m_combo_box_magics.Select()+"\""+"\n"+ // "m_ready: "+IntegerToString(m_ready)); }
Observe que, na cadeia de caracteres selecionada, imediatamente após criar e preencher as listas suspensas (no nosso caso, são os elementos m_combo_box_symbols e m_combo_box_magics), nas listas é definido o elemento com valor " ", ou seja, um caractere de tabulação.
Será durante o processamento de clique nas listas suspensas adequadas que será tomada a decisão sobre o estado das variáveis m_symbol e m_magic:
//+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void CAPHDialog::OnChangeComboBoxSymbols(void) { //Comment(__FUNCTION__+" \""+m_combo_box_symbols.Select()+"\""); if(m_combo_box_symbols.Select()=="All symbols") m_symbol=""; else m_symbol=m_combo_box_symbols.Select(); } //+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void CAPHDialog::OnChangeComboBoxMagics(void) { //Comment(__FUNCTION__+" \""+m_combo_box_magics.Select()+"\""); if(m_combo_box_magics.Select()=="All magics") m_magic=-1; else m_magic=StringToInteger(m_combo_box_magics.Select()); }
Assim, após um clique no botão "Start" serão preenchidas três variáveis, isto é: m_ready, m_symbol e m_magic. Resta descobrir como informar ao Expert Advisor que no painel realizada a seleção de parâmetros. A solução é simples: no EA, executamos um temporizador, a intervalos de 3 segundos, que consultará o painel. Para este fim, no painel escrevemos o método "CAPHDialog::IsReady"
//+------------------------------------------------------------------+ //| On the panel there are chosen parameters | //+------------------------------------------------------------------+ bool CAPHDialog::IsReady(string &symbol,ulong &magic) { if(m_ready) { symbol=m_symbol; magic=m_magic; m_ready=false; return(true); } else return(false); }
Neste método, registramos o valor das variáveis internas nas variáveis enviadas segundo referência e redefinimos a variável interna m_ready.
3.3. Pequeno ajuste no cálculo do magic selecionado
Seleção de transações ocorre de acordo com as condições especificadas, isto é: segundo símbolo ou todos os símbolos, ora segundo magic ou todos os magics, no "GetHistory":
//--- for all deals for(int i=0;i<deals;i++) { deal_ticket = HistoryDealGetTicket(i); deal_position_ID = HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID); deal_symbol = HistoryDealGetString(deal_ticket,DEAL_SYMBOL); deal_type = (ENUM_DEAL_TYPE)HistoryDealGetInteger(deal_ticket,DEAL_TYPE); deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); deal_volume = HistoryDealGetDouble(deal_ticket,DEAL_VOLUME); deal_price = HistoryDealGetDouble(deal_ticket,DEAL_PRICE); deal_commission = HistoryDealGetDouble(deal_ticket,DEAL_COMMISSION); deal_swap = HistoryDealGetDouble(deal_ticket,DEAL_SWAP); deal_profit = HistoryDealGetDouble(deal_ticket,DEAL_PROFIT); deal_magic = HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); if(sSymbol!="") if(deal_symbol!=sSymbol) continue; if(uMagic!=ULONG_MAX) if(deal_magic!=uMagic) continue; //--- onle BUY or SELL
Note que, para a variável uMagic, o valor ULONG_MAX indica "todos magics", enquanto, para a variável sSymbol, o valor "" indica "Todos os símbolos".
Vídeo sobre a construção do balanço e lucro flutuante com base no histórico de negociação (em primeiro lugar para todos os símbolos, depois, apenas para um único símbolo):
Vídeo
4. Gráficos de distribuição MFE e MAE
Para cada posição aberta, durante sua existência, são registrados os valores de lucro máximo (MFE) e perda máxima (MAE). Estes indicadores caracterizam adicionalmente cada posição fechada através dos valores de potencial máximo não realizado e o risco máximo autorizado. Nos gráficos de distribuição MFE/Profit e MAE/Profit, a cada posição corresponde um ponto, na horizontal, é dado o valor do lucro/perda obtida, e, na vertical, os valores máximos mostrados quanto ao lucro potencial ("Maximum Favorable Excursion" MFE) e à perda potencial ("Maximum Adverse Excursion" MAE).
4.1. Principio de monitoramento de MFE e MAE
No nível global de programa, são declaradas duas matrizes, isto é, "m_arr_pos_id" para monitoramento de posições e "m_arr_mfe_mae" para inventário do MFE, resultado financeiro final e MAE:
long m_arr_pos_id[]; double m_arr_mfe_mae[][3]; // [][0] - mfe, [][1] - final financial result,[][2] - mae
Após isto, na matriz base "m_arr_mfe_mae", serão construídos os gráficos de dispersão de MFE e MAE.
As matrizes "m_arr_pos_id" - para inventário de posições - e "m_arr_mfe_mae" - para inventário de mfe - sempre têm o mesmo tamanho na primeira dimensão, assim, para posições com índice "i" (m_arr_pos_id[i]) sempre existirá a correspondência m_arr_mfe_mae[i][][][]. As dimensões destas duas matrizes são definidas em "GetHistory":
if(deal_symbol=="") DebugBreak(); ArrOpenPositions.Add(HistoryDeal); //--- mfe, mae int size=ArraySize(m_arr_pos_id); ArrayResize(m_arr_pos_id,size+1,10); ArrayResize(m_arr_mfe_mae,size+1,10); m_arr_pos_id[size]=deal_position_ID; // [][0] - mfe, [][1] - final financial result,[][2] - mae m_arr_mfe_mae[size][0]=0.0; m_arr_mfe_mae[size][1]=0.0; m_arr_mfe_mae[size][2]=0.0; continue; } //--- if(deal_entry==DEAL_ENTRY_OUT)
Função que é responsável pela monitoramento do lucro máximo e perda máxima para cada posição:
//+------------------------------------------------------------------+ //| Add Result Mfe Mae | //+------------------------------------------------------------------+ void AddResultMfeMae(const long pos_id,const double floating_profit,const double financial_result) { // [][0] - mfe (profit), [][1] - final financial result,[][2] - mae (loss) //--- search pos_id int position=-1; int size=ArraySize(m_arr_pos_id); for(int i=0;i<size;i++) if(m_arr_pos_id[i]==pos_id) { position=i; break; } if(position==-1) return; //--- if(floating_profit==0.0) return; if(floating_profit>0.0) // profit { if(m_arr_mfe_mae[position][0]<floating_profit) m_arr_mfe_mae[position][0]=floating_profit; } else // loss { if(m_arr_mfe_mae[position][2]>floating_profit) m_arr_mfe_mae[position][2]=floating_profit; } m_arr_mfe_mae[position][1]=financial_result; }
Aqui a regra é passar todos os três parâmetros. Ou seja, se nossa posição virtual ainda não se encontrar na lista de posições abertas "ArrOpenPositions" e seu lucro flutuante for igual a "-20.2", a chamada será algo do tipo:
AddResultMfeMae(pos_id,-20.2,0.0);
se nossa posição virtual ainda não se encontrar na lista de posições abertas "ArrOpenPositions" e seu lucro flutuante for igual a "+5.81", a chamada será algo do tipo:
AddResultMfeMae(pos_id,5.81,0.0);
se nossa posição virtual for excluída na lista de posições abertas "ArrOpenPositions" e seu resultado financeiro final for igual a "+3.06", a chamada será algo do tipo:
AddResultMfeMae(pos_id,0.0,-3.06);
Ou seja, se houver um lucro flutuante, o resultado financeiro final será igual a "0", se a posição for fechada, o lucro flutuante será igual a "0".
4.2. Processamento de posições
- DEAL_ENTRY_IN - Entrada no mercado. Registramos a transação na matriz "ArrOpenPositions". Criamos o novo elemento nas matrizes "m_arr_pos_id" e "m_arr_mfe_mae"
- DEAL_ENTRY_OUT - Saída do mercado. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se a busca retornar false, não realizaremos alterações no gráficos "Balanço" e "Capital líquido" ("equity")
- se a busca retornar true, verificaremos o volume (em lotes)
- se os volumes forem iguais, removeremos a transação na matriz "ArrOpenPositions" e faremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0][resultado financeiro final].
- se o volume da transação na matriz "ArrOpenPositions" for maior - ajustaremos o volume de transação na matriz "ArrOpenPositions" e realizaremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0] [resultado financeiro final].
- se o volume da transação na matriz "ArrOpenPositions" for inferior - excluiremos a transação na matriz "ArrOpenPositions" e realizaremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0] [resultado financeiro final].
- DEAL_ENTRY_INOUT - Inversão. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se a busca retornar false, não realizaremos alterações no gráficos "Balanço" e "Capital líquido" ("equity")
- se a busca retornar true, ajustarmos o volume da transação na matriz "ArrOpenPositions", ajustaremos o tipo de transação na matriz "ArrOpenPositions" e realizaremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0] [resultado financeiro final].
- DEAL_ENTRY_OUT_BY - Fechamento usando a posição oposta. Procuramos na matriz "ArrOpenPositions" a transação com o tipo DEAL_ENTRY_IN com o mesmo DEAL_POSITION_ID
- se os volumes forem iguais, removeremos a transação na matriz "ArrOpenPositions" e faremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0][resultado financeiro final].
- se os volumes forem diferentes, ajustaremos a transação na matriz "ArrOpenPositions" e faremos alterações na matriz "m_arr_balance_equity" - na coluna "Balanço". Na matriz "m_arr_mfe_mae" registramos [lucro flutuante 0.0][resultado financeiro final].
Além disso, em "GetHistory", se for necessário recalcular o lucro flutuante, para cada posição na matriz "m_arr_mfe_mae" registramos [lucro flutuante] [resultado financeiro final 0.0].
Para exibir o gráfico de Balanço / Capital líquido ("equity") e MFE e MAE, o painel evolui de forma:
Fig. 4. Painel modificado
Gráficos de MFE (lucro máximo) e de MAE (perda máxima) são baseados em duas coordenadas, isto é: coordenada "X" - valor do resultado financeiro final de posição, enquanto no eixo "Y" - valor de MFE ou de MAE, respectivamente.
Fig. 5. MFE
Fig. 6 MAE
Conclusão
Agora nas contas de cobertura ("hedge"), ao EAs negociarem simultaneamente, é possível visualizar as estatísticas do balanço e capital liquido ("equity") de cada símbolo e cada magic, quer dizer, identificar visualmente a contribuição de um determinado Expert Advisor (ORDER_MAGIC) para o balanço geral e, mais importante, qual o abaixamento em cada Expert Advisor.
Programas utilizados no artigo:
# |
Nome |
Tipo |
Descrição |
---|---|---|---|
1 |
HistoryDeal.mqh | Biblioteca | Classe de inventário de posições abertas no intervalo selecionado |
2 |
HistoryDealGetTicket.mq5 | Expert Advisor | Exemplo de obtenção de propriedades de transação a partir do histórico de negociação para o período especificado |
3 |
APHDialog.mqh | Biblioteca | Classe de painel de diálogo do Expert Advisor |
4 |
Accounting_positions_on_history.mq5 | Expert Advisor | Expert Advisor principal - com base no artigo |
5 |
MQL5.zip | Arquivo | Arquivo com o Expert Advisor principal e seus arquivos incorporados. |