English Русский 中文 Español Deutsch 日本語
preview
Simulação de mercado (Parte 01): Cross Order (I)

Simulação de mercado (Parte 01): Cross Order (I)

MetaTrader 5Testador |
387 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Desenvolvendo um sistema de Replay (Parte 78): Um novo Chart Trade (V), mostrei como o Expert Advisor conseguirá entender o que o Chart Trade estará informando a ele. A informação que o Chart Trade irá de fato passar, isto para o Expert Advisor, dependerá da interação do usuário com o Chart Trade. Ou seja, quando o usuário interagir com o botão de compra, venda ou fechamento de posição, uma mensagem será repassada ao gráfico. O Expert Advisor, que estiver no gráfico, tem como uma das tarefas interceptar, decodificar e executar a tarefa que estiver sendo informada na mensagem.

Apesar deste mecanismo ser bastante simples e igualmente bastante confiável. Temos um pequeno problema. Bem, na verdade não é exatamente um problema, e sim um inconveniente. Este tal inconveniente precisa ser resolvido, antes que realmente venhamos a enviar ordens para o servidor de negociação.

Se você não faz ideia do que se trata, talvez seja pelo motivo de você não operar ativos, ou melhor dizendo, contratos futuros. Tais tipos de ativo, tem um prazo de validade. E muitas das vezes, temos dois tipos sendo negociados. Um tipo cheio, que é definido desta forma, por conta que nele temos um volume maior. E o tipo mini, normalmente este tipo mini, poderia ser entendido como uma fração do tipo cheio, facilitando assim certos tipos de estratégia.

Não irei de fato entrar aqui no mérito, ou na descrição de tais estratégias. Mas o fato é que muitas vezes, precisamos de um número menor de volume, ou de contratos, a fim de ter a nossa estratégia sendo criada. Para quem vier a se interessa sobre o assunto, pesquise sobre estratégias de HEDGE. Mas para nos aqui, como programadores, o que realmente nos interessa é como conseguir fazer uma operação no minicontrato, tendo no gráfico o contrato cheio.

Mas além deste detalhe, temos um outro problema, e este se encontra relacionado a estratégias de longo prazo. Novamente, não entrarei nos detalhes, mas sempre que um contrato vence, e este vencimento é sempre conhecido por todos. Um novo contrato, ou melhor, uma nova série, se inicia. Isto para quem opera em prazos mais longos, que envolve o uso de várias séries subsequentes, é um baita de um problema. Isto por que, todos os indicadores e médias terão que recomeçar novamente a serem calculados.

Para compreender a fundo este problema, vamos usar o contrato de dólar futuro, que é negociado na B3 ( Bolsa do Brasil ). Este contrato de dólar futuro, tem um vencimento mensal. Ou seja, todo mês, uma série se encerra e uma nova série começa. Considerando que temos em média 20 dias de negociação ( cinco dias úteis, em média, durante quatro semanas por mês ), teremos sérios problemas em utilizar por exemplo, uma média móvel de 20 períodos. Isto por que quando a média vier a ser de fato calculada, podendo assim ser plotada no gráfico. O contrato irá de fato vencer e um novo será iniciado. Isto considerando apenas a média de 20 períodos. Fora outros indicadores, que precisam de períodos ainda maiores para poderem ser plotados. Ou seja, um baita de um problema.

Por conta disto, temos a possibilidade de usar o histórico do contrato futuro. Porém o fato de podermos usar o histórico, não resolve o problema. Na verdade ele criar outros problemas para nos, programadores. Lembre-se de que para o operador do contrato, não importa como o servidor irá de fato receber as informações, ou como as informações estão sendo plotadas no gráfico. O operador do contrato, quer apenas que as informações, e suas operações sejam de fato mostradas e executadas. Depende de nos, programadores, resolver este problema, de como plotar as informações e repassar os pedidos feitos no gráfico ao servidor de negociação.

