preview
Simulação de mercado: Position View (XIII)

Simulação de mercado: Position View (XIII)

MetaTrader 5Testador |
128 0
Daniel Jose
Daniel Jose

Introdução

Olá pessoal, e sejam bem-vindos a mais um artigo da série sobre como construir um sistema de replay/simulação.

No artigo anterior Simulação de mercado: Position View (XII), fizemos algumas melhorias no indicador de posição. Estas visaram tornar o indicador bem mais interessante e agradável de ser utilizado. Porém, ainda não podemos considerar que temos algo, realmente prático em nossas mãos. Apesar de já termos algumas possibilidades que muitos poderiam imaginar ser algo extremamente difícil e complicado de ser implementado. E fizemos tudo isto de uma maneira bastante simples e agradável. Mas agora precisamos fazer algumas pequenas mudanças para tornar a coisa ainda mais interessante.

Mas não precisa se preocupar. Tais mudanças que serão feitas, serão bem simples de serem entendidas. Porém, elas abriram as portas para que possamos criar algo ainda mais elaborado e útil. Então vamos começar.


Removendo a classe C_IndicatorPosition

Antes de começarmos a efetuar, o que é o título deste tópico. Talvez seja interessante, para você, meu caro leitor e entusiasta. Entender por que de remover a classe C_IndicatorPosition do código final. O motivo é bastante simples: Evitar o uso de um salto extra entre o indicador e a classe C_ElementsTrade. Bem, é justo que você me questione, sobre o motivo de estar fazendo isto somente agora. E ele é bastante simples. Ainda não havia sido definido de que forma o indicador de posição iria de fato trabalhar. Assim para separar a implementação de possíveis falhas ou mudanças radicais. Ficou decidido deixar por um tempo a classe C_IndicatorPosition, como sendo uma intermediaria. Conforme pode ser visto na imagem abaixo.

