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

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

MetaTrader 5Testador |
90 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 (I), começamos a falar sobre a possibilidade de construção e implementação de um indicador, que nos permita visualizar posições abertas, diretamente no gráfico do ativo. Apesar de muitos, imaginarei não ser algo necessário, já que podemos contar com a ajuda do MetaTrader 5, para tal coisa. Isto não se aplica quando, fazemos uso de um modelo operacional do tipo cross order. Ou mesmo, como será o nosso caso específico: Usar um replay/simulador.

Porém, como foi mencionado, existem alguns problemas quando começamos a trabalhar com muitos objetos no gráfico. Especialmente, quando eles de alguma forma terão algum tipo de relação entre si. O que torna todo o trabalho bastante complicado de ser feito e desenvolvido. Muito bem, mas aqui, nosso foco não é trazer os problemas que encontramos, e sim mostrar algum tipo de solução na qual decidimos que iremos de fato implementar. O que começaremos a ver, como venho falando já a algum tempo. Não será uma solução definitiva, ou a única possível. O que proponho, é que você, meu caro leitor, venha a parar e pensar um pouco, antes de começar a criar códigos e mais códigos sem um motivo aparente.

Porém, como o assunto a ser tratado, é bastante extenso, não pretendo, me estender muito nesta introdução. Pretendo que até no final deste artigo, tenhamos produzido algo um pouco melhor, do que foi visto no artigo anterior. Então mãos à obra.


Preparando o caminho para a implementação

Muito bem, o indicador que vimos no artigo anterior, apenas nos informava os dados de uma posição, que se encontrava aberta. Porém isto era feito no terminal, em formato de texto. Aquilo não parece assim tão motivador. Já que o que muitos, inclusive eu desejo, é que a informação seja mostrada diretamente no gráfico. Este será o objetivo neste artigo. Tudo que precisamos fazer, é criar um objeto do tipo linha horizontal, cuja coordenada é o preço. E aplicar nesta coordenada o valor que obtivemos no artigo anterior. Algo muito simples e direto. Porém irão surgir alguns problemas ao fazermos isto. Mas iremos ver isto com calma.

Primeiro então vamos implementar estes conjuntos de linhas. E sim, precisamos de três linhas, que o indicador de posição deverá apresentar. Uma linha para o preço de abertura da posição, e outras duas linhas extras. Uma para a posição onde o stop se encontra, e uma última para a posição do take. Mas para criar tais linhas, iremos usar o que já se encontra confeccionado em nosso código de replay/simulação.