No artigo Desenvolvendo um Expert Advisor de negociação do zero (Parte 11): Sistema CROSS ORDER expliquei alguns detalhes relacionados a isto. Porém, aqui nesta sequência, que envolve também o uso de um replay/simulador. Nosso problema se torna ainda maior. No entanto, vamos fazer como Napoleão. Dividir para conquistar. Vamos dividir este problema, para conseguir desenvolver a solução, a fim de conquistar terreno. Para finalmente conseguir desenvolver um sistema de ordens simulado. Vamos então começar fazendo o seguinte: Cobrir a questão do uso de indicadores em contratos futuros. E como o dólar futuro, é o caso mais extremo que conheço, iremos de fato focar nele. Mas você deve compreender, que o que será explicado, pode e deve ser adaptado para outros casos igualmente complicados. Ou que envolve os mesmos conceitos que serão aplicados aqui, como operações envolvendo outros tipos de contratos.


Começando a implementar a solução

No caso do artigo, que mencionei acima, onde foi desenvolvido um sistema de ordens cruzadas, ou CROSS ORDER, fazer alguns ajustes, a fim de cobrir outros tipos de contrato era relativamente bastante complicado. No entanto, por motivos práticos, aqui faremos as coisas de forma a tornar tais ajustes bem mais simples. Não para o operador, mas sim para nos, que precisamos programar a coisa toda. O operador terá que se adequar ao que iremos de fato fazer. Mas para ele será bem mais simples. Pois daremos de fato, ao operador, a possibilidade se selecionar, se deseja operar o contrato cheio ou o mini.

Para fazer com que as coisas funcionem. Pelo menos neste primeiro momento, onde a comunicação se dará de fato com o servidor real de negociação. Precisaremos fazer algumas pequenas e bastante pontuais mudanças no código já existente. Vamos começar entendendo o seguinte fato. Como mencionei na introdução, o melhor gráfico a ser utilizado é o do histórico do contrato. Mas o histórico do contrato, não pode ser de fato negociado diretamente.

Para fazer isto, precisamos usar um sistema que nos permita, fazer o roteamento das ordens que são dadas no gráfico do histórico, para o contrato que o operador deseja. No caso lembre-se de que o operador poderá desejar fazer a operação no contrato cheio ou no mini. Mas não vamos nos preocupar com isto neste momento. Primeiro, precisamos entender este fato. O conteúdo que realmente se encontrará no gráfico, é o que se encontra no histórico do contrato. Ponto.

No caso da B3 ( Bolsa do Brasil ) os contratos futuros, tem seis nomenclaturas diferentes. Isto para cada contrato especifico. Ou seja, para os contratos cheios são seis tipos, e para os míni também são seis tipos. Ou seja, uma baita complicação. Mas isto a primeira vista. Pois apenas da nomenclatura definir seis tipos, deferentes. Eles na verdade são três tipos, divididos em dois modelos.

Muito bem, isto facilita bastante as coisas para nos. Mas de qualquer maneira, aconselho a você estudar as diferenças entre estes três tipos. Pois a informação que será mostrada no gráfico, difere e muito entre cada um dos tipos. Se no caso, você for apenas programar a solução, não deixe de avisar ao operador sobre estes três tipos. Pois muitos operadores desconhecem completamente isto. Agora se você, além de programar a solução, vier também a fazer uso da mesma. Redobro o conselho, pois você pode acabar se dando muito mal, se de fato não entender as diferenças nos tipos.

Então sabemos que são três os tipos de nomenclatura. E duas variações no mesmo tipo. Ok. Mas para nos programadores, o que importa não é isto. Isto é importante para o operador. Para nos o que importa é: Existem alguma regra nesta nomenclatura? E se sim, como podemos fazer uso desta regra a fim de conseguir criar um sistema de ordens cruzadas?

Muito bem, de fato tal regra existe. E já fazemos uso da mesma. E isto já algum tempo. Veja como este uso está sendo feito, observando o fragmento abaixo.