Neste esquema visto acima, a linha preta, representa a comunicação existente entre o indicador e a classe C_IndicatorPosition. Já dentro da classe C_IndicatorPosition, temos três saídas, que são identificadas pelas linhas vermelha, azul e verde. Cada uma destas saídas representa um componente que deverá ser plotado no gráfico. Fazendo assim aparecer a linha de stop loss, preço de abertura e take profit respectivamente. Porém, apesar deste esquema ter sido bastante útil até o momento, a partir deste ponto, ele irá mais nos atrapalhar do que nos ajudar. Sendo assim, a classe C_IndicatorPosition, será removida do projeto. Contudo, o código atualmente presente na classe será transferido para dentro do código do indicador, conforme mostrado abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property icon "/Images/Market Replay/Icons/Positions.ico"
04. #property description "Indicator for tracking an open position on the server."
05. #property description "This should preferably be used together with an Expert Advisor."
06. #property description "For more details see the same article."
07. #property version   "1.125"
08. #property link "https://www.mql5.com/pt/articles/13356"
09. #property indicator_chart_window
10. #property indicator_plots 0
11. //+------------------------------------------------------------------+
12. #define def_ShortName "Position View"
13. //+------------------------------------------------------------------+
14. #include <Market Replay\Order System\C_ElementsTrade.mqh>
15. #include <Market Replay\Defines.mqh>
16. //+------------------------------------------------------------------+
17. input ulong user00 = 0;        //For Expert Advisor use
18. //+------------------------------------------------------------------+
19. struct st00
20. {
21.     ulong  ticket;
22.     string szShortName;
23. }m_Infos;
24. //+------------------------------------------------------------------+
25. C_ElementsTrade *Open = NULL, *Stop = NULL, *Take = NULL;
26. //+------------------------------------------------------------------+
27. bool CheckCatch(ulong ticket)
28. {
29.     ZeroMemory(m_Infos);
30.     m_Infos.szShortName = StringFormat("%I64u", m_Infos.ticket = ticket);
31.     if (!PositionSelectByTicket(m_Infos.ticket)) return false;
32.     if (ObjectFind(0, m_Infos.szShortName) >= 0)
33.     {
34.         m_Infos.ticket = 0;
35.         return false;
36.     }
37.     IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName);
38.     EventChartCustom(0, evUpdate_Position, ticket, 0, "");
39.             
40.     return true;
41. }
42. //+------------------------------------------------------------------+
43. int OnInit()
44. {
45.     IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
46.     if (!CheckCatch(user00))
47.     {
48.         ChartIndicatorDelete(0, 0, def_ShortName);
49.         return INIT_FAILED;
50.     }
51. 
52.     return INIT_SUCCEEDED;
53. }
54. //+------------------------------------------------------------------+
55. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
56. {
57.     return rates_total;
58. }
59. //+------------------------------------------------------------------+
60. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
61. {
62.     double value;
63.             
64.     if (Open != NULL) (*Open).DispatchMessage(id, lparam, dparam, sparam);
65.     if (Take != NULL) (*Take).DispatchMessage(id, lparam, dparam, sparam);
66.     if (Stop != NULL)    (*Stop).DispatchMessage(id, lparam, dparam, sparam);
67.     switch (id)
68.     {
69.         case CHARTEVENT_CUSTOM + evUpdate_Position:
70.             if (lparam != m_Infos.ticket) return;
71.             if (!PositionSelectByTicket(m_Infos.ticket))
72.             {
73.                 ChartIndicatorDelete(0, 0, m_Infos.szShortName);
74.                 return;
75.             };
76.             if (Open == NULL) Open = new C_ElementsTrade(m_Infos.ticket, evMsgClosePositionEA, clrRoyalBlue, StringFormat("%I64u : Position opening price.", m_Infos.ticket), PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
77.             if (Take == NULL) Take = new C_ElementsTrade(m_Infos.ticket, evMsgCloseTakeProfit, clrForestGreen, StringFormat("%I64u : Take Profit price.", m_Infos.ticket));
78.             if (Stop == NULL) Stop = new C_ElementsTrade(m_Infos.ticket, evMsgCloseStopLoss, clrFireBrick, StringFormat("%I64u : Stop Loss price.", m_Infos.ticket));
79.             (*Open).UpdatePrice(0, value = PositionGetDouble(POSITION_PRICE_OPEN));
80.             (*Take).UpdatePrice(value, PositionGetDouble(POSITION_TP));
81.             (*Stop).UpdatePrice(value, PositionGetDouble(POSITION_SL));
82.             break;
83.     }
84.     ChartRedraw();
85. };
86. //+------------------------------------------------------------------+
87. void OnDeinit(const int reason)
88. {
89.     delete Open;
90.     delete Take;
91.     delete Stop;
92. }
93. //+------------------------------------------------------------------+

Código fonte do Indicador de posição

Observem que tudo que estava em C_IndicatorPosition, agora está neste código visto acima. Assim o nosso esquema mudou do que era antes para este que é visto logo abaixo.

Ou seja, aparentemente as coisas ficaram mais simples. Porém olhando o código do indicador, parece ter ficado mais complicado. Mas estas duas sensações não são de fato o que está acontecendo. A coisa toda não ficou nem mais simples e tão pouco mais complicada. Apenas mudou a forma como estava sendo estruturada.

No entanto, esta mudança é necessária que venha a ser feita. Visto que agora, iremos adicionar elementos que precisam conversar diretamente com um dos componentes da posição. No caso específico, com o componente do preço de abertura. Mas o que iremos de fato fazer, que precisamos nos comunicar com o sistema presente no preço de abertura? Bem, esta é a parte legal, do que vamos fazer. Agora vamos adicionar a visualização dos valores que estão na posição. Ou seja, vamos fornecer ao operador, a visualização de valor ou número de ticks, que estamos tendo de lucro ou prejuízo. Assim o operador, poderá facilmente saber se é adequado fechar ou não a posição.

Hum, agora sim a coisa ficou bastante interessante. Mas será que não poderíamos fazer isto usando a classe C_IndicatorPosition? Na verdade poderíamos, mas ao meu ver não faz sentido, adicionar uma única função na classe, apenas para poder acessar o ponteiro Open. Que é justamente o usado para manter os objetos presentes no gráfico, que indicam onde a posição foi aberta. Acredito que você, meu caro leitor, deva ter compreendido os motivos da mudança. Então podemos partir para o próximo tópico.


Entendendo a indicação de lucro ou prejuízo

Neste momento, não vamos nos preocupar com muitas outras informações. Vamos focar apenas e somente nesta informação a ser mostrada para o usuário. Se a posição está dando lucro ou prejuízo. E em qualquer caso, qual é o valor financeiro ou em termos de pontos. Mas como o valor financeiro depende de outras modificações a serem feitas. Vamos primeiro focar nos valores em termos de pontos. Pois é consideravelmente mais simples de ser implementado logo de início.

Muito bem, agora vamos pensar um pouco. Como iremos capturar a informação do preço atual do ativo? Pois não adianta simplesmente usarmos a função OnCalculate, isto por que o operador, pode estar usando um sistema cross order. E neste caso a função OnCalculate pode não ser a ideal. Porém, temos que assumir que o operador, estará usando um ativo parecido. Como por exemplo, você pode decidir usar o histórico do dólar cheio, para poder operar o contrato atual do mini dólar. E este é um típico caso que as coisas não fugirão do controle.

Uma rápida explicação para quem não sabe do que acabei de falar. Na B3 ( Bolsa do Brasil ) existem contratos que não são negociáveis. Um caso é histórico dos contratos futuros. É muito comum, entre operadores profissionais, se usar o histórico para operar o contrato atualmente vigente. Isto para que o operador tenha uma noção de movimentos antigos do contrato. Mas existe uma outra classe de operação que podemos fazer uso também, a fim de tentar conseguir ter algum lucro em operação de bolsa. E esta outra classe exige que tenhamos a possibilidade de uso de um sistema cross order. Porém para quem opera pares de moedas, ou mais conhecido como FOREX, isto talvez não faça muito sentido.

No entanto, existe uma forma de você criar um gráfico de relação. E quando se faz uso de tal método dentro do FOREX, se torna necessário o uso do sistema cross order. Ou seja, o que estou explicando, pode lhe servir também, desde é claro você, meu caro leitor, saiba o que está fazendo. Mas vamos continuar, pois estas questões sobre modelos de operação serão em uma outra oportunidade no futuro. Por hora, vamos focar no presente.

Estão está decidido, vamos usar a função OnCalculate para nos mostrar se estamos tendo lucro ou prejuízo. Mas não podemos simplesmente usar o valor do preço atual. Se bem, que à primeira vista isto seria o mais adequado e o mais simples. No entanto, existe um problema em se fazer isto. Quero que você preste atenção ao que explicarei, pois é importante. Quando efetuamos uma compra, agredimos alguma ordem que está em ASK e quando efetuamos uma venda, agredimos alguma ordem que está em BID. Ok, então quando estamos comprados e vamos encerrar a posição, precisamos efetuar uma venda, e por consequência agredimos o BID. A mesma coisa vale para uma posição de venda. Pois quando vamos encerrar esta venda, precisamos efetuar uma compra e por isto agredimos alguma ordem em ASK.

No decorrer desta série de artigos sobre o replay/simulador. Mostrei que temos duas formas de plotagem. A plotagem LAST e a plotagem BID. Se você não sabe do que estou falando, leia os artigos anteriores, para entender o que estou explicando. Ok, independentemente do tipo de plotagem, o valor indicado no parâmetro price da função OnCalculate é sempre o valor do último preço. Se bem que isto pode ser modificado. Mas vamos desconsiderar a possibilidade de mudança. Já que o valor que nos interessa é o do último preço, e não de alguma média. Assim sendo, na plotagem LAST, o valor em price é o valor onde saiu o último negócio, podendo ser o BID ou ASK. Já na plotagem BID, o valor em price representa exatamente, e sempre o valor BID, ou seja, o valor do melhor comprador.

Então aqui temos o nosso primeiro problema. Pois normalmente a plotagem LAST é usada em contas do tipo NETTING. Já a plotagem BID normalmente é usada no FOREX. Muitos provavelmente vão pensar o seguinte: Cara por que complicar? Basta ler o valor da propriedade POSITION_PROFIT e lançar o valor no gráfico, em algum tipo de objeto de texto. Não precisa de toda esta complicação. De certa forma eu devo concordar. Porém, este tipo de abordagem pode gerar prejuízo quando você imaginava que estaria tendo um lucro. E o motivo disto tem um nome: SPREAD.

Talvez muitos de vocês não tem a devida noção de como POSITION_PROFIT é calculado. Mas o fato é que POSITION_PROFIT não leva em consideração o fato de você estar comprado ou vendido. E pior o cálculo não leva em consideração o SPREAD. E é este spread é que destrói completamente um patrimônio. Pois você começa a perder dinheiro sem se dar conta, achando que a corretora, ou sistema financeiro está se sacaneado. Pois você olha o valor POSITION_PROFIT imagina estar no lucro, fecha a posição e quando vai realmente ver a situação. Tem a terrível surpresa de ter tido prejuízo na operação.

Então esqueça o valor que estiver na propriedade POSITION_PROFIT. Vamos fazer o nosso próprio cálculo, baseado na nossa situação. Ou seja, se estamos comprados, vamos verificar o que acontece ao encerrarmos a posição agredindo o BID. E se estivermos vendidos o que acontece se agredimos o ASK. Por isto, se você for usar este indicador em um sistema cross order, peço para que você o use em um ativo de boa liquidez. Isto para que a variação dos valores venha a acompanhar o que de fato esteja acontecendo.


Adicionando a indicação de lucro ou prejuízo

Agora que expliquei o que iremos e por que iremos fazer o que faremos. Podemos começar a codificar as coisas. Vamos começar fazendo uma demonstração bem simples. E para que ela aconteça, é preciso modificar levemente o código do indicador. Abaixo você tem o novo código já modificado na íntegra.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. #property icon "/Images/Market Replay/Icons/Positions.ico"
004. #property description "Indicator for tracking an open position on the server."
005. #property description "This should preferably be used together with an Expert Advisor."
006. #property description "For more details see the same article."
007. #property version   "1.125"
008. #property link "https://www.mql5.com/pt/articles/13356"
009. #property indicator_chart_window
010. #property indicator_plots 0
011. //+------------------------------------------------------------------+
012. #define def_ShortName "Position View"
013. //+------------------------------------------------------------------+
014. #include <Market Replay\Order System\C_ElementsTrade.mqh>
015. #include <Market Replay\Defines.mqh>
016. //+------------------------------------------------------------------+
017. input ulong user00 = 0;        //For Expert Advisor use
018. //+------------------------------------------------------------------+
019. struct st00
020. {
021.     ulong   ticket;
022.     string  szShortName,
023.             szSymbol;
024.     double  priceOpen;
025.     bool    bIsBuy;
026. }m_Infos;
027. //+------------------------------------------------------------------+
028. C_ElementsTrade *Open = NULL, *Stop = NULL, *Take = NULL;
029. //+------------------------------------------------------------------+
030. bool CheckCatch(ulong ticket)
031. {
032.     ZeroMemory(m_Infos);
033.     m_Infos.szShortName = StringFormat("%I64u", m_Infos.ticket = ticket);
034.     if (!PositionSelectByTicket(m_Infos.ticket)) return false;
035.     if (ObjectFind(0, m_Infos.szShortName) >= 0)
036.     {
037.         m_Infos.ticket = 0;
038.         return false;
039.     }
040.     m_Infos.szSymbol = PositionGetString(POSITION_SYMBOL);
041.     IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName);
042.     EventChartCustom(0, evUpdate_Position, ticket, 0, "");
043.             
044.     return true;
045. }
046. //+------------------------------------------------------------------+
047. int OnInit()
048. {
049.     IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
050.     if (!CheckCatch(user00))
051.     {
052.         ChartIndicatorDelete(0, 0, def_ShortName);
053.         return INIT_FAILED;
054.     }
055. 
056.     return INIT_SUCCEEDED;
057. }
058. //+------------------------------------------------------------------+
059. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
060. {
061.     double ask, bid;
062.     
063.     ask = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_ASK);
064.     bid = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_BID);
065.     
066.     Comment(StringFormat("BID : %f  ||| ASK : %f  ||| PROFIT : %f", bid, ask, (m_Infos.bIsBuy ? bid - m_Infos.priceOpen : m_Infos.priceOpen - ask)));
067.     
068.     return rates_total;
069. }
070. //+------------------------------------------------------------------+
071. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
072. {
073.     if (Open != NULL) (*Open).DispatchMessage(id, lparam, dparam, sparam);
074.     if (Take != NULL) (*Take).DispatchMessage(id, lparam, dparam, sparam);
075.     if (Stop != NULL) (*Stop).DispatchMessage(id, lparam, dparam, sparam);
076.     switch (id)
077.     {
078.         case CHARTEVENT_CUSTOM + evUpdate_Position:
079.             if (lparam != m_Infos.ticket) return;
080.             if (!PositionSelectByTicket(m_Infos.ticket))
081.             {
082.                 ChartIndicatorDelete(0, 0, m_Infos.szShortName);
083.                 return;
084.             };
085.             if (Open == NULL) Open = new C_ElementsTrade(m_Infos.ticket, evMsgClosePositionEA, clrRoyalBlue, StringFormat("%I64u : Position opening price.", m_Infos.ticket), m_Infos.bIsBuy = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY));
086.             if (Take == NULL) Take = new C_ElementsTrade(m_Infos.ticket, evMsgCloseTakeProfit, clrForestGreen, StringFormat("%I64u : Take Profit price.", m_Infos.ticket));
087.             if (Stop == NULL) Stop = new C_ElementsTrade(m_Infos.ticket, evMsgCloseStopLoss, clrFireBrick, StringFormat("%I64u : Stop Loss price.", m_Infos.ticket));
088.             (*Open).UpdatePrice(0, m_Infos.priceOpen = PositionGetDouble(POSITION_PRICE_OPEN));
089.             (*Take).UpdatePrice(m_Infos.priceOpen, PositionGetDouble(POSITION_TP));
090.             (*Stop).UpdatePrice(m_Infos.priceOpen, PositionGetDouble(POSITION_SL));
091.             break;
092.     }
093.     ChartRedraw();
094. };
095. //+------------------------------------------------------------------+
096. void OnDeinit(const int reason)
097. {
098.     delete Open;
099.     delete Take;
100.     delete Stop;
101. }
102. //+------------------------------------------------------------------+