Muito bem, já que você, caro leitor, pode vir a desejar colocar as coisas, de uma maneira diferente da que irei de fato mostrar. Vamos começar criando uma lista de prioridades. Esta pode ser vista no código abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_VERSION_DEBUG
05. //+------------------------------------------------------------------+
06. #ifdef def_VERSION_DEBUG
07.     #define macro_DEBUG_MODE(A) \
08.                     Print(__FILE__, " ", __LINE__, " ", __FUNCTION__ + " " + #A + " = " + (string)(A));
09. #else
10.     #define macro_DEBUG_MODE(A)
11. #endif
12. //+------------------------------------------------------------------+
13. #define def_SymbolReplay           "RePlay"
14. #define def_MaxPosSlider           400
15. #define def_MaskTimeService        0xFED00000
16. #define def_IndicatorTimeFrame     (_Period < 60 ? _Period : (_Period < PERIOD_D1 ? _Period - 16325 : (_Period == PERIOD_D1 ? 84 : (_Period == PERIOD_W1 ? 91 : 96))))
17. #define def_IndexTimeFrame         4
18. //+------------------------------------------------------------------+
19. union uCast_Double
20. {
21.     double   dValue;
22.     long     _long;                                   // 1 Information
23.     datetime _datetime;                               // 1 Information
24.     uint     _32b[sizeof(double) / sizeof(uint)];     // 2 Informations
25.     ushort   _16b[sizeof(double) / sizeof(ushort)];   // 4 Informations
26.     uchar    _8b [sizeof(double) / sizeof(uchar)];    // 8 Informations
27. };
28. //+------------------------------------------------------------------+
29. enum EnumEvents     {
30.             evTicTac,                         //Event of tic-tac
31.             evHideMouse,                      //Hide mouse price line
32.             evShowMouse,                      //Show mouse price line
33.             evHideBarTime,                    //Hide bar time
34.             evShowBarTime,                    //Show bar time
35.             evHideDailyVar,                   //Hide daily variation
36.             evShowDailyVar,                   //Show daily variation
37.             evHidePriceVar,                   //Hide instantaneous variation
38.             evShowPriceVar,                   //Show instantaneous variation
39.             evCtrlReplayInit,                 //Initialize replay control
40.             evChartTradeBuy,                  //Market buy event
41.             evChartTradeSell,                 //Market sales event 
42.             evChartTradeCloseAll,             //Event to close positions
43.             evChartTrade_At_EA,               //Event to communication
44.             evEA_At_ChartTrade,               //Event to communication
45.             evChatWriteSocket,                //Event to Mini Chat
46.             evChatReadSocket                  //Event To Mini Chat
47.                         };
48. //+------------------------------------------------------------------+
49. enum EnumPriority {                           //Priority list on objects
50.             ePriorityNull = -1,
51.             ePriorityDefault = 0,
52.             ePriorityChartTrade = 5,
53.             ePriorityOrders = 10
54.                         };
55. //+------------------------------------------------------------------+

Código fonte do arquivo Defines.mqh

Observe esta mudança que fizemos aqui no arquivo Defines.mqh. Ela é justamente a adição de uma enumeração na linha 49. Mas por que disto? O motivo é simples. Como falei no artigo anterior, objetos gráficos, podem acabar ficando uns sobre os outros. O pior dos cenários, é quando dois objetos do tipo linha ficam sobrepostos. Neste caso, não há como você fazer uma seleção simples e rápida de um dos objetos. Porém, se você informar ao MetaTrader 5, de que mesmo objetos do mesmo tipo, terão prioridade diferente. O MetaTrader 5, entenderá quando você for selecionar objetos que estejam sobrepostos. E dará prioridade ao que tiver o valor mais alto primeiro. Porém, tenha cautela ao fazer isto. Não quero que você entre em uma ciranda de colocar cada vez valores maiores. A fim de dar prioridade aos seus objetos em detrimento de outros.

Repare que estou criando 4 níveis. O primeiro nível é o que todos objetos criados pelas nossas aplicações, e que não precisam de tanta prioridade irão receber. Ou seja, o valor -1. Já na linha 51, é indicado o valor que normalmente o MetaTrader 5, utiliza quando o usuário adiciona um objeto no gráfico. Ou seja, eles recebem o valor zero. Como alguns objetos podem ter algum nível de transparência, e durante uma repintura, ficarem no topo da lista. Eles podem ocultar parcialmente o Chart Trade. Porém, tome cuidado. Pois mesmo se o Chart Trade, estiver totalmente oculto, ou seja, atrás de algum objeto. Se você clicar na região onde ele se encontra, o MetaTrader 5, dará prioridade a ele, e não ao objeto que está em primeiro plano.

Isto é conseguido, por conta que estamos definindo uma prioridade de cinco nele. A mesma coisa acontece, na linha 53. Note que entre a prioridade do Chart Trade e a dos objetos que criaremos em breve, existe uma distância. Esta distância, nos permite colocar outros níveis de prioridade, se assim vier a ser necessário. Então pelo modelo que acabo de apresentar, os objetos que farão parte do sistema de indicação de ordens e posições terão a prioridade mais alta de todas. Você pode modificar isto se desejar. Mas tenha em mente exatamente o que expliquei a pouco.

Muito bem, feito isto, teremos que fazer duas outras mudanças no código, já existente. Mas não precisa ficar preocupado ou com receio. São mudanças bem simples. Apenas para que esta enumeração seja de fato usada. Assim, vamos modificar o código da classe C_Terminal. O ponto a ser modificado pode ser visto no fragmento logo abaixo.

201. //+------------------------------------------------------------------+
202. inline void CreateObjectGraphics(const string szName, const ENUM_OBJECT obj, const color cor = clrNONE, const EnumPriority zOrder = ePriorityNull) const
203.             {
204.                 ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, 0, false);
205.                  ObjectCreate(m_Infos.ID, szName, obj, m_Infos.SubWin, 0, 0);
206. 

Fragmento da classe C_Terminal

Você deve mudar, o código original que se encontra na linha 202, por exatamente este mesmo, mostrado também na linha 202. O que estamos fazendo aqui, é justamente declarando que agora, iremos usar a lista de prioridades, que acabamos de definir. O outro trecho a ser modificado, também pode ser visto no fragmento logo abaixo. Só que este se encontra na classe C_ChartFloatingRAD.

164. //+------------------------------------------------------------------+
165.         template <typename T >
166.         void CreateObjectEditable(eObjectsIDE arg, T value)
167.             {
168.                 DeleteObjectEdit();
169.                 CreateObjectGraphics(m_Info.szObj_Editable, OBJ_EDIT, clrBlack, ePriorityChartTrade);
170.                 ObjectSetInteger(m_Init.id, m_Info.szObj_Editable, OBJPROP_XDISTANCE, m_Info.Regions[arg].x + m_Info.x + 3);
171.                 ObjectSetInteger(m_Init.id, m_Info.szObj_Editable, OBJPROP_YDISTANCE, m_Info.Regions[arg].y + m_Info.y + 3);

Fragmento da classe C_ChartFloadingRAD

A mudança deverá ser feita na linha 169. Você deverá substituir a linha original, por esta linha vista no fragmento acima. Com isto, quando você por ventura vier a mudar a lista de prioridade e compilar novamente as aplicações. O indicador Chart Trade, automaticamente passará a usar a nova prioridade. Isto caso ele tenha tido a prioridade modificada. Com isto, não precisamos mudar mais absolutamente nada no código já existente. Podendo assim começar a trabalhar no novo indicador.


Iniciando a implementação dos novos objetos

Antes de ver realmente o código mais avançado. Vamos ver as coisas um pouco mais devagar. Isto para que você consiga acompanhar a linha de raciocínio que irei aplicar. Desta forma, começaremos pelo código visto logo abaixo. Que nada mais é do que uma melhoria do código visto no artigo anterior.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Indicator for tracking an open position on the server."
04. #property version   "1.00"
05. #property indicator_chart_window
06. #property indicator_plots 0
07. //+------------------------------------------------------------------+
08. #define def_SufixLinePrice   "Price"
09. #define def_SufixLineTake    "Take"
10. #define def_SufixLineStop    "Stop"
11. //+------------------------------------------------------------------+
12. #include <Market Replay\Auxiliar\C_Terminal.mqh>
13. //+------------------------------------------------------------------+
14. input color user00 = clrBlue;               //Color Line Price
15. input color user01 = clrForestGreen;        //Color Line Take Profit
16. input color user02 = clrFireBrick;          //Color Line Stop Loss
17. //+------------------------------------------------------------------+
18. C_Terminal *Terminal;
19. struct st
20. {
21.     long       id;
22.     string     szPrefixName;
23. }glVariables;
24. //+------------------------------------------------------------------+
25. void CreateLinePriceOpen(const string szObjName)
26. {
27.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, user00, ePriorityNull);
28.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, PositionGetDouble(POSITION_PRICE_OPEN));
29. }
30. //+------------------------------------------------------------------+
31. int OnInit()
32. {
33.     ZeroMemory(glVariables);
34.     Terminal = new C_Terminal();
35.     if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED;
36.     glVariables.id = (*Terminal).GetInfoTerminal().ID;
37.     glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET));
38.     CreateLinePriceOpen(glVariables.szPrefixName + def_SufixLinePrice);
39.     
40.     return INIT_SUCCEEDED;
41. }
42. //+------------------------------------------------------------------+
43. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
44. {
45.     return rates_total;
46. }
47. //+------------------------------------------------------------------+
48. void OnDeinit(const int reason)
49. {
50.     delete Terminal;
51.     if (glVariables.id > 0)
52.         ObjectsDeleteAll(glVariables.id, glVariables.szPrefixName);
53. }
54. //+------------------------------------------------------------------+