38. //+------------------------------------------------------------------+
39.       void CurrentSymbol(void)
40.          {
41.             MqlDateTime mdt1;
42.             string sz0, sz1;
43.             datetime dt = macroGetDate(TimeCurrent(mdt1));
44.             enum eTypeSymbol {WIN, IND, WDO, DOL, OTHER} eTS = OTHER;
45.       
46.             sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, 0, 3);
47.             for (eTypeSymbol c0 = 0; (c0 < OTHER) && (eTS == OTHER); c0++) eTS = (EnumToString(c0) == sz0 ? c0 : eTS);
48.             switch (eTS)
49.             {
50.                case DOL   :
51.                case WDO   : sz1 = "FGHJKMNQUVXZ"; break;
52.                case IND   :
53.                case WIN   : sz1 = "GJMQVZ";       break;
54.                default    : return;
55.             }
56.             for (int i0 = 0, i1 = mdt1.year - 2000, imax = StringLen(sz1);; i0 = ((++i0) < imax ? i0 : 0), i1 += (i0 == 0 ? 1 : 0))
57.                if (dt < macroGetDate(SymbolInfoInteger(m_Infos.szSymbol = StringFormat("%s%s%d", sz0, StringSubstr(sz1, i0, 1), i1), SYMBOL_EXPIRATION_TIME))) break;
58.          }
59. //+------------------------------------------------------------------+

Fragmento do arquivo C_Terminal.mqh

Este fragmento, faz parte do código fonte do arquivo de cabeçalho C_Terminal.mqh. Observe que na linha 44 definimos os nome dos contratos futuros que estaremos cobrindo. Você pode adicionar outros nomes a esta lista, caso deseje trabalhar com outros contratos, como por exemplo milho, boi, S&P, euro e por ai vai. Mas lembre-se se observar as regras de nomenclatura para cada contrato, a fim de saber como definir o contrato vigente. Pois este procedimento visto acima, não retorna um contrato passado e muito menos um contrato que estará vigente daqui dois ou mais vencimentos. Este procedimento sempre retorna o contrato atualmente vigente.

Para fazer isto, ele captura na linha 46, os três primeiros caracteres do nome do ativo. Não importa o ativo, ele sempre irá de fato capturar os três primeiros. Isto por que a regra de nomenclatura na B3 (Bolsa do Brasil) indica que os três primeiros carácteres do nome do ativo, diz que ativo estamos usando. Já que o ativo no gráfico, pode não necessariamente ser um contrato futuro. Nesta mesma linha 46, armazenamos o nome do ativo na variável, que conterá o nome, para todos demais códigos. Preste atenção a este fato.

Agora na linha 47, fazemos uma varredura, na enumeração de nomes de contratos que estamos implementando. Veja que a ideia aqui, é capturar o nome correto. Por isto que na enumeração da linha 44, precisamos que o nome se pareça com o nome do contrato. E como a B3 (Bolsa do Brasil) utiliza carácteres maiúsculos, precisamos que eles sejam maiúsculos na enumeração. Quando o contrato for encontrado, ou a lista terminar o laço da linha 47 finalizará.

Então poderemos testar na linha 48, qual o valor encontrado. Caso nenhuma correspondência seja feita, teremos a execução do código na linha 54. Em qualquer outro caso, iremos de fato iniciar a criação da nomenclatura do contrato. A nomenclatura final, de fato se dá na linha 57, onde testamos e verificamos se o contrato que o procedimento criou o nome é o atual. Ou seja, o próprio procedimento varrerá a lista de possíveis contratos futuros, até encontrar o contrato atualmente vigente.

Mas existe um ponto, em todo este procedimento, que você deve ficar atento. O mesmo irá de fato usar o nome base do contrato com base no nome do ativo. Ou seja, você poderá apenas fazer a transcrição do histórico do contrato, para o nome do contrato atual. Não é possível fazer, no código mostrado acima, a transição do histórico do contrato cheio para o contrato atual vigente no contrato míni. Este é o tal inconveniente que precisamos resolver, e que iremos de fato resolver neste artigo.

Ao fazer isto, daremos ao operador, a possibilidade de selecionar, se deseja usar o contrato cheio, ou o contrato mini na negociação. Isto usando e tendo no gráfico o histórico de um dos contratos, seja ele o cheio, seja ele o mini. Muito bem, vamos então fazer isto, de forma a precisar mudar, e se necessário adicionar o mínimo de código. Já que quanto mais código for modificado e adicionado, maior será a possibilidade das coisas darem errado.

Para cumprir este objetivo, o novo código do fragmento acima, foi modificado e ficou como mostrado abaixo:

38. //+------------------------------------------------------------------+
39.       void CurrentSymbol(bool bUsingFull)
40.          {
41.             MqlDateTime mdt1;
42.             string sz0, sz1;
43.             datetime dt = macroGetDate(TimeCurrent(mdt1));
44.             enum eTypeSymbol {WIN, IND, WDO, DOL, OTHER} eTS = OTHER;
45.       
46.             sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, 0, 3);
47.             for (eTypeSymbol c0 = 0; (c0 < OTHER) && (eTS == OTHER); c0++) eTS = (EnumToString(c0) == sz0 ? c0 : eTS);
48.             switch (eTS)
49.             {
50.                case DOL   :
51.                case WDO   : sz1 = "FGHJKMNQUVXZ"; break;
52.                case IND   :
53.                case WIN   : sz1 = "GJMQVZ";       break;
54.                default   : return;
55.             }
56.             sz0 = EnumToString((eTypeSymbol)(((eTS & 1) == 1) ? (bUsingFull ? eTS : eTS - 1) : (bUsingFull ? eTS + 1: eTS)));
57.             for (int i0 = 0, i1 = mdt1.year - 2000, imax = StringLen(sz1);; i0 = ((++i0) < imax ? i0 : 0), i1 += (i0 == 0 ? 1 : 0))
58.                if (dt < macroGetDate(SymbolInfoInteger(m_Infos.szSymbol = StringFormat("%s%s%d", sz0, StringSubstr(sz1, i0, 1), i1), SYMBOL_EXPIRATION_TIME))) break;
59.          }
60. //+------------------------------------------------------------------+

Fragmento do arquivo C_Terminal.mqh

Notem, que as mudanças foram mínimas. A primeira delas foi adicionar um parâmetro que será recebido pela função. Isto na linha 39. Tal argumento visa dizer ao procedimento, se o nome do contrato a ser montado, deverá ser o contrato cheio, ou minicontrato. Esta escolha quem irá de fato fazer será o operador. Nos como programadores devemos e daremos ao operador a oportunidade de usar o gráfico que bem desejar. Isto é claro, desde que os dados do ativo a ser colocado no gráfico, represente de alguma forma o contrato a ser negociado. Podemos, como programadores fazer coisas bem mais exóticas, mas não vamos complicar o que temos de fazer.

Muito bem, além desta mudança na linha 39, foi adicionada uma nova linha. Apesar de tal adição, não ser de fato necessária, já que poderíamos mudar o código. Mas para facilitar a explicação, mas principalmente para que você caro leitor consiga entender o que está sendo feito. Preferi adicionar esta linha 56. A mesma poderia ser colocada no lugar que a variável sz0 se encontra na linha 58, e funcionaria da mesma forma, no entanto a explicação ficaria muito confusa e de difícil compreensão.

Então para quem não está conseguindo entender, o que esta linha 56 está fazendo na variável sz0. Vamos aos detalhes da explicação. Observe que estamos ignorando, qualquer coisa que esteja relacionada ao nome do ativo. O que estamos fazendo é transformando a enumeração da linha 44 em uma string. Isto por que o MQL5 nos permite fazer isto, ao usar a função EnumToString.

Agora vem um detalhe, que talvez possa dificultar as coisas para você. Isto caso de você esteja trabalhando, com algum contrato futuro, em que não exista um contrato cheio e um mini. Este tipo de coisa é bastante comum, quando se fala em COMMODITIES. Mas para o que quero mostrar, que são índices e moeda, no caso o dólar, existem ambos os contratos, tanto o mini quanto o cheio.

A enumeração sempre começa com um valor igual a zero, salvo você venha a definir um valor para início da enumeração. Sendo assim, os minicontratos estão sendo definidos como valores pares, e os contratos cheios como valores ímpares. É importante você entender isto. Os valores estão na forma binária, e isto também é importante você saber. Mas o principal é saber como isolar um bit em particular. No caso dos valores binários, o bit menos significativo, ou seja, o mais à direita, indica se o valor é par ou ímpar. Então ao fazermos uma operação AND a fim de isolar este bit menos significativo, podemos verificar se o valor é par ou ímpar. Lembre-se novamente, na enumeração os minicontratos são pares, e os contratos cheios são ímpares.

Então caso o valor seja, por exemplo ímpar, teremos a execução da primeira parte do operador ternário. Caso o valor seja par, teremos a execução da segunda parte do operador ternário. Até neste ponto, acredito que você possa ter entendido. Então fazemos um novo teste, isto em cada parte do operador ternário, de forma que teremos um novo operador ternário. Neste segundo operador ternário, o teste tem como objetivo, ajustar o valor da variável eTS para que ela indique o nome correto a ser usado no contrato.