Código fonte do Indicador de Posição

Agora vamos entender o que está acontecendo aqui e quais mudanças foram feitas. Primeiramente o que nos chama a atenção é a estrutura da linha 19. Agora temos mais informações presentes nela. Todas estas informações terão seu uso imediato. Pois bem, precisamos inicializar estes novos valores. O primeiro a ser inicializado é o nome do ativo. Isto é feito na linha 40. Mas por que capturar o nome do ativo, usando para isto a posição. Não seria mais simples usar a constante _Symbol? Não meu caro leitor. Precisamos de fato inicializar o nome com base no que é informado na posição. Lembre-se que este indicador poderá ser usado em um ativo diferente do que está no gráfico. Muito bem, agora já temos o nome do ativo, podemos passar para a próxima etapa. Mas por enquanto, vamos pular a função OnCalculate e vamos para a função OnChartEvent, que se encontra na linha 71.

Aqui vamos inicializar as demais informações da estrutura. A primeira é m_Infos.bIsBuy, que é inicializada na linha 85. E a segunda é m_Infos.priceOpen, que é inicializada na linha 88. Perfeito, agora já temos tudo o que precisamos. Mas antes de realmente fazer a indicação via algum objeto. Vamos ver como a coisa funciona, e quero que você experimente isto neste ponto do desenvolvimento. Isto para conseguir entender se o que foi dito no tópico anterior, faz ou não sentido. Então vamos para a linha 59, ou seja, a função OnCalculate.