Código fonte do Indicador de posição

Muito bem. Você olhando este código acima, já deve estar imaginando: Agora a coisa começou a complicar. Mas não, ainda estamos no básico da coisa. Este código acima, irá apenas e somente criar uma única linha no gráfico. Isto se existir uma posição, no ativo em que o indicador for colocado. Este código ainda está super simples, compacto e sem nenhum tipo de testagem sendo feita. Ele apenas criará um objeto H_LINE e o apresenta no gráfico, segundo a cor que o usuário, poderá definir. Simples assim. Mas se você estiver acostumado em colocar objetos no gráfico, fazendo isto pelo MQL5, deve estar estranhando. Já que não é apresentado nenhum tipo de chamada, que você realmente está acostumado em utilizar. Assim surge a dúvida. Será que este código realmente funciona? E se funciona. Como isto acontece de fato?

Vamos começar pela linha oito. Ali temos uma definição sendo feita, assim como nas duas próximas linhas. Onde definimos um sufixo para os objetos do tipo linha que iremos criar. O motivo de eu fazer isto, será melhor compreendido depois. Já entre as linhas 14 e 16, permitimos ao usuário, a possibilidade de modificar as cores que serão usadas nas linhas. Até aqui nada muito complicado. Porém agora começa a parte interessante. Isto na linha 19, onde começamos a definir uma estrutura, que depois irá desaparecer. Mas por hora, vamos fazer as coisas desta maneira. Já que você, meu caro leitor e entusiasta, precisa de fato entender a minha linha de pensamento. Isto para conseguir compreender por que estou fazendo as coisas desta maneira.

Por hora vamos pular o procedimento na linha 25, e vamos para a linha 31. Onde o indicador começará a ser executado pelo MetaTrader 5. Observe que a primeira coisa, na qual estou fazendo é zerar a região onde se encontra a estrutura glVariables. Por que fazer isto? O motivo, como eu disse é que esta estrutura irá desaparecer futuramente. Mas mesmo que ela seja mantida. Quero garantir que todas as variáveis presentes dentro da estrutura tenham como valor inicial o zero. Fazer isto via a chamada mostrada, é mais simples do que declarar variável por variável. E caso eu venha a esquecer de alguma, ela com toda a certeza estará com o valor zero.