Então vamos entender o seguinte: Se o contrato for por exemplo o WDO, o valor da variável eTS é dois, ou seja, um valor par. Neste caso a segunda parte do primeiro operador ternário será executada. Quando esta segunda parte for executada, um novo operador ternário, fará um novo teste, este tem como objetivo, verificar se na chamada do procedimento, queremos usar o contrato cheio ou minicontrato.

Caso queiramos usar o contrato cheio, este segundo operador ternário, irá de fato fazer com que a variável eTS seja incrementada em um. Ou seja, o valor que antes era dois, passará a ser três, e ao olhar a terceira posição na enumeração vemos que o dado é o DOL. Quando o MQL5, executar a função EnumToString, este valor três será transformado na string DOL, permitindo assim, que o nome do contrato seja o do contrato cheio. Mesmo que no gráfico o ativo visto, seja o histórico do contrato do mini dólar.

A mesma coisa vale ao contrário. Se você estiver no gráfico, o histórico do contrato do dólar cheio, e informar ao procedimento que deseja operar o contrato do mini dólar. Os testes farão com que o primeiro operador ternário seja verdadeiro, fazendo a primeira parte se executada, quando esta primeira parte for executada, o segundo operador ternário, irá de fato falhar, fazendo com que o valor de eTS que era de três, ou seja, ímpar, venha a ser subtraído em uma unidade, se tornando assim dois.

Resumindo: O valor que a linha 47 encontrar, será reajustado na linha 56, de forma que o nome do contrato venha a corresponder ao esperado pelo operador. Seja que ele esteja querendo operar o minicontrato ou o contrato cheio. O único requisito é que o gráfico precise ser do histórico de um dos contratos.

Muito legal, muito bem, muito bonito. Mas suponhamos que exista um caso em que não temos um minicontrato, ou seja, temos apenas o contrato futuro cheio. Como podemos lidar com um caso deste? Neste caso, você pode pensar que existem duas soluções possíveis. Não é mesmo? Mas não, a solução neste caso é apenas uma, pois se você estiver pensando em duplicar o valor na enumeração de forma a se ter um valor par e ímpar, o compilador não irá de forma alguma aceitar. Porém, você pode fazer o seguinte: Pode colocar na enumeração, os contratos em uma ordem lógica, de forma que ao testar um determinado valor. Caso não exista minicontratos, a variável sz0, não precise mudar. Então a partir deste valor devidamente definido e conhecido, a mudança não ocorria. Isto lhe forçará a fazer um teste extra. Mas não é nada difícil ou complicado de ser feito.

Com isto solucionamos a primeira parte do problema. Mas não estamos com tudo ainda resolvido. Para passar a resolver, mais um detalhe, precisamos mudar uma outra coisa, ainda no arquivo de cabeçalho C_Terminal.mqh. Tal coisa é o constructor da classe, pois é ele o responsável por chamar o procedimento mostrado acima. O constructor original deverá ser modificado para a versão mostrada abaixo.

72. //+------------------------------------------------------------------+      
73.       C_Terminal(const long id = 0, const uchar sub = 0, const bool bUsingFull = false)
74.          {
75.             m_Infos.ID = (id == 0 ? ChartID() : id);
76.             m_Mem.AccountLock = false;
77.             m_Infos.SubWin = (int) sub;
78.             CurrentSymbol(bUsingFull);
79.             m_Mem.Show_Descr = ChartGetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR);
80.             m_Mem.Show_Date  = ChartGetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE);
81.             ChartSetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR, false);
82.             ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_DELETE, true);
83.             ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, true);
84.             ChartSetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE, false);
85.             m_Infos.nDigits = (int) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_DIGITS);
86.             m_Infos.Width   = (int)ChartGetInteger(m_Infos.ID, CHART_WIDTH_IN_PIXELS);
87.             m_Infos.Height  = (int)ChartGetInteger(m_Infos.ID, CHART_HEIGHT_IN_PIXELS);
88.             m_Infos.PointPerTick  = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_SIZE);
89.             m_Infos.ValuePerPoint = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_VALUE);
90.             m_Infos.VolumeMinimal = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_VOLUME_STEP);
91.             m_Infos.AdjustToTrade = m_Infos.ValuePerPoint / m_Infos.PointPerTick;
92.             m_Infos.ChartMode   = (ENUM_SYMBOL_CHART_MODE) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_CHART_MODE);
93.             if(m_Infos.szSymbol != def_SymbolReplay) SetTypeAccount((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE));
94.             ChartChange();
95.          }
96. //+------------------------------------------------------------------+