Legal, veja que é algo muito simples que estamos fazendo nesta função OnCalculate. Nas linhas 63 e 64, pedimos ao MetaTrader 5 que nos informe o valor de ASK e BID. Logo depois na linha 66 iremos imprimir no canto superior esquerdo do gráfico uma informação que variará, dependendo do que esteja acontecendo. Ali, estamos colocando o valor do melhor comprador, do melhor vendedor e também o resultado se encerramos a operação naquele instante específico. Observe que o cálculo é feito com base, no fato de estarmos em uma posição comprada ou vendida. Se o valor apresentado for negativo, significa que estamos tendo prejuízo se a posição for fechada, se o valor for positivo, significa que estamos tendo lucro. Algo bem simples e direto. Não tem nenhum tipo de complicação ou enrolação.

Se você experimentou e viu como isto de fato funciona, podemos passar para a próxima etapa. Que é justamente informar este mesmo valor PROFIT em algum objeto que esteja ligado a linha de preço de abertura. Um detalhe, a ser mencionado antes de fazermos isto. Da maneira como este código do indicador foi implementado. Você poderá fazer operações de preço médio, ou mesmo operações com mudanças no volume negociado, sem nenhum problema. Pois caso o preço de abertura venha a mudar, o indicador irá se adaptar automaticamente a nova condição. Refletindo assim o que está de fato sendo visto pelo servidor de negociação. Detalhe: Ainda não estamos nos preocupando com a questão financeira. Neste ponto estamos calculando o percentual em termos de deslocamento do preço. Ou para ficar mais claro, a quantidade de ticks que estão sendo deslocados. Seja em direção ao lucro ou em direção a um prejuízo.

Muito bem, para separar adequadamente as coisas. Vamos para um novo tópico.


Criando a indicação na linha de preço