Magnifico. Agora as linhas 34 e 35, já foram explicadas no artigo anterior. Então podemos pular elas. Já a linha 36 serve apenas como memória para um uso futuro do valor presente na classe C_Terminal. Com isto chegamos nas linhas principais. A primeira, que é a linha 37, definimos o valor que será o prefixo, do nome do objeto que iremos criar. No caso um objeto do tipo HLINE. O valor deste prefixo, é justamente o valor numérico que define o bilhete da posição. Isto garante que teremos apenas um único objeto com este nome no gráfico.

Mas como, iremos reaproveitar este mesmo valor depois, precisamos fazer algumas coisas. Isto para que o MetaTrader 5, não venha a confundir os objetos que estaremos colocando no gráfico. Imaginando que o objeto, já existe, quando na verdade estamos criando um novo. Agora você começa a entender as definições das linhas oito até a linha dez. Mas vamos voltar ao código, pois agora temos a linha 38. Que é onde, fazemos uma chamada a linha 25. Com o seguinte objetivo: Criar uma linha no gráfico e a posicionar no preço de abertura da posição.

Então vamos para o procedimento na linha 25, para compreender algumas coisas. Pois neste momento, o código ainda está bem simples. E fácil de entender. Este procedimento, recebe o nome que o objeto do tipo HLINE deverá receber. Mas onde estamos criando o tal objeto? Estamos fazendo isto usando a classe C_Terminal. Isto na linha 27. Agora observe uma coisa aqui. E quero que você preste bastante atenção a isto. Note que no quarto parâmetro da linha 27. Estamos usando uma prioridade muito baixa. Na verdade a mais baixa, que existe na lista. Por que?

Você pode pensar o seguinte: Mas esta linha que estamos criando neste ponto, não é um objeto que faz parte do indicador de posição e ordens? Por que ela está recebendo uma prioridade de eventos, abaixo de outros objetos? Não faz sentido isto. A prioridade ao meu ver deveria ser que colocamos na lista como sendo a prioridade dos objetos a serem criados no indicador de posições e ordens. Não meu caro leitor, pensar assim, mas principalmente neste caso em questão, não é o correto. E o motivo é simples. Está linhas horizontal, e que fique bem claro, apenas esta linha. Deverá ter a prioridade mais baixa possível. E o motivo é simples. Ela não irá se mover, ou deverá receber eventos. Já que ela representa o preço, ou ponto onde uma posição aberta está sendo indicada pelo servidor de negociação. Compreendeu agora o motivo de ela receber este valor de prioridade?

Porém você não deve ainda ficar tranquilo. Pois a única coisa que fizemos foi, criar a linha, e a posicionar no gráfico do ativo. Este posicionamento acontece na linha 28 do código acima. Somente isto foi feito. Se o usuário, apagar, mover, ou mesmo selecionar esta linha no gráfico, ele a poderá movimentar. Oque viola completamente o princípio que desejamos implementar com neste indicador. Resolver este tipo de coisa, envolve implementar ainda mais código. Mas como o objetivo aqui, é ser o mais didático quanto for possível. Faremos isto aos poucos, para que você consiga fazer compreender por que não consegue mover um objeto, que no caso é a linha do preço. Porém consegue mover outros objetos similares.

De qualquer maneira, quando o indicador for removido do gráfico, teremos na linha 51, um teste. Caso este tenha sucesso, na linha 52, removeremos todos os objetos que levam o prefixo, que usamos neste código, a fim de criar os objetos a serem visualizados no gráfico. Espero que você tenha compreendido esta parte. Pois para adicionar as linhas horizontais, que indicam onde se encontra o stop loss e o take profit, seguem o mesmo princípio. Mas existem algumas poucas diferenças. Como você pode ver abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Indicator for tracking an open position on the server."
04. #property version   "1.00"
05. #property indicator_chart_window
06. #property indicator_plots 0
07. //+------------------------------------------------------------------+
08. #define def_SufixLinePrice   "Price"
09. #define def_SufixLineTake    "Take"
10. #define def_SufixLineStop    "Stop"
11. //+------------------------------------------------------------------+
12. #include <Market Replay\Auxiliar\C_Terminal.mqh>
13. //+------------------------------------------------------------------+
14. input color user00 = clrBlue;               //Color Line Price
15. input color user01 = clrForestGreen;        //Color Line Take Profit
16. input color user02 = clrFireBrick;          //Color Line Stop Loss
17. //+------------------------------------------------------------------+
18. C_Terminal *Terminal;
19. struct st
20. {
21.     long       id;
22.     string     szPrefixName;
23. }glVariables;
24. //+------------------------------------------------------------------+
25. void CreateLinePriceOpen(const string szObjName)
26. {
27.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, user00, ePriorityNull);
28.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, PositionGetDouble(POSITION_PRICE_OPEN));
29. }
30. //+------------------------------------------------------------------+
31. void CreateLineStopAndTake(const string szObjName, const double price, const color cor)
32. {
33.     if (price <= 0) return;
34.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, ePriorityOrders);
35.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, price);
36. }
37. //+------------------------------------------------------------------+
38. int OnInit()
39. {
40.     ZeroMemory(glVariables);
41.     Terminal = new C_Terminal();
42.     if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED;
43.     glVariables.id = (*Terminal).GetInfoTerminal().ID;
44.     glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET));
45.     CreateLinePriceOpen(glVariables.szPrefixName + def_SufixLinePrice);
46.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01);
47.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02);
48.     
49.     return INIT_SUCCEEDED;
50. }
51. //+------------------------------------------------------------------+
52. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
53. {
54.     return rates_total;
55. }
56. //+------------------------------------------------------------------+
57. void OnDeinit(const int reason)
58. {
59.     delete Terminal;
60.     if (glVariables.id > 0)
61.         ObjectsDeleteAll(glVariables.id, glVariables.szPrefixName);
62. }
63. //+------------------------------------------------------------------+