Fragmento do arquivo C_Terminal.mqh

Note que são duas mudanças bem simples. A primeira é na linha 73, onde adicionamos um novo parâmetro. Este novo parâmetro é usado na linha 78, onde chamamos o procedimento mostrado e explicado acima. Observem que por padrão, estou definindo que daremos prioridade ao uso de minicontratos. Mas queremos e desejamos que o operador, faça a escolha que melhor que couber. Assim será preciso fazer alguns pequenos e poucos ajustes em determinados pontos no código.

Já que ainda não estamos de fato, mexendo no código do Expert Advisor. Precisamos e vamos fazer a mudança no código do Chart Trade. Mas para separar melhor as coisas, vamos ver isto em um novo tópico.


Tornando o Chart Trade um sistema cross order

As mudanças no Chart Trade, para que ele consiga trabalhar como cross order, são bem simples. Apesar de que, você pode desejar adicionar, algum objeto que permita ao operador, mudar diretamente o cross order. Aqui não farei isto. A ideia é fazer o mínimo possível de mudanças no código. E adicionar um objeto para que o operador, possa mudar diretamente no Chart Trade, o tipo de cross order. Nos forçaria a adicionar muito mais código, apenas para cobrir tal funcionalidade. No entanto, podemos permitir que o operador mude o cross order, ao modificar as configurações do indicador. E fazer isto, além de ser muito simples, trará muita pouca mudança no código já existente. A primeira coisa que faremos é mostrada no código abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Chart Trade Base Indicator."
04. #property description "See the articles for more details."
05. #property version   "1.80"
06. #property icon "/Images/Market Replay/Icons/Indicators.ico"
07. #property link "https://www.mql5.com/pt/articles/12536"
08. #property indicator_chart_window
09. #property indicator_plots 0
10. //+------------------------------------------------------------------+
11. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh>
12. //+------------------------------------------------------------------+
13. #define def_ShortName "Indicator Chart Trade"
14. //+------------------------------------------------------------------+
15. C_ChartFloatingRAD *chart = NULL;
16. //+------------------------------------------------------------------+
17. enum eTypeContract {MINI, FULL};
18. //+------------------------------------------------------------------+
19. input ushort         user01 = 1;         //Leverage
20. input double         user02 = 100.1;     //Finance Take
21. input double         user03 = 75.4;      //Finance Stop
22. input eTypeContract  user04 = MINI;      //Cross order in contract
23. //+------------------------------------------------------------------+
24. int OnInit()
25. {
26.    chart = new C_ChartFloatingRAD(def_ShortName, new C_Mouse(0, "Indicator Mouse Study"), user01, user02, user03, (user04 == FULL));
27.    
28.    if (_LastError >= ERR_USER_ERROR_FIRST) return INIT_FAILED;
29. 
30.    return INIT_SUCCEEDED;
31. }
32. //+------------------------------------------------------------------+
33. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
34. {
35.    return rates_total;
36. }
37. //+------------------------------------------------------------------+
38. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
39. {
40.    if (_LastError < ERR_USER_ERROR_FIRST) 
41.       (*chart).DispatchMessage(id, lparam, dparam, sparam);
42. }
43. //+------------------------------------------------------------------+
44. void OnDeinit(const int reason)
45. {
46.    switch (reason)
47.    {
48.       case REASON_INITFAILED:
49.          ChartIndicatorDelete(ChartID(), 0, def_ShortName);
50.          break;
51.       case REASON_CHARTCHANGE:
52.          (*chart).SaveState();
53.          break;
54.    }
55. 
56.    delete chart;
57. }
58. //+------------------------------------------------------------------+

Código fonte do Indicador Chart Trade