Fazer a implementação de tal indicação, não é uma tarefa complicada. Apenas um pouco mais do mesmo. Ou seja, crie um objeto, ajuste as propriedades do mesmo e apresente ele no gráfico, no local adequado. Simples assim. Então agora, vamos deixar por enquanto o código do indicador, e vamos passar para o código da classe C_ElementsTrade. E implementar o objeto que precisamos colocar no gráfico. E para fazer isto, o novo código da classe C_ElementsTrade, pode ser visto na íntegra logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_NameHLine      m_Info.szPrefixName + "#HLINE"
005. #define def_NameBtnClose   m_Info.szPrefixName + "#CLOSE"
006. #define def_NameBtnMove    m_Info.szPrefixName + "#MOVE"
007. #define def_NameInfoDirect m_Info.szPrefixName + "#DIRECT"
008. #define def_NameObjLabel   m_Info.szPrefixName + "#PROFIT"
009. //+------------------------------------------------------------------+
010. #define macro_LineInFocus(A) ObjectSetInteger(0, def_NameHLine, OBJPROP_YSIZE, m_Info.weight = (A ? 3 : 1));
011. //+------------------------------------------------------------------+
012. #define def_PathBtns "Images\\Market Replay\\Orders\\"
013. #define def_Btn_Close def_PathBtns + "Btn_Close.bmp"
014. #resource "\\" + def_Btn_Close;
015. //+------------------------------------------------------------------+
016. #include "..\Auxiliar\C_Mouse.mqh"
017. //+------------------------------------------------------------------+
018. class C_ElementsTrade : private C_Mouse
019. {
020.     private    :
021. //+------------------------------------------------------------------+
022.         struct st00
023.         {
024.             ulong       ticket;
025.             string      szPrefixName,
026.                         szDescr;
027.             EnumEvents  ev;
028.             double      price;
029.             bool        bClick,
030.                         bIsBuy;
031.             char        weight,
032.                         digits;
033.             color       _color;
034.         }m_Info;
035. //+------------------------------------------------------------------+
036.         void UpdateViewPort(const double price)
037.         {
038.             int x, y;
039.             
040.             ChartTimePriceToXY(0, 0, 0, price, x, y);            
041.             x = (m_Info.ev == evMsgClosePositionEA ? 150 : (m_Info.ev == evMsgCloseTakeProfit ? 220 : 290));
042.             ObjectSetInteger(0, def_NameHLine, OBJPROP_XDISTANCE, x);
043.             ObjectSetInteger(0, def_NameHLine, OBJPROP_YDISTANCE, y - (m_Info.weight > 1 ? (int)(m_Info.weight / 2) : 0));
044.             ObjectSetInteger(0, def_NameBtnClose, OBJPROP_XDISTANCE, x);
045.             ObjectSetInteger(0, def_NameBtnClose, OBJPROP_YDISTANCE, y);
046.             ObjectSetInteger(0, def_NameObjLabel, OBJPROP_XDISTANCE, x + 10);
047.             ObjectSetInteger(0, def_NameObjLabel, OBJPROP_YDISTANCE, y - 8);
048.             ObjectSetInteger(0, def_NameInfoDirect, OBJPROP_XDISTANCE, x + 80);
049.             ObjectSetInteger(0, def_NameInfoDirect, OBJPROP_YDISTANCE, y);
050.             ObjectSetInteger(0, def_NameBtnMove, OBJPROP_XDISTANCE, x + 30);
051.             ObjectSetInteger(0, def_NameBtnMove, OBJPROP_YDISTANCE, y);
052.         }
053. //+------------------------------------------------------------------+
054. inline void CreateLinePrice(void)
055.         {
056.             string szObj;
057.             
058.             CreateObjectGraphics(szObj = def_NameHLine, OBJ_RECTANGLE_LABEL, m_Info._color, (EnumPriority)(ePriorityDefault));
059.             ObjectSetInteger(0, szObj, OBJPROP_BGCOLOR, m_Info._color);
060.             ObjectSetInteger(0, szObj, OBJPROP_XSIZE, TerminalInfoInteger(TERMINAL_SCREEN_WIDTH));
061.             ObjectSetInteger(0, szObj, OBJPROP_BORDER_TYPE, BORDER_FLAT);
062.             ObjectSetInteger(0, szObj, OBJPROP_CORNER, CORNER_LEFT_UPPER);
063.             ObjectSetString(0, szObj, OBJPROP_TOOLTIP, m_Info.szDescr);
064.             macro_LineInFocus(false);
065.         }
066. //+------------------------------------------------------------------+
067. inline void CreateBoxInfo(const bool bMove)
068.         {
069.             string szObj;
070.             const char c[] = {(char)(bMove ? 'u' : (m_Info.bIsBuy ? 236 : 238)), 0};
071.             
072.             CreateObjectGraphics(szObj = (bMove ? def_NameBtnMove : def_NameInfoDirect), OBJ_LABEL, clrNONE, (EnumPriority)(ePriorityDefault));
073.             ObjectSetString(0, szObj, OBJPROP_FONT, "Wingdings");
074.             ObjectSetString(0, szObj, OBJPROP_TEXT, CharArrayToString(c));
075.             ObjectSetInteger(0, szObj, OBJPROP_COLOR, (bMove ? m_Info._color : (m_Info.bIsBuy ? clrForestGreen : clrFireBrick)));
076.             ObjectSetInteger(0, szObj, OBJPROP_FONTSIZE, (bMove ? 17 : 15));
077.             ObjectSetInteger(0, szObj, OBJPROP_ANCHOR, ANCHOR_CENTER);
078.         }
079. //+------------------------------------------------------------------+
080. inline void CreateObjectInfoText(void)
081.         {
082.             string szObj;
083.             
084.             CreateObjectGraphics(szObj = def_NameObjLabel, OBJ_EDIT, clrNONE, (EnumPriority)(ePriorityDefault));
085.             ObjectSetString(0, szObj, OBJPROP_FONT, "Lucida Console");
086.             ObjectSetInteger(0, szObj, OBJPROP_FONTSIZE, 10);
087.             ObjectSetInteger(0, szObj, OBJPROP_COLOR, clrBlack);
088.             ObjectSetInteger(0, szObj, OBJPROP_BORDER_COLOR, m_Info._color);
089.             ObjectSetInteger(0, szObj, OBJPROP_ALIGN, ALIGN_CENTER);
090.             ObjectSetInteger(0, szObj, OBJPROP_READONLY, true);
091.             ObjectSetInteger(0, szObj, OBJPROP_YSIZE, 17);
092.             ObjectSetInteger(0, szObj, OBJPROP_XSIZE, 60);
093.         }
094. //+------------------------------------------------------------------+
095. inline void CreateButtonClose(void)
096.         {
097.             string szObj;
098.             
099.             CreateObjectGraphics(szObj = def_NameBtnClose, OBJ_BITMAP_LABEL, clrNONE, (EnumPriority)(ePriorityDefault));
100.             ObjectSetString(0, szObj, OBJPROP_BMPFILE, 0, "::" + def_Btn_Close);
101.             ObjectSetInteger(0, szObj, OBJPROP_ANCHOR, ANCHOR_CENTER);
102.         }
103. //+------------------------------------------------------------------+
104.     public    :
105. //+------------------------------------------------------------------+
106.         C_ElementsTrade(const ulong ticket, const EnumEvents ev, color _color, char digits, string szDescr = "\n", const bool IsBuy = true)
107.             :C_Mouse(0, "")
108.         {        
109.             ZeroMemory(m_Info);
110.             m_Info.szPrefixName = StringFormat("%I64u@%03d", m_Info.ticket = ticket, (int)(m_Info.ev = ev));
111.             m_Info._color = _color;
112.             m_Info.szDescr = szDescr;
113.             m_Info.bIsBuy = IsBuy;
114.             m_Info.digits = digits;
115.         }
116. //+------------------------------------------------------------------+
117.         ~C_ElementsTrade()
118.         {
119.             ObjectsDeleteAll(0, m_Info.szPrefixName);
120.         }
121. //+------------------------------------------------------------------+
122. inline void UpdatePrice(const double open, const double price)
123.         {
124.             if (price > 0)
125.             {
126.                 CreateLinePrice();
127.                 CreateButtonClose();
128.             }else
129.                 ObjectsDeleteAll(0, m_Info.szPrefixName);
130.             CreateBoxInfo(m_Info.ev != evMsgClosePositionEA);
131.             if (m_Info.ev == evMsgClosePositionEA)
132.                 CreateObjectInfoText();
133.             UpdateViewPort(m_Info.price = (price > 0 ? price : open));
134.         }
135. //+------------------------------------------------------------------+
136.         void ViewValue(const double profit)
137.         {
138.             ObjectSetString(0, def_NameObjLabel, OBJPROP_TEXT, StringFormat("%." + (string)m_Info.digits + "f", (profit < 0 ? -(profit) : profit)));
139.             ObjectSetInteger(0, def_NameObjLabel, OBJPROP_BGCOLOR, (profit >= 0 ? clrPaleGreen : clrCoral));
140.             ChartRedraw();
141.         }
142. //+------------------------------------------------------------------+
143.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
144.         {
145.             string sz0;
146.             long _lparam = lparam;
147.             double _dparam = dparam;
148.             
149.             C_Mouse::DispatchMessage(id, lparam, dparam, sparam);
150.             switch (id)
151.             {
152.                 case (CHARTEVENT_KEYDOWN):
153.                     if (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) break;
154.                     _lparam = (long) m_Info.ticket;
155.                     _dparam = 0;
156.                 case CHARTEVENT_CUSTOM + evMsgSetFocus:
157.                     macro_LineInFocus((m_Info.ticket == (ulong)(_lparam)) && ((EnumEvents)(_dparam) == m_Info.ev));
158.                     EventChartCustom(0, (ushort)(_dparam ? evHideMouse : evShowMouse), 0, 0, "");
159.                     m_Info.bClick = false;
160.                 case CHARTEVENT_CHART_CHANGE:
161.                     UpdateViewPort(m_Info.price);
162.                     break;
163.                 case CHARTEVENT_OBJECT_CLICK:
164.                     sz0 = GetPositionsMouse().szObjNameClick;
165.                     if (m_Info.bClick) switch (m_Info.ev)
166.                     {
167.                         case evMsgClosePositionEA:
168.                             if (sz0 == def_NameBtnClose)
169.                                 EventChartCustom(0, evMsgClosePositionEA, m_Info.ticket, 0, "");
170.                             break;
171.                         case evMsgCloseTakeProfit:
172.                             if (sz0 == def_NameBtnClose)
173.                                 EventChartCustom(0, evMsgCloseTakeProfit, m_Info.ticket, PositionGetDouble(POSITION_SL), PositionGetString(POSITION_SYMBOL));
174.                             else if (sz0 == def_NameBtnMove)
175.                                 EventChartCustom(0, evMsgSetFocus, m_Info.ticket, evMsgCloseTakeProfit, "");
176.                             break;
177.                         case evMsgCloseStopLoss:
178.                             if (sz0 == def_NameBtnClose)
179.                                 EventChartCustom(0, evMsgCloseStopLoss, m_Info.ticket, PositionGetDouble(POSITION_TP), PositionGetString(POSITION_SYMBOL));
180.                             else if (sz0 == def_NameBtnMove)
181.                                 EventChartCustom(0, evMsgSetFocus, m_Info.ticket, evMsgCloseStopLoss, "");
182.                             break;
183.                     }
184.                     m_Info.bClick = false;
185.                     break;
186.                 case CHARTEVENT_MOUSE_MOVE:
187.                     m_Info.bClick = (CheckClick(C_Mouse::eClickLeft) ? true : m_Info.bClick);
188.                     if (m_Info.weight > 1)
189.                     {
190.                         UpdateViewPort(GetPositionsMouse().Position.Price);
191.                         if (m_Info.bClick)
192.                         {
193.                             switch (m_Info.ev)
194.                             {
195.                                 case evMsgCloseTakeProfit:
196.                                     EventChartCustom(0, evMsgNewTakeProfit, m_Info.ticket, GetPositionsMouse().Position.Price, PositionGetString(POSITION_SYMBOL));
197.                                     break;
198.                                 case evMsgCloseStopLoss:
199.                                     EventChartCustom(0, evMsgNewStopLoss, m_Info.ticket, GetPositionsMouse().Position.Price, PositionGetString(POSITION_SYMBOL));
200.                                     break;
201.                             }
202.                             EventChartCustom(0, evMsgSetFocus, 0, 0, "");
203.                         }
204.                     }
205.                     break;
206.             }
207.         }
208. //+------------------------------------------------------------------+
209. };
210. //+------------------------------------------------------------------+
211. #undef macro_LineInFocus
212. //+------------------------------------------------------------------+
213. #undef def_Btn_Close
214. #undef def_PathBtns
215. //+------------------------------------------------------------------+
216. #undef def_NameObjLabel
217. #undef def_NameInfoDirect
218. #undef def_NameBtnMove
219. #undef def_NameBtnClose
220. #undef def_NameHLine
221. //+------------------------------------------------------------------+