Código fonte do Indicador de posição

Note que foi adicionado muito pouco código. Porém, agora se você utilizar esta aplicação em um gráfico. Onde o ativo, tem apenas e somente uma única posição em aberto. Você poderá ver onde estão os preços de abertura, take profit e stop loss. Mas então vamos ver o que foi adicionado, para que esta visualização se torne possível.

Agora na linha 31, temos um novo procedimento. Este é o que criará as linhas horizontais de take profit e stop loss. Observe que ele é praticamente igual ao procedimento para colocar a linha do preço de abertura. Mas por que eu os deixei separados? O motivo, é para que você entenda, que a linha do preço de abertura, deverá ter uma prioridade diferente, das demais linhas. Que no caso é a de take profit e stop loss. Um outro detalhe é que, na linha 33, testamos se o valor do preço, é zero ou negativo. O que não faz sentido. Se este for o caso, o objeto de linha horizontal não será criado.

Mas mesmo adicionando tendo a possibilidade de termos mais duas linhas, sendo colocadas no gráfico pelo indicador. Assim que ele for removido, todas as linhas que foram criadas, por ele serão removidas. Então só foi preciso adicionar, as linhas 46 e 47 no código para que tudo ficasse concluído. Pelo menos na forma mais básica de toda a coisa. Como resultado você poderá ver a imagem logo abaixo. Quando o indicador estiver no gráfico e uma posição estiver aberta.

Mas antes de partimos para algo ainda mais complexo. Vamos adicionar algum tipo de texto, para que possamos saber do que se trata aquela linha presente no gráfico. Já que sem isto, poderíamos ficar tentados em remover elas de forma manual, via Janela de objetos presente no MetaTrader 5. Tal janela, pode ser vista na imagem abaixo.

Aqui podemos ver, todos os objetos que se encontram presentes no gráfico. Estejam eles ocultos, ou não. Mas se o objeto, se encontra de alguma forma no gráfico ele será listado aqui. E não queremos que o usuário venha a deletar um destes objetos, apenas por que ele não sabe o propósito de tal objeto. Assim, faremos uma pequena mudança no código. Esta mudança pode ocorrer em dois locais. Aqui no indicador, ou na classe C_Terminal. No entanto e sinceramente, não quero ficar mexendo em uma classe que já se encontra totalmente estável. Adicionando possíveis instabilidades nela. Sem um bom motivo. Então como precisaremos mudar o status de algumas das propriedades dos objetos que acabamos de criar. Vamos fazer isto aqui, localmente.


Melhorando ainda mais as coisas