Observe que foi adicionada a linha 17, onde temos uma enumeração. Esta tem por finalidade ajudar ao operador, ou usuário, o que será definido. Note que estamos fazendo uso desta enumeração na linha 22. Este é o ponto, onde o operador ou usuário, fará a escolha se estará, sendo usado o contrato cheio ou minicontrato pelo Expert Advisor. Existe uma complicação aqui, neste ponto. Pois o ideal seria fazer a seleção no Expert Advisor, e não aqui no Chart Trade. Mas já que por hora, o Chart Trade e o Expert Advisor, são duas entidades distintas e separadas. Vamos fazer as coisas assim.

Mas o real problema, não está aqui no Chart Trade ou no Expert Advisor. Pois como você viu no artigo passado, podemos controlar o Expert Advisor pelo Chart Trade. O problema está realmente é em uma outra coisa que será desenvolvida futuramente. Ali é que realmente temos o grande problema. Já que tudo irá de fato passar pelo Expert Advisor. Então o ideal seria configurar as coisas nele. Mas novamente, por hora e apenas para demonstração, já que o Chart Trade e o Expert Advisor estão separados, vamos deixar as coisas assim.

Este valor configurado, é usado na linha 26. Mas observe que, estamos repassando um valor booleano para dentro do constructor, e não um valor numérico. Por que? O motivo é que para o usuário, um valor booleano pode não ser tão explicativo. Mas para nos, programadores um valor booleano é bem expressivo, já que estamos apenas testando duas condições. Você usuário vai usar um contrato cheio ou um minicontrato. Por isto o valor booleano é adequado para nos programadores. Assim sendo, podemos passar para o constructor da classe, para entender como isto irá se refletir no código. Já que precisaremos mexer apenas no constructor. Vamos ver isto em um fragmento que pode ser mostrado abaixo.

213. //+------------------------------------------------------------------+
214.       C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const short Leverage, const double FinanceTake, const double FinanceStop, const bool bUsingFull)
215.          :C_Terminal(0, 0, bUsingFull)
216.          {
217.             m_Mouse = MousePtr;
218.             m_Info.IsSaveState = false;
219.             if (!IndicatorCheckPass(szShortName)) return;
220.             if (!RestoreState())
221.             {
222.                m_Info.Leverage = Leverage;
223.                m_Info.IsDayTrade = true;
224.                m_Info.FinanceTake = FinanceTake;
225.                m_Info.FinanceStop = FinanceStop;
226.                m_Info.IsMaximized = true;
227.                m_Info.minx = m_Info.x = 115;
228.                m_Info.miny = m_Info.y = 64;
229.             }
230.             CreateWindowRAD(170, 210);
231.             AdjustTemplate(true);
232.          }
233. //+------------------------------------------------------------------+

Fragmento do arquivo C_ChartFloatingRAD.mqh

Aqui a coisa é tão simples como foi no constructor da classe C_Terminal. Apenas adicionamos um novo parâmetro, a ser recebido pelo constructor, isto na linha 214. E o repassamos para o constructor da classe C_Terminal. Isto na linha 215. Mas simples que isto, impossível. Tanto que nem preciso explicar os detalhes envolvidos.

Apesar disto ser muito bacana, precisamos fazer mais uma pequena mudança. Na verdade, uma adição ao código na classe C_ChartFloatingRAD. Isto para que o Chart Trade, consiga dizer o Expert Advisor, o que está se passando, ou melhor dizendo. O que o usuário estará, esperando operar. Tal mudança pode ser visto no fragmento logo abaixo.

330.       case MSG_BUY_MARKET:
331.          ev = evChartTradeBuy;
332.       case MSG_SELL_MARKET:
333.          ev = (ev != evChartTradeBuy ? evChartTradeSell : ev);
334.       case MSG_CLOSE_POSITION:
335.          if ((m_Info.IsMaximized) && (sz < 0))
336.          {
337.             string szTmp = StringFormat("%d?%s?%s?%c?%d?%.2f?%.2f", ev, _Symbol, GetInfoTerminal().szSymbol, (m_Info.IsDayTrade ? 'D' : 'S'),
338.                                         m_Info.Leverage, FinanceToPoints(m_Info.FinanceTake, m_Info.Leverage), FinanceToPoints(m_Info.FinanceStop, m_Info.Leverage));                           
339.             PrintFormat("Send %s - Args ( %s )", EnumToString((EnumEvents) ev), szTmp);
340.             EventChartCustom(GetInfoTerminal().ID, ev, 0, 0, szTmp);
341.          }
342.       break;