C_ElementsTrade

Claro que será preciso mudar uns detalhes no código do indicador. Mas vamos primeiro entender este código da classe C_ElementsTrade. Muito bem, como grande parte deste código não mudou, vamos dar ênfase apenas as partes que realmente são novas aqui. Começando com a definição na linha oito. Algo bem básico. Em seguida temos uma outra mudança também que é a inclusão da variável na linha 32. Ela será usada para um propósito bastante nobre. Porém vamos com calma e logo você verá que propósito é este.

Agora como temos um novo elemento no gráfico, precisamos reorganizar os objetos. Por isto observe as mudanças ocorridas no procedimento UpdateViewPort, presente na linha 36. Não vou entrar em detalhes, pois é algo bastante simples de ser entendido. Apenas estou chamando a sua atenção, meu caro leitor, para que você não fique procurando as coisas nos locais errados.

Muito bem, agora temos também um novo procedimento. Este é visto na linha 80. Que é justamente o procedimento responsável por criar o objeto que receberá as informações vindas do indicador. Algo comum de ser feito, então não vou entrar em detalhes, pois já vimos isto diversas vezes aqui nesta sequência. Porém quero chamar a sua atenção, meu caro leitor, para o constructor da classe. Este está presente na linha 106. Observe que ele precisa receber um novo valor, que é justamente o número de dígitos a serem impressos depois do ponto decimal. Como neste momento estamos apenas mostrando a quantidade de ticks, ou pontos que estamos em lucro ou prejuízo. Precisamos desta informação para apresentar o valor da maneira correta.

Feito isto, vamos para a linha 136, que é o novo procedimento público da classe. Este procedimento, será de fato acessado pelo código do indicador. Veja que ele é relativamente muito simples, contanto apenas e somente com três linhas. Como muito provavelmente o conteúdo destas linhas pode lhe ser algo estranho. Vou dar uma rápida explicação do que está acontecendo aqui. Note que este procedimento receberá apenas um valor, que é justamente aquele impresso no canto superior esquerdo do gráfico. Isto para que você saiba de onde vem este valor.

Agora, na linha 138, temos uma chamada a função StringFormat, presente no MQL5. Mas olhando esta função, você pode ficar bastante confuso sobre por que ela tem este formato tão peculiar. O motivo é bem simples. Queremos apresentar qualquer tipo de valor, sendo sempre positivo, mas com um número de dígitos depois do ponto decimal, que pode variar, de ativo para ativo. Não confunda este valor com um valor financeiro. Eles são diferentes. Para que você possa entender melhor, é necessário que você tenha alguma familiaridade com alguns ativos. Se este não é o seu caso, sugiro que procure estudar um pouco mais sobre questões de movimentação de ativos diferentes. Mas mesmo assim, vou lhe dar uma colher de chá. Explicando pelo menos o básico da coisa. Alguns ativos podem se mover 5 pontos de cada vez. Enquanto outros podem se mover 0.01 pontos de cada vez. Mas existem casos de ativos que podem se mover 0.00001 de cada vez.

Ok, isto parece ser algo estranho e complicado à primeira vista. Mas é justamente isto que esta chamada a StringFormat tenta fazer. Ela tenta adaptar de maneira automática, a quantidade de dígitos esperados em um movimento. Pois não faz sentido, imprimir mais casas depois do ponto decimal do que o necessário. Poderíamos fixar o valor em cinco, mas isto iria de forma inútil complicar a leitura de um ativo que precise de duas casas decimais. Ou não precise de nenhuma casa decimal. O que é algo raro. Mas existe, como é o caso do Índice Futuro presente na B3 ( Bolsa do Brasil ).

Assim note como estamos fazendo isto. Primeiro abrimos aspas duplas, logo depois colocamos o sinal de porcentagem. Este diz a função StringFormat que os próximos dados serão referentes a formatação do que será representado. Em seguida colocamos um ponto e fechamos as aspas. IMPORTANTE: NÃO SE DEVE DAR ESPAÇO ENTRE ESTE PONTO E AS ASPAS DUPLAS. Em seguida informamos o valor que está na variável digits. Logo depois abrimos aspas duplas novamente. E colocamos um f que indica um valor de ponto flutuante. E novamente entre esta primeira aspa dupla e o f, NÃO SE DEVE DAR ESPAÇO. Depois do f você pode colocar qualquer coisa. Desde que no final feche a formatação da string com aspas duplas também. Para que você entenda mais facilmente o que acabou de acontecer. Já que isto será feito em tempo de execução, ou seja RUN-TIME. Vamos ver alguns exemplos simples:

Supondo que estejamos em um ativo com dois dígitos depois do ponto. Quando este código da linha 138 for executado. E isto em RUN-TIME. Será criado algo do tipo: "%.2f". Assim quando a função StringFormat executar ela saberá que deverá usar dois dígitos depois do ponto decimal. E sem precisar compilar novamente este código, você usar ele em um ativo que precise de cinco dígitos depois do ponto decimal. Quando em RUN-TIME executarmos isto, será criado algo do tipo "%.5f".

Como eu disse, parece ser algo complicado, mas é bem simples e com um resultado bastante legal. Já a linha 139, tem como finalidade, mostra de forma bastante rápida se estamos no positivo ou negativo. Isto por que o valor apresentado sempre e sempre será positivo. Mas olhando a cor de fundo podemos facilmente notar se estamos no negativo, tendo assim um prejuízo. Ou se já estamos no positivo, tendo assim um possível lucro. Neste ponto muitos pode não gostar do que irão ver. Já que com exceção do FOREX, onde de vez em quando temos o BID igual o ASK. Em um ambiente de bolsa, você SEMPRE E SEMPRE começa no prejuízo. Ou seja, aquela coisa de entrar a mercado e imediatamente sair a mercado, faz com que você perca dinheiro. Não é uma possibilidade é uma REALIDADE.

Já a linha 140, apenas serve para forçar o MetaTrader 5 a atualizar o gráfico imediatamente. Isto por que normalmente estas operações em objetos, entram em uma fila de execução. O que pode acarretar uma demora de alguns instantes, até que de fato, você possa ver o que está acontecendo. Para evitar isto, usamos a linha 140. Fora estes pontos que mencionei nada mais mudou no código. Então vamos agora ver o que mudou no código do indicador. E para explicar isto. O código dele é mostrado na íntegra logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. #property icon "/Images/Market Replay/Icons/Positions.ico"
004. #property description "Indicator for tracking an open position on the server."
005. #property description "This should preferably be used together with an Expert Advisor."
006. #property description "For more details see the same article."
007. #property version   "1.125"
008. #property link "https://www.mql5.com/pt/articles/13356"
009. #property indicator_chart_window
010. #property indicator_plots 0
011. //+------------------------------------------------------------------+
012. #define def_ShortName "Position View"
013. //+------------------------------------------------------------------+
014. #include <Market Replay\Order System\C_ElementsTrade.mqh>
015. #include <Market Replay\Defines.mqh>
016. //+------------------------------------------------------------------+
017. input ulong user00 = 0;        //For Expert Advisor use
018. //+------------------------------------------------------------------+
019. struct st00
020. {
021.     ulong   ticket;
022.     string  szShortName,
023.             szSymbol;
024.     double  priceOpen;
025.     char    digits;
026.     bool    bIsBuy;
027. }m_Infos;
028. //+------------------------------------------------------------------+
029. C_ElementsTrade *Open = NULL, *Stop = NULL, *Take = NULL;
030. //+------------------------------------------------------------------+
031. bool CheckCatch(ulong ticket)
032. {
033.     ZeroMemory(m_Infos);
034.     m_Infos.szShortName = StringFormat("%I64u", m_Infos.ticket = ticket);
035.     if (!PositionSelectByTicket(m_Infos.ticket)) return false;
036.     if (ObjectFind(0, m_Infos.szShortName) >= 0)
037.     {
038.         m_Infos.ticket = 0;
039.         return false;
040.     }
041.     m_Infos.szSymbol = PositionGetString(POSITION_SYMBOL);
042.     m_Infos.digits = (char)SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_DIGITS);
043.     IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName);
044.     EventChartCustom(0, evUpdate_Position, ticket, 0, "");
045.             
046.     return true;
047. }
048. //+------------------------------------------------------------------+
049. int OnInit()
050. {
051.     IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
052.     if (!CheckCatch(user00))
053.     {
054.         ChartIndicatorDelete(0, 0, def_ShortName);
055.         return INIT_FAILED;
056.     }
057. 
058.     return INIT_SUCCEEDED;
059. }
060. //+------------------------------------------------------------------+
061. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
062. {
063.     double ask, bid;
064.     
065.     ask = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_ASK);
066.     bid = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_BID);
067.     
068.     Comment(StringFormat("BID : %f  ||| ASK : %f  ||| PROFIT : %f", bid, ask, (m_Infos.bIsBuy ? bid - m_Infos.priceOpen : m_Infos.priceOpen - ask)));
069.     if (Open != NULL) (*Open).ViewValue((m_Infos.bIsBuy ? bid - m_Infos.priceOpen : m_Infos.priceOpen - ask));
070.     
071.     return rates_total;
072. }
073. //+------------------------------------------------------------------+
074. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
075. {
076.     if (Open != NULL) (*Open).DispatchMessage(id, lparam, dparam, sparam);
077.     if (Take != NULL) (*Take).DispatchMessage(id, lparam, dparam, sparam);
078.     if (Stop != NULL) (*Stop).DispatchMessage(id, lparam, dparam, sparam);
079.     switch (id)
080.     {
081.         case CHARTEVENT_CUSTOM + evUpdate_Position:
082.             if (lparam != m_Infos.ticket) return;
083.             if (!PositionSelectByTicket(m_Infos.ticket))
084.             {
085.                 ChartIndicatorDelete(0, 0, m_Infos.szShortName);
086.                 return;
087.             };
088.             if (Open == NULL) Open = new C_ElementsTrade(m_Infos.ticket, evMsgClosePositionEA, clrRoyalBlue, m_Infos.digits, StringFormat("%I64u : Position opening price.", m_Infos.ticket), m_Infos.bIsBuy = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY));
089.             if (Take == NULL) Take = new C_ElementsTrade(m_Infos.ticket, evMsgCloseTakeProfit, clrForestGreen, m_Infos.digits, StringFormat("%I64u : Take Profit price.", m_Infos.ticket));
090.             if (Stop == NULL) Stop = new C_ElementsTrade(m_Infos.ticket, evMsgCloseStopLoss, clrFireBrick, m_Infos.digits, StringFormat("%I64u : Stop Loss price.", m_Infos.ticket));
091.             (*Open).UpdatePrice(0, m_Infos.priceOpen = PositionGetDouble(POSITION_PRICE_OPEN));
092.             (*Take).UpdatePrice(m_Infos.priceOpen, PositionGetDouble(POSITION_TP));
093.             (*Stop).UpdatePrice(m_Infos.priceOpen, PositionGetDouble(POSITION_SL));
094.             break;
095.     }
096.     ChartRedraw();
097. };
098. //+------------------------------------------------------------------+
099. void OnDeinit(const int reason)
100. {
101.     delete Open;
102.     delete Take;
103.     delete Stop;
104. }
105. //+------------------------------------------------------------------+