Uma das coisas que podemos colocar, isto para que o usuário, saiba o que aquele objeto específico representa. E por que motivo ele está ali. É uma descrição no objeto. Fazer isto é muito simples. Basta, você modificar o código anterior, para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Indicator for tracking an open position on the server."
04. #property version   "1.00"
05. #property indicator_chart_window
06. #property indicator_plots 0
07. //+------------------------------------------------------------------+
08. #define def_SufixLinePrice   "Price"
09. #define def_SufixLineTake    "Take"
10. #define def_SufixLineStop    "Stop"
11. //+------------------------------------------------------------------+
12. #include <Market Replay\Auxiliar\C_Terminal.mqh>
13. //+------------------------------------------------------------------+
14. input color user00 = clrRoyalBlue;          //Color Line Price
15. input color user01 = clrForestGreen;        //Color Line Take Profit
16. input color user02 = clrFireBrick;          //Color Line Stop Loss
17. //+------------------------------------------------------------------+
18. C_Terminal *Terminal;
19. struct st
20. {
21.     long       id;
22.     string     szPrefixName;
23. }glVariables;
24. //+------------------------------------------------------------------+
25. void CreateLinePriceOpen(const string szObjName, const string szDescription = "\n")
26. {
27.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, user00, ePriorityNull);
28.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, PositionGetDouble(POSITION_PRICE_OPEN));
29.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TEXT, szDescription);
30.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TOOLTIP, szDescription);
31. }
32. //+------------------------------------------------------------------+
33. void CreateLineStopAndTake(const string szObjName, const double price, const color cor, const string szDescription = "\n")
34. {
35.     if (price <= 0) return;
36.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, ePriorityOrders);
37.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, price);
38.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TEXT, szDescription);
39.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TOOLTIP, szDescription);
40. }
41. //+------------------------------------------------------------------+
42. int OnInit()
43. {
44.     ZeroMemory(glVariables);
45.     Terminal = new C_Terminal();    
46.     if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED;
47.     glVariables.id = (*Terminal).GetInfoTerminal().ID;
48.     glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET));
49.     CreateLinePriceOpen(glVariables.szPrefixName + def_SufixLinePrice, "Position opening price.");
50.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point.");
51.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point.");
52.     
53.     return INIT_SUCCEEDED;
54. }
55. //+------------------------------------------------------------------+
56. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
57. {
58.     return rates_total;
59. }
60. //+------------------------------------------------------------------+
61. void OnDeinit(const int reason)
62. {
63.     delete Terminal;
64.     if (glVariables.id > 0)
65.         ObjectsDeleteAll(glVariables.id, glVariables.szPrefixName);
66. }
67. //+------------------------------------------------------------------+

Código fonte do Indicador de posição

Note novamente, que foi preciso adicionar muito pouco código, para que o resultado obtido pudesse se este visto logo na imagem abaixo.

Assim como também na lista de objetos, onde agora temos o que é visto logo abaixo.

Lembrando o seguinte: Para que o texto venha a aparecer no gráfico conforme é visto na imagem acima. É preciso, que nas configurações do gráfico, a seguinte propriedade esteja marcada conforme é visto logo abaixo.

Até dá para marcar esta propriedade via código MQL5. Para isto bastaria que você adicionasse uma linha de código no programa. Conforme é mostrado no fragmento logo abaixo.

41. //+------------------------------------------------------------------+
42. int OnInit()
43. {
44.     ZeroMemory(glVariables);
45.     Terminal = new C_Terminal();
46.     if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED;
47.     glVariables.id = (*Terminal).GetInfoTerminal().ID;
48.     ChartSetInteger(glVariables.id, CHART_SHOW_OBJECT_DESCR, true);    
49.     glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET));
50.     CreateLinePriceOpen(glVariables.szPrefixName + def_SufixLinePrice, "Position opening price.");
51.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point.");
52.     CreateLineStopAndTake(glVariables.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point.");
53.     
54.     return INIT_SUCCEEDED;
55. }
56. //+------------------------------------------------------------------+

Fragmento do código principal

Observe que a linha adicionada é justamente a linha 48. Isto iria marcar a mesma informação vista na imagem acima. Mas como fazer isto, adiciona mais um elemento, para ser analisado pelo código. Isto a fim de evitar que o usuário, venha a mudar as configurações que você programador, talvez não queria que sejam modificadas. Não irei usar isto no código final. Mas se você, desejar fazer isto, sinta-se à vontade. Assim como a cor na qual o texto é apresentado, também pode ser modificado. Isto é feito no seguinte ponto marcado na imagem abaixo:

Também podemos mudar esta propriedade via código MQL5. Mas novamente, não quero ficar me preocupando, ou mudando as configurações que o usuário já deva estar acostumado a utilizar no dia a dia. Quero precisar fazer o mínimo de esforço possível, a fim de cumprir o objetivo proposto. Mas voltando ao código principal. Quero chamar a sua atenção, meu caro leitor, para uma coisa. Observe o fato de que tanto da declaração do procedimento CreateLinePriceOpen, como na declaração de CreateLineStopAndTake. O valor szDescription está recebendo um valor. Caso você, como programador, durante o uso da função, abster de informar, ou de fornecer uma descrição para o objeto. Ele irá receber uma descrição cujo valor é "\n". Isto se encontra na documentação do MQL5, dizendo o seguinte:

O texto de um "tooltip" (dica). Se a propriedade não é definida, então o "tooltip" gerado automaticamente pelo terminal é exibido. Um "tooltip" pode ser desabilitado através da atribuição do valor "\n" (quebra de linha) a ele.

Assim, este valor default, que szDescription está recebendo. Na verdade, não influenciará a informação que estará sendo colocada na propriedade OBJPROP_TEXT, isto nas linhas 29 e 38. Mas impedirá que o terminal do MetaTrader 5, venha a gerar um valor, para a propriedade OBJPROP_TOOLTIP, que é declarada nas linhas 30 e 39.