Fragmento do arquivo C_ChartFloatingRAD.mqh

Neste fragmento a mudança é tão sutil que pode passar desapercebida. Ela está na linha 337, onde adicionamos um novo valor, a ser repassado para o Expert Advisor. Tal valor, visa dizer ao Expert Advisor, o nome do ativo, ou contrato que está sendo visto no Chart Trade. Já digo logo de cara, que esta mudança forçará uma outra mudança no Expert Advisor. Mas isto será visto depois.


Considerações finais

Apesar do que foi feito neste artigo, mostrar o quando podemos fazer dentro do MQL5. Temos outros problemas, a serem resolvidos, justamente por conta do que foi feito aqui neste artigo. Tal tipo de coisa, está longe de ser simples, e de ser completamente e facilmente resolvida. Já que ao usar um sistema de cross order, que permite ao usuário do Chart Trade, dizer ao Expert Advisor, que o gráfico do ativo, não representa o ativo a ser operado. Causa enormes problemas. Muitos destes problemas não são exatamente por conta do Chart Trade, ou do Expert Advisor. Isto já posso deixar claro.

O problema de fato acontece, é quando fazemos uso de algo, que você caro leitor, ainda não viu. Pois ainda não mencionei nenhuma parte do código que terá de ser criado ainda. Mas devo informar que o fato de permitir ao usuário, definir, no Chart Trade, qual o tipo de contrato a ser utilizado, não é a melhor solução. Pelo menos não vejo isto desta forma, neste momento.

Talvez, o que precisa ser mostrado ainda, venha a sofrer mudanças que tornarão a definição no Chart Trade, algo interessante e sustentável. Mas ainda estou pensando em uma forma simples de mostrar as coisas. Implementar uma solução pessoal é simples e rápido. Mas implementar algo que deverá ser explicado e compreendido é complicado e trabalhoso. Então aguardem futuras mudanças neste sistema Chart Trade - Expert Advisor. Pois elas com toda certeza ocorrerão.

No vídeo abaixo, você pode ver como o processo no gráfico.


Arquivos anexados |
Anexo.zip (490.53 KB)
Simulação de mercado (Parte 02): Cross Order (II) Simulação de mercado (Parte 02): Cross Order (II)
Diferente do que foi visto no artigo anterior, aqui vamos fazer o controle de seleção no Expert Advisor. Porém, esta não é uma solução ainda definitiva. Mas irá nos atender por hora. Então acompanhe o artigo para entender como implementar uma das soluções possíveis.
Do básico ao intermediário: Sobrecarga Do básico ao intermediário: Sobrecarga
Este talvez será o artigo mais confuso para você iniciante. Já que aqui mostrarei que nem sempre, teremos em um mesmo código, todas funções e procedimentos com nomes exclusivos. Podemos sim ter funções e procedimentos com um mesmo nome e isto é conhecido como sobrecarga. O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como sendo, uma aplicação cuja finalidade não venha a ser o aprendizado e estudo dos conceitos mostrados.
Do básico ao intermediário: Template e Typename (I) Do básico ao intermediário: Template e Typename (I)
Aqui neste artigo, começaremos a lidar com um dos conceitos, que muitos iniciantes evitam. Isto por conta de que, templates, não é um assunto que podemos dizer, ser simples de entender e utilizar. Já que muitos não compreendem o princípio básico que se encontra por baixo do que seria um template. Que é justamente a sobrecarga de funções e procedimentos.
Do básico ao intermediário: Ponto Flutuante Do básico ao intermediário: Ponto Flutuante
Este artigo é uma breve introdução ao que seria o ponto flutuante. Como este conteúdo é muito complicado, aconselho você o ler com calma e atenção. Não espere dominar o sistema de ponto flutuante de maneira rápida. O mesmo somente é dominado com o tempo e experiência de uso. Mas este artigo irá lhe ajudar a entender, por que as vezes sua aplicação, reporta um resultado diferente daquele esperado originalmente. O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como sendo, uma aplicação cuja finalidade não venha a ser o aprendizado e estudo dos conceitos mostrados.