Código fonte do indicador de posição

Basicamente não mudou muita coisa. Você pode ver que adicionamos uma nova variável na linha 25. Justamente aquela que precisamos informar no constructor da classe C_ElementsTrade. Pois bem, esta mesma variável é inicializada com um valor na linha 42. Perceba que o valor recebido, depende do ativo informado na posição. E o nome do ativo, é conseguido na linha 41. Isto depois de termos buscado o valor na linha 35.

Então, como é de se esperar os constructores nas linhas 88 a 90, tiveram uma pequena mudança. Mas o que de fato quero chamar a sua atenção, meu caro leitor e entusiasta. É para o que está acontecendo na função OnCalculate. Veja que a única coisa que mudou aqui, frente ao que foi feito no começo deste artigo. Foi a inclusão da linha 69. A linha 68 pode ser descartada, sem problemas. Ela está ali, apenas para que você confirme, ou verifique o que está sendo indicado no objeto presente no gráfico. Mas vamos voltar a linha 69. Veja que estamos fazendo as coisas de uma maneira idêntica ao que está sendo feito na linha 68. Ou seja, o mesmo cálculo.

Com isto, o valor que será mostrado no objeto, é exatamente a diferença entre o ponto de abertura e o ponto de melhor saída. Seja agredindo o BID, seja agredindo o ASK. Mas, vou voltar a ressaltar o seguinte fato: O que você estará vendo, NÃO É UM VALOR FINANCEIRO, E SIM UM VALOR EM TERMOS DE PONTOS. Por isto cuidado, achando que estará ganhando pouco ou muito. Pois para saber o financeiro envolvido é necessário fazer um novo cálculo. Mas aqui já estamos em direção a isto.

Bem, caso você queira saber o resultado, sem de fato experimentar localmente. Pode ver isto na animação logo abaixo.

Note que, mesmo quando a linha de último negócio, ou o valor de fechamento, se move. O mesmo não acontece com o valor de resultante de uma saída a mercado. Ou seja, o valor de BID ou ASK não se alterou. Mesmo com alteração no valor do preço de fechamento.


Considerações finais

Neste artigo, mostrei como você, pode sem muito esforço, conseguir implementar um objeto que irá lhe mostrar no gráfico. Se uma posição, está lhe dando prejuízo ou mesmo lucro. Isto de maneira extremamente simples e eficaz. Apesar de muitos operadores iniciantes não terem a devida noção do que estão fazendo no mercado. Acabando assim por tomar grandes e frequentes prejuízos. Usando este indicador que estou mostrando como desenvolver, você, mesmo sem muito conhecimento, conseguirá facilmente saber quando é hora de fechar uma posição. E ao fazê-lo, não virá a ter um resultado diferente do esperado. Isto por que, estamos efetuando o cálculo de forma a termos a real situação de nossa posição. Isto por que neste calculo que estamos fazendo, estamos levando em consideração o SPREAD envolvido para fechar a posição. Diferente do que acontece quando simplesmente lemos e fazemos uso do valor POSITION_PROFIT.

Para quem não consegue ainda criar estas aplicações, ou deseja simplesmente verificar se elas são adequadas, ao que é esperado. No anexo, deixo todas as partes necessárias para você as usar localmente. Minha sugestão é que você faça isto em uma conta DEMO. Não use nada em uma conta REAL, antes de saber exatamente como as coisas funcionam. Mesmo por que tudo que estou mostrando aqui, é voltado a ser o mais didático possível. E não uma aplicação final e sem falhas.

ArquivoDescrição
Experts\Expert Advisor.mq5
Demonstra a interação entre o Chart Trade e o Expert Advisor (É necessário o Mouse Study para interação)
Indicators\Chart Trade.mq5Cria a janela para configuração da ordem a ser enviada (É necessário o Mouse Study para interação)
Indicators\Market Replay.mq5Cria os controles para interação com o serviço de replay/simulador (É necessário o Mouse Study para interação)
Indicators\Mouse Study.mq5Permite interação entre os controles gráficos e o usuário (Necessário tanto para operar o replay simulador, quanto no mercado real)
Indicators\Order Indicator.mq5Responsável pela indicação de ordens de mercado, permitindo interação e controle das mesmas
Indicators\Position View.mq5Responsável pela indicação de posições de mercado, permitindo interação e controle das mesmas
Services\Market Replay.mq5Cria e mantém o serviço de replay e simulação de mercado (Arquivo principal de todo o sistema)
Arquivos anexados |
Anexo.zip (779.24 KB)
Redes neurais em trading: Dupla clusterização de séries temporais (Conclusão) Redes neurais em trading: Dupla clusterização de séries temporais (Conclusão)
Damos continuidade à implementação dos métodos propostos pelos autores do framework DUET, que apresenta uma abordagem inovadora para a análise de séries temporais, combinando clusterização temporal e de canais para revelar padrões ocultos nos dados analisados.
Do básico ao intermediário: Filas, Listas e Árvores (V) Do básico ao intermediário: Filas, Listas e Árvores (V)
Neste artigo começamos a trabalhar com a implementação do mecanismo de árvore. Como sei que este mecanismo pode ser extremamente complicado de ser compreendido e assimilado, no começo do aprendizado. Iremos implementar as coisas com calma e devagar. Assim todos irão conseguir entender como uma árvore funciona e qual o melhor momento para utiliza-la.
Visualização de estratégias em MQL5: distribuindo os resultados da otimização em gráficos de critérios Visualização de estratégias em MQL5: distribuindo os resultados da otimização em gráficos de critérios
Neste artigo, escreveremos um exemplo de visualização do processo de otimização e exibiremos os três melhores passes para quatro critérios de otimização. Além disso, implementaremos a possibilidade de selecionar um dos três melhores passes para exibir seus dados em tabelas e no gráfico.
Redes neurais no trading: Dupla clusterização de séries temporais (DUET) Redes neurais no trading: Dupla clusterização de séries temporais (DUET)
O framework DUET propõe uma abordagem inovadora para a análise de séries temporais, combinando clusterização temporal e de canais para identificar padrões ocultos nos dados analisados. Isso permite adaptar os modelos às mudanças ao longo do tempo e aumentar a precisão das previsões por meio da eliminação de ruídos.