Mas como teremos acesso a esta propriedade OBJPROP_TOOLTIP? Ela não é a mesma coisa de OBJPROP_TEXT? Não, elas não são a mesma coisa. A propriedade OBJPROP_TEXT, é justamente a que você vê quando o algum objeto permite que você adicione um texto a ele. Um caso, de objeto que permite isto é o objeto de linha horizontal. Mas esta propriedade não está presente em todos os objetos.

Diferente da propriedade OBJPROP_TOOLTIP, que estará presente em todos os objetos no gráfico. Mas o texto de ambas propriedades não necessariamente tem que ser o mesmo. Eles podem ser diferentes. Já que a propriedade OBJPROP_TOOLTIP, só tem seu texto apresentado, quando você posiciona o mouse sobre um objeto por um tempo. Neste momento, irá surgir uma pequena janela, com a informação que estiver presente na propriedade OBJPROP_TOOLTIP.

Caso você nunca tenha notado isto, na animação logo abaixo, você pode ver do que se trata a tal pequena janela. Assim como a forma de visualizar o que a propriedade OBJPROP_TOOLTIP, contem.

Note que o conteúdo e a forma de interação, assim como o objetivo de tal propriedade, seria como se fosse uma dica. Algo simples, direto e prático para muitas situações em geral. Todos os objetos podem receber algumas informações nesta propriedade. Sempre que desejar, ajudar um usuário a entender alguma de suas aplicações. Onde existem muitos botões, e muitas das vezes sendo estes botões ícones ou imagens. Use esta propriedade, para dar uma dica ao usuário. Ele irá lhe agradecer muito. Já que isto melhora a experiência dele junto a sua aplicação. Fica a dica.

Muito bem, estamos chegando ao fim deste artigo. Mas antes de terminar. Que tal unir a criação das linhas em uma única rotina. Assim você precisará de menos trabalho no futuro. Já que usaremos de outros meios para fazer com que estas linhas venham de fato a se mover. Então o código final, que será usado no próximo artigo é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Indicator for tracking an open position on the server."
04. #property version   "1.00"
05. #property indicator_chart_window
06. #property indicator_plots 0
07. //+------------------------------------------------------------------+
08. #define def_SufixLinePrice   "Price"
09. #define def_SufixLineTake    "Take"
10. #define def_SufixLineStop    "Stop"
11. //+------------------------------------------------------------------+
12. #include <Market Replay\Auxiliar\C_Terminal.mqh>
13. //+------------------------------------------------------------------+
14. input color user00 = clrRoyalBlue;          //Color Line Price
15. input color user01 = clrForestGreen;        //Color Line Take Profit
16. input color user02 = clrFireBrick;          //Color Line Stop Loss
17. //+------------------------------------------------------------------+
18. C_Terminal *Terminal;
19. struct st
20. {
21.     long       id;
22.     string     szPrefixName;
23. }glVariables;
24. //+------------------------------------------------------------------+
25. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n")
26. {
27.     if (price <= 0) return;
28.     (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == user00 ? ePriorityNull : ePriorityOrders))
29.     ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, price);
30.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TEXT, szDescription);
31.     ObjectSetString(glVariables.id, szObjName, OBJPROP_TOOLTIP, szDescription);
32.     ObjectSetInteger(glVariables.id, szObjName, OBJPROP_SELECTABLE, cor != user00);
33. }
34. //+------------------------------------------------------------------+
35. int OnInit()
36. {
37.     ZeroMemory(glVariables);
38.     Terminal = new C_Terminal();
39.     if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED;
40.     glVariables.id = (*Terminal).GetInfoTerminal().ID;
41.     glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET));
42.     CreateLineInfos(glVariables.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), user00, "Position opening price.");
43.     CreateLineInfos(glVariables.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point.");
44.     CreateLineInfos(glVariables.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point.");
45.     
46.     return INIT_SUCCEEDED;
47. }
48. //+------------------------------------------------------------------+
49. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
50. {
51.     return rates_total;
52. }
53. //+------------------------------------------------------------------+
54. void OnDeinit(const int reason)
55. {
56.     delete Terminal;
57.     if (glVariables.id > 0)
58.         ObjectsDeleteAll(glVariables.id, glVariables.szPrefixName);
59. }
60. //+------------------------------------------------------------------+

Código fonte do Indicador de posição

Este será o código que iremos modificar no próximo artigo. Como ele praticamente não mudou, acredito que você, apenas lendo este artigo, e pensando um pouco, conseguirá facilmente entender como ele funciona. O único detalhe, e este eu devo lhe aconselhar em não fazer. Será usar a mesma cor para as três linhas. Até que você pode usar a mesma cor para as linhas de stop loss e take profit. Mas não use a mesma cor para a linha de preço de abertura. Isto por que na linha 28, assim como na linha 32, usamos a cor como uma forma de separar as coisas. Mas isto não é algo assim tão grave. Apenas poderá lhe confundir e lhe deixar sem entender por que as coisas não estão funcionando como o esperado.


Considerações finais

Neste artigo, mostrei de maneira o mais simples e prática possível. Como você poderá usar um indicador como sendo uma forma de observar posições que estejam abertas. Isto junto ao servidor de negociação. Estou fazendo isto, desta forma e aos poucos, justamente para mostrar, que você não precisa necessariamente, colocar tais coisas em um Expert Advisor. Muitos de vocês, já devem estar bastante acostumados em fazer isto. Seja por um motivo, seja por outro qualquer. Mas a verdade é que isto é pura bobagem, já que conforme formos avançando nesta implementação, ficará claro, que você poderá criar, ou implementar diversos tipos diferentes de indicadores. Isto a fim de observar e interagir com posições ou ordens que estejam presentes no servidor. Ou no nosso caso, no serviço de replay/simulador.

Porém mesmo que a proposta principal aqui, seja de usar o indicador, no replay/simulador. Quero que você veja, que ainda não o apliquei em um ativo que esteja sendo simulado. Ou mesmo que estejamos fazendo replay. Estou usando e testando o indicador, em ativos reais. Com posições reais. Então não faz sentido você usar ele apenas no replay/simulador. Só quero que você tome o seguinte cuidado, ao usar ele. Ele somente irá mostrar uma única posição. Não adianta você ter duas ou mais posições abertas. E isto no caso de contas do tipo HEDGING, e esperar que o indicador funcione. Pois ele ainda não é capaz de fazer isto.

Em breve, iremos ver como é o processo correto, de usar tal indicador. Afim de que possamos visualizar mais de uma posição em aberto. No caso das contas do tipo NETTING, você não terá tal preocupação, visto que elas não permitem você operar vendido e comprado ao mesmo tempo no mesmo ativo. Mas contas do tipo HEDGING permitem tal coisa. E para é justamente para este caso específico, que iremos precisar fazer um pequeno ajuste, na forma de usar este indicador. Mas o custo para isto é tão baixo, que sinceramente vale apena você pensar em tirar tal peso de dentro do Expert Advisor. Isto por que ainda não mostrei tudo que este indicador pode nos proporcionar. Então no próximo artigo, iremos melhorar um pouco mais este indicador. Já que existe uma pequena falha aqui. E se você deseja saber que falha é esta. Veja o próximo artigo desta mesma sequência.

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)
Ganhe Vantagem em Qualquer Mercado (Parte IV): Índices de Volatilidade do Euro e do Ouro da CBOE Ganhe Vantagem em Qualquer Mercado (Parte IV): Índices de Volatilidade do Euro e do Ouro da CBOE
Vamos analisar dados alternativos selecionados pela Chicago Board Of Options Exchange (CBOE) para melhorar a precisão de nossas redes neurais profundas ao prever o símbolo XAUEUR.
Do básico ao intermediário: Eventos em Objetos (IV) Do básico ao intermediário: Eventos em Objetos (IV)
Neste artigo iremos terminar o que foi começado no artigo anterior. Ou seja, uma forma total e completamente interativa de redimensionar os objetos diretamente no gráfico. Apesar do fato de muitos imaginarem que para fazer tal coisa, seria necessário muito mais conhecimento sobre MQL5. Você irá notar que usando conceitos simples e um conhecimento muito básico, podemos implementar uma forma de trabalhar com os objetos diretamente no gráfico. Algo que terá um resultado bem divertido e bastante interessante.
Expert Advisor Auto-otimizável com MQL5 e Python (Parte IV): Empilhamento de Modelos Expert Advisor Auto-otimizável com MQL5 e Python (Parte IV): Empilhamento de Modelos
Hoje, vamos demonstrar como você pode construir aplicações de trading com IA capazes de aprender com os próprios erros. Vamos demonstrar uma técnica conhecida como stacking (empilhamento), na qual usamos 2 modelos para fazer 1 previsão. O primeiro modelo é tipicamente um aprendiz mais fraco, e o segundo modelo normalmente é um modelo mais poderoso que aprende com os resíduos do nosso aprendiz mais fraco. Nosso objetivo é criar um conjunto de modelos (ensemble), na esperança de alcançar maior acurácia.
Simulação de mercado: Position View (I) Simulação de mercado: Position View (I)
O conteúdo, que veremos a partir de agora, é muito mais complicado em termos de teorias e conceitos. Tentarei deixar o conteúdo o mais simples quanto for possível fazer. A parte referente a programação em si. É até bastante simples e direta. Mas se você não compreender toda a teórica, que está debaixo dos panos. Ficará completamente sem meios para poder melhorar, ou mesmo adaptar o sistema de replay/simulador. A algo diferente do que irei mostrar. Meu intuito não é que você simplesmente compile e use o código que estou mostrando. Quero que você aprenda, entenda e se possível, possa criar algo ainda melhor.