Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XV): coleção de objetos-símbolo
Sumário
- Coleção de símbolos
- Objetos descendentes do objeto abstrato base 'símbolo'
- Classe para a coleção de símbolos
- Teste para a coleção de símbolos
- O que vem agora?
Conceito de coleção de símbolos
Na terceira parte da descrição da biblioteca já definimos o conceito de construção de classes-coleções de objetos, portanto não vamos nos afastar da estrutura de armazenamento de dados adotada. Assim, para a coleção de símbolo, precisamos criar a lista (na qual são armazenados os objetos descendentes da classe 'símbolo') criada no último artigo. Os descendentes de símbolos abstratos vão esclarecer os dados do símbolo e definir a disponibilidade das propriedades básicas do objeto-símbolo no programa. Além disso, esses objetos-símbolos vão ser distinguidos por sua afiliação a grupos (status do símbolo):
- Símbolo Forex — todos os símbolos Forex que não se enquadram nas seguintes categorias de símbolos forex:
- Símbolo Forex maior — categoria personalizada dos símbolos Forex mais usados
- Símbolo Forex menor — categoria personalizada dos símbolos Forex menos usados
- Símbolo Forex exótico — categoria personalizada dos símbolos Forex raramente usados
- Símbolo Forex rublo — categoria personalizada dos símbolos Forex contendo rublo
- Metal — categoria personalizada de símbolos-metal
- Índice — categoria personalizada de símbolos-índices
- Indicativo — categoria personalizada de símbolos-indicativos
- Símbolo de criptomoeda — categoria definida pelo usuário de símbolos-criptomoeda
- Símbolo de commodities — categoria definida pelo usuário de símbolos-commodities
- Símbolo bolsista — todos os símbolos de bolsistas que não se enquadram nas seguintes categorias:
- Futuros
- Contrato por diferença (CFD)
- Ações
- Obrigações
- Opções
- Ativo não negociável
- Símbolo personalizado
- Categoria geral — símbolos que não se enquadram nas categorias acima
Para determinar a qual o grupo pertence o símbolo (seu status), criaremos conjuntos de dados personalizados — arrays contendo nomes de
símbolos, nos quais procuraremos a categoria do símbolo ao qual ele deve pertencer. Se o símbolo não for encontrado na categoria de
personalizados (seu nome não está disponível em todos os arrays contendo nomes de símbolos especificados pelo usuário), o símbolo
será determinado por sua propriedade "método de cálculo de garantia" (
ENUM_SYMBOL_CALC_MODE), nela se
pode determinar se um símbolo pertence a alguma das categorias listadas acima. Quer dizer, realizamos uma pesquisa em duas
verificações: nas categorias, definidas pelo usuário, e se não conseguirmos definir a categoria, temos que defini-la usando o método
de cálculo de garantia. Previamente, foi planejado usar outro método — definir pelo nome da pasta na qual está o símbolo na árvore de
diretórios de símbolos no servidor. No entanto, esse método não é confiável, uma vez que os nomes de pastas podem estar em servidores
diferentes para o mesmo símbolo, é por essa razão que preferi não usá-lo.
A categoria personalizada tem precedência — porque se o usuário desejar que o símbolo, por exemplo, USDUSC esteja na categoria
"maior", é a sua escolha — e o símbolo estará presente, independentemente de ser indicativo.
Já decidimos sobre as categorias — para elas, criaremos as classes herdadas do símbolo abstrato necessárias, símbolo esse que criamos
no
último artigo.
Para armazenar todos os objetos dos símbolos, usamos a classe
CListObj, herdada da classe de biblioteca padrão
CArrayObj, que abordamos no quinto
artigo ao discutir a reorganização das classes da biblioteca. Nos programas baseados nesta biblioteca, é possível escolher com
qual lista de símbolo trabalhar:
- Apenas uma é o símbolo atual ao qual o programa está anexado
- Conjunto de símbolos predefinido especificado no programa
- Trabalho com a lista de símbolos que estão na janela 'Observação do Mercado'
- Trabalho com a lista completa de símbolos disponíveis no servidor
Assim, cobriremos a maioria das tarefas de programação necessárias para acessar os instrumentos-símbolos de trabalho.
Aqui é
necessário sublinhar dois pontos:
Primeiro, este é um trabalho com uma lista de símbolos da Observação do Mercado — neste modo, será preciso usar a pesquisa de eventos na
janela 'Observação do mercado' — para responder às alterações atempadamente (adicionar/remover um símbolo da lista e
classificá-lo com o mouse).
Em segundo lugar, ao trabalhar com a lista completa de símbolos disponíveis no servidor, é necessário considerar o
processamento normal do grande número possível de símbolos disponíveis — afinal, na primeira inicialização, será visível a
lista completa de símbolos no servidor e serão criados objetos-símbolos para os quais será preciso obter todas as suas
propriedades. Este processo não é rápido — quando uso um laptop comum, leva cerca de dois minutos criar toda a coleção de símbolos no
servidor.
Inicialmente, acho que, ao escolher este método de trabalho, é necessário pelo menos alertar o usuário sobre a possivelmente longa coleta de
informações iniciais.
Nos próximos artigos, abordaremos isso, bem como o acompanhamento de eventos de símbolos e de eventos da janela "Observação do
mercado", mas, por enquanto, criemos uma lista-coleção.
Para começar, criemos outro arquivo incluído, nele armazenaremos todos os dados necessários para a biblioteca — array de grupos de
símbolos personalizados, arquivos, imagens e outros conjuntos de dados necessários posteriormente para a biblioteca.
No diretório de localização da biblioteca \MQL5\Include\DoEasy\, criamos um novo arquivo de inclusão chamado Datas.mqh
e imediatamente inserimos nele alguns arrays, que eu já havia preparado com antecedência, depois de ter iterado várias contas e de
ter coletado dados - da estrutura em árvore da janela 'Observação do Mercado' - sobre os grupos de símbolos definidos em diferentes
servidores:
//+------------------------------------------------------------------+ //| Datas.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" //+------------------------------------------------------------------+ //| Conjuntos de dados | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Símbolos Forex Majors | //+------------------------------------------------------------------+ string DataSymbolsFXMajors[]= { "AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD","CADCHF","CADJPY","CHFJPY","EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD", "EURUSD","GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPNZD","GBPUSD","NZDCAD","NZDCHF","NZDJPY","NZDUSD","USDCAD","USDCHF","USDJPY" }; //+------------------------------------------------------------------+ //| Símbolos Forex Menors | //+------------------------------------------------------------------+ string DataSymbolsFXMinors[]= { "EURCZK","EURDKK","EURHKD","EURNOK","EURPLN","EURSEK","EURSGD","EURTRY","EURZAR","GBPSEK","GBPSGD" ,"NZDSGD","USDCZK","USDDKK","USDHKD","USDNOK","USDPLN","USDSEK","USDSGD","USDTRY","USDZAR" }; //+------------------------------------------------------------------+ //| Símbolos Forex Exotics | //+------------------------------------------------------------------+ string DataSymbolsFXExotics[]= { "EURMXN","USDCNH","USDMXN","EURTRY","USDTRY" }; //+------------------------------------------------------------------+ //| Símbolos Forex Rublo | //+------------------------------------------------------------------+ string DataSymbolsFXRub[]= { "EURRUB","USDRUB" }; //+------------------------------------------------------------------+ //| Símbolos Forex Indicativos | //+------------------------------------------------------------------+ string DataSymbolsFXIndicatives[]= { "EUREUC","USDEUC","USDUSC" }; //+------------------------------------------------------------------+ //| Símbolos-metais | //+------------------------------------------------------------------+ string DataSymbolsMetalls[]= { "XAGUSD","XAUUSD" }; //+------------------------------------------------------------------+ //| Símbolos commodities | //+------------------------------------------------------------------+ string DataSymbolsCommodities[]= { "BRN","WTI","NG" }; //+------------------------------------------------------------------+ //| Índices | //+------------------------------------------------------------------+ string DataSymbolsIndexes[]= { "CAC40","HSI50","ASX200","STOXX50","NQ100","FTSE100","DAX30","IBEX35","SPX500","NIKK225" "Volatility 10 Index","Volatility 25 Index","Volatility 50 Index","Volatility 75 Index","Volatility 100 Index", "HF Volatility 10 Index","HF Volatility 50 Index","Crash 1000 Index","Boom 1000 Index","Step Index" }; //+------------------------------------------------------------------+ //| Símbolos-criptomoedas | //+------------------------------------------------------------------+ string DataSymbolsCrypto[]= { "BCHUSD","BTCEUR","BTCUSD","DSHUSD","EOSUSD","ETHEUR","ETHUSD","LTCUSD","XRPUSD" }; //+------------------------------------------------------------------+ //| Opções | //+------------------------------------------------------------------+ string DataSymbolsOptions[]= { "BO Volatility 10 Index","BO Volatility 25 Index","BO Volatility 50 Index","BO Volatility 75 Index","BO Volatility 100 Index" }; //+------------------------------------------------------------------+
Como se pode ver na lista, esta é apenas uma enumeração dos nomes dos símbolos que adicionamos aos arrays necessários que definem o grupo de símbolos que estão em cada um dos arrays. Se desejado e necessário, pode-se processar a composição destes arrays contendo nomes de símbolos — enviar algo para outro array, adicionar/remover algo etc.
Um teste mais "rígido" do comportamento do objeto-símbolo abstrato deixou claro que o uso das constantes SYMBOL_MARGIN_LONG,
SYMBOL_MARGIN_SHORT, SYMBOL_MARGIN_STOP, SYMBOL_MARGIN_LIMIT e SYMBOL_MARGIN_STOPLIMIT não deu na obtenção da propriedade
desejada. Por isso, foi necessário substituir a maneira de receber essas propriedades, e começar a fazê-lo através da função
SymbolInfoMarginRate().
Como o tipo de ordem é
enviado para essa função, eu tive que
criar para cada um dos tipos de ordens, sua própria constante nas propriedades
reais do objeto-símbolo no arquivo Defines.mqh:
//+------------------------------------------------------------------+ //| Propriedades reais do símbolo | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_DOUBLE { SYMBOL_PROP_BID = SYMBOL_PROP_INTEGER_TOTAL, // Bid - melhor oferta de venda SYMBOL_PROP_BIDHIGH, // Bid máximo do dia SYMBOL_PROP_BIDLOW, // Bid máximo do dia SYMBOL_PROP_ASK, // Ask - melhor oferta de compra SYMBOL_PROP_ASKHIGH, // Ask máximo do dia SYMBOL_PROP_ASKLOW, // Ask mínimo do dia SYMBOL_PROP_LAST, // Preço da última transação SYMBOL_PROP_LASTHIGH, // Last máximo do dia SYMBOL_PROP_LASTLOW, // Last máximo do dia SYMBOL_PROP_VOLUME_REAL, // Volume do dia SYMBOL_PROP_VOLUMEHIGH_REAL, // Volume máximo do dia SYMBOL_PROP_VOLUMELOW_REAL, // Volume mínimo do dia SYMBOL_PROP_OPTION_STRIKE, // Preço de exercício da opção SYMBOL_PROP_POINT, // Valor de um ponto SYMBOL_PROP_TRADE_TICK_VALUE, // Valor SYMBOL_TRADE_TICK_VALUE_PROFIT SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT, // Valor calculado do tick para uma posição lucrativa SYMBOL_PROP_TRADE_TICK_VALUE_LOSS, // Valor calculado do tick para uma posição desfavorável SYMBOL_PROP_TRADE_TICK_SIZE, // Alteração mínima de preço SYMBOL_PROP_TRADE_CONTRACT_SIZE, // Tamanho do contrato de transação SYMBOL_PROP_TRADE_ACCRUED_INTEREST, // Juros corridos SYMBOL_PROP_TRADE_FACE_VALUE, // Valor nominal é o valor inicial do título estabelecido pelo emissor SYMBOL_PROP_TRADE_LIQUIDITY_RATE, // O índice de liquidez é a proporção do valor do ativo que pode ser usada como garantia SYMBOL_PROP_VOLUME_MIN, // Volume mínimo para realização da transação SYMBOL_PROP_VOLUME_MAX, // Volume máximo para realização da transação SYMBOL_PROP_VOLUME_STEP, // Incremento mínimo de alteração do volume para o realização da transação SYMBOL_PROP_VOLUME_LIMIT, // Volume total máximo permitido para posições abertas e ordens pendentes numa direção (compra ou venda) SYMBOL_PROP_SWAP_LONG, // Valor de swap em long SYMBOL_PROP_SWAP_SHORT, // Valor de swap em short SYMBOL_PROP_MARGIN_INITIAL, // Margem inicial SYMBOL_PROP_MARGIN_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção do instrumento SYMBOL_PROP_MARGIN_LONG_INITIAL, // Margem inicial para posição long SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL, // Margem inicial para ordens BuyStop SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL, // Margem inicial para ordens BuyLimit SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL, // Margem inicial para ordens BuyStopLimit SYMBOL_PROP_MARGIN_LONG_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para posições longas SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens BuyStop SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens BuyLimit SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens BuyStopLimit SYMBOL_PROP_MARGIN_SHORT_INITIAL, // Margem inicial para posições curtas SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL, // Margem inicial para ordens SellStop SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL, // Margem inicial para ordens SellLimit SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL, // Margem inicial para ordens SellStopLimit SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para posições curtas SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens SellStop SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens SellLimit SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Coeficiente de cobrança da margem de manutenção para ordens SellStopLimit SYMBOL_PROP_SESSION_VOLUME, // Volume total de transações na sessão atual SYMBOL_PROP_SESSION_TURNOVER, // Faturação total na sessão atual SYMBOL_PROP_SESSION_INTEREST, // Volume total de posições abertas SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME, // Volume total de ordens de compra atual SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME, // Volume total de ordens de venda atual SYMBOL_PROP_SESSION_OPEN, // Preço de abertura da sessão SYMBOL_PROP_SESSION_CLOSE, // Preço de fechamento da sessão SYMBOL_PROP_SESSION_AW, // Preço médio ponderado da sessão SYMBOL_PROP_SESSION_PRICE_SETTLEMENT, // Preço de liquidação da sessão atual SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN, // Valor mínimo permitido da sessão SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX, // Valor máximo permitido da sessão SYMBOL_PROP_MARGIN_HEDGED // Tamanho do contrato ou margem para um lote de posições sobrepostas (posições com várias direções segundo um mesmo símbolo). }; #define SYMBOL_PROP_DOUBLE_TOTAL (58) // Número total de propriedades reais #define SYMBOL_PROP_DOUBLE_SKIP (0) // Número de propriedades reais do símbolo que não são usadas na classificação //+------------------------------------------------------------------+
Consequentemente, a quantidade total de propriedades reais aumentou para 58 (em vez das 47 anteriores)
Da mesma maneira, tive que adicionar as constantes correspondentes à enumeração de possíveis critérios para classificar símbolos:
//+------------------------------------------------------------------+ //| Possíveis critérios para classificar símbolos | //+------------------------------------------------------------------+ #define FIRST_SYM_DBL_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP) #define FIRST_SYM_STR_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP) enum ENUM_SORT_SYMBOLS_MODE { //--- Classificar por propriedades de número inteiro SORT_BY_SYMBOL_STATUS = 0, // Classificar por status do símbolo SORT_BY_SYMBOL_CUSTOM, // Classificar por símbolo personalizado SORT_BY_SYMBOL_CHART_MODE, // Classificar por tipo de preço para construir barras – Bid ou Last (a partir da enumeração ENUM_SYMBOL_CHART_MODE) SORT_BY_SYMBOL_EXIST, // Classifica pelo fato de existir um símbolo com o mesmo nome SORT_BY_SYMBOL_SELECT, // Classificar pelo fato de o símbolo estar selecionado no Market Watch SORT_BY_SYMBOL_VISIBLE, // Classificar pelo fato de o símbolo selecionado ser exibido no Market Watch SORT_BY_SYMBOL_SESSION_DEALS, // Classificar pelo número de transações na sessão atual SORT_BY_SYMBOL_SESSION_BUY_ORDERS, // Classificar pelo número total de ordens de compra atualmente SORT_BY_SYMBOL_SESSION_SELL_ORDERS, // Classificar pelo número total de ordens de venda atualmente SORT_BY_SYMBOL_VOLUME, // Classificar pelo Volume - volume na última transação SORT_BY_SYMBOL_VOLUMEHIGH, // Classificar pelo Volume máximo do dia SORT_BY_SYMBOL_VOLUMELOW, // Classificar pelo Volume mínimo do dia SORT_BY_SYMBOL_TIME, // Classificar pela hora da última cotação SORT_BY_SYMBOL_DIGITS, // Classificar pelo número de casas decimais SORT_BY_SYMBOL_DIGITS_LOT, // Classificar pelo número de casas decimais no lote SORT_BY_SYMBOL_SPREAD, // Classificar pelo tamanho do spread em pontos SORT_BY_SYMBOL_SPREAD_FLOAT, // Classificar por spread flutuante SORT_BY_SYMBOL_TICKS_BOOKDEPTH, // Classificar pelo número máximo de ordens exibidas no livro de ofertas SORT_BY_SYMBOL_TRADE_CALC_MODE, // Classificar pelo método de cálculo do valor do contrato (a partir da enumeração ENUM_SYMBOL_CALC_MODE) SORT_BY_SYMBOL_TRADE_MODE, // Classifica pelo tipo de execução da ordem (a partir da enumeração ENUM_SYMBOL_TRADE_MODE) SORT_BY_SYMBOL_START_TIME, // Classificar pela data de início da negociação do instrumento (geralmente usado para futuros) SORT_BY_SYMBOL_EXPIRATION_TIME, // Classificar pela data de término da negociação do instrumento (geralmente usado para futuros) SORT_BY_SYMBOL_TRADE_STOPS_LEVEL, // Classificar pelo recuo mínimo em pontos em relação ao preço de fechamento atual para posicionar ordens Stop SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL, // Classificar pela distância de congelamento de operações (em pontos) SORT_BY_SYMBOL_TRADE_EXEMODE, // Classificar por modo de transação (a partir da enumeração ENUM_SYMBOL_TRADE_EXECUTION) SORT_BY_SYMBOL_SWAP_MODE, // Classificar pelo modelo de cálculo de swap (a partir da enumeração ENUM_SYMBOL_SWAP_MODE) SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS, // Classificar pelo dia da semana para calcular o swap triplo (a partir da enumeração ENUM_DAY_OF_WEEK) SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG, // Classificar pelo modo de cálculo da margem de cobertura pelo lado maior (Buy ou Sell) SORT_BY_SYMBOL_EXPIRATION_MODE, // Classificar por sinalizadores dos modos de expiração de ordem permitidos SORT_BY_SYMBOL_FILLING_MODE, // Classificar por sinalizadores dos modos de preenchimento de ordem permitidos SORT_BY_SYMBOL_ORDER_MODE, // Classificar por sinalizadores de tipos de ordem permitidos SORT_BY_SYMBOL_ORDER_GTC_MODE, // Classificar por expiração das ordens StopLoss e TakeProfit SORT_BY_SYMBOL_OPTION_MODE, // Classificar por tipo de opção (a partir da enumeração ENUM_SYMBOL_OPTION_MODE) SORT_BY_SYMBOL_OPTION_RIGHT, // Classificar por direito de opção (Call/Put) (a partir da enumeração ENUM_SYMBOL_OPTION_RIGHT) //--- Classificar por propriedades reais SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP, // Classificar por Bid SORT_BY_SYMBOL_BIDHIGH, // Classificar por Bid máximo do dia SORT_BY_SYMBOL_BIDLOW, // Classificar por Bid mínimo do dia SORT_BY_SYMBOL_ASK, // Classificar por Ask SORT_BY_SYMBOL_ASKHIGH, // Classificar por Ask máximo do dia SORT_BY_SYMBOL_ASKLOW, // Classificar por Ask mínimo do dia SORT_BY_SYMBOL_LAST, // Classificar pelo preço da última transação concluída SORT_BY_SYMBOL_LASTHIGH, // Classificar pelo Last máximo do dia SORT_BY_SYMBOL_LASTLOW, // Classificar pelo Last mínimo do dia SORT_BY_SYMBOL_VOLUME_REAL, // Classificar pelo Volume do dia SORT_BY_SYMBOL_VOLUMEHIGH_REAL, // Classificar pelo Volume máximo do dia SORT_BY_SYMBOL_VOLUMELOW_REAL, // Classificar pelo Volume mínimo do dia SORT_BY_SYMBOL_OPTION_STRIKE, // Classificar pelo preço de exercício da opção SORT_BY_SYMBOL_POINT, // Classificar pelo valor de um ponto SORT_BY_SYMBOL_TRADE_TICK_VALUE, // Classificar pelo valor SYMBOL_TRADE_TICK_VALUE_PROFIT SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT, // Classificar pelo valor calculado do tick para uma posição lucrativa SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS, // Classificar pelo valor calculado do tick para uma posição desfavorável SORT_BY_SYMBOL_TRADE_TICK_SIZE, // Classificar pela alteração de preço mínima SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE, // Classificar por tamanho do contrato comercial SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST, // Classificar por juros corridos SORT_BY_SYMBOL_TRADE_FACE_VALUE, // Classificar por valor nominal SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE, // Classificar por taxa de liquidez SORT_BY_SYMBOL_VOLUME_MIN, // Classificar pelo volume mínimo para realizar a transação SORT_BY_SYMBOL_VOLUME_MAX, // Classificar pelo volume máximo para realizar a transação SORT_BY_SYMBOL_VOLUME_STEP, // Classificar pelo passo mínimo de alteração do volumer para realizar a transação SORT_BY_SYMBOL_VOLUME_LIMIT, // Classificar pelo volume total máximo permitido de uma posição aberta e ordens pendentes numa direção SORT_BY_SYMBOL_SWAP_LONG, // Classificar pelo valor do swap em long SORT_BY_SYMBOL_SWAP_SHORT, // Classificar pelo valor do swap em short SORT_BY_SYMBOL_MARGIN_INITIAL, // Classificar pela margem inicial SORT_BY_SYMBOL_MARGIN_MAINTENANCE, // Classificar por margem de manutenção por instrumento SORT_BY_SYMBOL_MARGIN_LONG_INITIAL, // Classificar por margem inicial para posições longas SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL, // Classificar por margem inicial para ordens BuyStop SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL, // Classificar por margem inicial para ordens BuyLimit SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL, // Classificar por margem inicial para ordens BuyStopLimit SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE, // Classificar por margem de manutenção para posições longas SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE, // Classificar por margem de manutenção para BuyStop SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE, // Classificar por margem de manutenção para BuyLimit SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Classificar por margem de manutenção para BuyStopLimit SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL, // Classificar por margem inicial para posições curtas SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL, // Classificar por margem inicial para ordens SellStop SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL, // Classificar por margem inicial para ordens SellLimit SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL, // Classificar por margem inicial para ordens SellStopLimit SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE, // Classificar por margem de manutenção para posições curtas SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE, // Classificar por coeficiente de cobrança da margem de manutenção para SellStop SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE, // Classificar por coeficiente de cobrança da margem de manutenção para SellLimit SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Classificar por coeficiente de cobrança da margem de manutenção para SellStopLimit SORT_BY_SYMBOL_SESSION_VOLUME, // Classificar pelo volume total de transações na sessão atual SORT_BY_SYMBOL_SESSION_TURNOVER, // Classificar pelo rotatividade total na sessão atual SORT_BY_SYMBOL_SESSION_INTEREST, // Classificar pelo volume total de posições atual SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME, // Classificar pelo volume total de ordens no momento SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME, // Classificar pelo volume total de ordens de venda atualmente SORT_BY_SYMBOL_SESSION_OPEN, // Classificar pelo preço de abertura da sessão SORT_BY_SYMBOL_SESSION_CLOSE, // Classificar pelo preço de fechamento da sessão SORT_BY_SYMBOL_SESSION_AW, // Classificar pelo preço médio ponderado da sessão SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT, // Classificar pelo preço de entrega da sessão atual SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN, // Classificar pelo preço mínimo permitido por sessão SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX, // Classificar pelo preço máximo permitido por sessão SORT_BY_SYMBOL_MARGIN_HEDGED, // Classificar pelo tamanho ou margem do contrato para um lote de posições sobrepostas //--- Classificar por propriedades de string SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, // Classificar pelo nome do símbolo SORT_BY_SYMBOL_BASIS, // Classificar pelo nome do ativo subjacente para o derivado SORT_BY_SYMBOL_CURRENCY_BASE, // Classificar pela moeda base do instrumento SORT_BY_SYMBOL_CURRENCY_PROFIT, // Classificar pela moeda de lucro SORT_BY_SYMBOL_CURRENCY_MARGIN, // Classificar pela moeda na qual é calculada a garantia SORT_BY_SYMBOL_BANK, // Classificar pela fonte da cotação atual SORT_BY_SYMBOL_DESCRIPTION, // Classificar pela descrição de string do símbolo SORT_BY_SYMBOL_FORMULA, // Classificar pela fórmula para plotar o preço do símbolo personalizado SORT_BY_SYMBOL_ISIN, // Classificar pelo nome do símbolo no sistema de códigos internacionais de identificação de valores mobiliários - ISIN SORT_BY_SYMBOL_PAGE, // Classificar pelo endereço da página da web com informações do símbolo SORT_BY_SYMBOL_PATH // Classificar pelo caminho na árvore de símbolos }; //+------------------------------------------------------------------+
Bem, como estamos editando o arquivo Deines.mqh, inserimos imediatamente tudo o que precisamos nele, analisando simultaneamente o que estamos adicionando e por que é necessário.
Para uma coleção de símbolos, precisamos de um temporizador, porque precisamos atualizar os dados de todos os símbolos da coleção de acordo
com o ele. Além disso tem a particularidade de que precisaremos atualizar os dados de cotação de todos os símbolos e os dados restantes —
aqueles que podem ser alterados para serem rastreados na classe de eventos de símbolos (falaremos mais sobre isso no próximo artigo) e
também precisamos verificar a lista de símbolos no temporizador na 'Observação do Mercado' — para atempadamente responder às alterações e
atualizar a lista de coleções.
Precisamos atualizar os dados de cotação com mais frequência do que os dados de símbolo restantes e sua lista na janela 'Observação do Mercado'.
Portanto, precisamos de dois temporizador para uma coleção de símbolos — um temporizador de dados de cotação e um temporizador para as ações
restantes com listas de símbolos.
Inserimos as substituições de macro necessárias para dois temporizadores da coleção de símbolos:
//--- Parâmetros do temporizador1 da coleção de símbolos #define COLLECTION_SYM_PAUSE1 (100) // Pausa do temporizador1 da coleção de símbolos em milissegundos (para rastreamento de símbolos na observação do mercado) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Incremento do temporizador1 de símbolos #define COLLECTION_SYM_COUNTER_ID1 (3) // Identificador do contador do temporizador1 de símbolos //--- Parâmetros do temporizador2 da coleção de símbolos #define COLLECTION_SYM_PAUSE2 (300) // Pausa do temporizador2 de coleção de símbolos em milissegundos (para eventos da lista de símbolos na observação do mercado) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Incremento do contador do temporizador2 de símbolos #define COLLECTION_SYM_COUNTER_ID2 (4) // Identificador do contador do temporizador2 de símbolos
A diferença entre estes dados está apenas na pausa para cada temporizador e seus identificadores — para o primeiro temporizador, a pausa será de 100 milissegundos, para o segundo, 300.
Para cada coleção, temos nosso próprio identificador. A coleção de símbolos não é exceção.
Atribuímos um identificador
próprio à sua lista:
//--- Identificadores da lista de coleções #define COLLECTION_HISTORY_ID (0x7778+1) // Identificador da lista de coleção histórica #define COLLECTION_MARKET_ID (0x7778+2) // Identificador da lista de coleção de mercado #define COLLECTION_EVENTS_ID (0x7778+3) // Identificador da lista de coleção de eventos #define COLLECTION_ACCOUNT_ID (0x7778+4) // Identificador da coleção de contas #define COLLECTION_SYMBOLS_ID (0x7778+5) // Identificador da lista de coleção de símbolos
Para determinar a cor de fundo com a qual o símbolo é destacado na janela "Observação do mercado" e exibir sua descrição de string, no último artigo foi usada uma construção para comparar cores com a cor clrWhite — se o valor da propriedade for maior que o valor long da cor especificada, será considerado que a cor do plano de fundo não está definida:
property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Cor de fundo do símbolo na Observação do Mercado","Background color of the symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : #ifdef __MQL5__ (this.GetProperty(property)>clrWhite ? TextByLanguage(": (Ausente)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) :
No entanto, de acordo com os desenvolvedores, isso não é verdade, uma vez que o valor long da cor de plano de fundo do símbolo na janela
'Observação do Mercado', ao que parece, pode ser maior que o valor long da cor "branca". Isso significa que, em alguns casos, essa
verificação não retornará o resultado correto.
Para identificar corretamente a ausência de uma cor de plano de fundo, é preciso comparar o valor da propriedade com o valor CLR_DEFAULT e
CLR_NONE.
Definimos a substituição de macro do valor da cor padrão. (a cor 'ausente' CLR_NONE já existe em MQL5 e MQL4):
//--- Parâmetro de símbolos #define CLR_DEFAULT (0xFF000000) // Cor por padrão //+------------------------------------------------------------------+
Como resultado, a seção de substituição de macro para o arquivo Defines.mqh agora fica assim:
//+------------------------------------------------------------------+ //| Substituição de macros | //+------------------------------------------------------------------+ //--- "Descrição da função com o número da string de erro" #define DFUN_ERR_LINE (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Linha " : ", Line ")+(string)__LINE__+": ") #define DFUN (__FUNCTION__+": ") // "Descrição da função" #define COUNTRY_LANG ("Russian") // Idioma #define END_TIME (D'31.12.3000 23:59:59') // Data final para solicitações de dados do histórico da conta #define TIMER_FREQUENCY (16) // Frequência mínima do temporizador da biblioteca em milissegundos //--- Parâmetro do temporizador da coleção de ordens e de transações #define COLLECTION_ORD_PAUSE (250) // Pausa do temporizador da coleção de ordens e de transações em milissegundos #define COLLECTION_ORD_COUNTER_STEP (16) // Incremento do contador do temporizador da coleção de ordens e de transações #define COLLECTION_ORD_COUNTER_ID (1) // Identificador do contador do temporizdor da coleção de ordens e de transações //--- Parâmetros do temporizador da coleção de contas #define COLLECTION_ACC_PAUSE (1000) // Pausa do temporizador da coleção de contas em milissegundos #define COLLECTION_ACC_COUNTER_STEP (16) // Incremento do contador do temporizador de contas #define COLLECTION_ACC_COUNTER_ID (2) // Identificador do contador do temporizador de contas //--- Parâmetros do temporizador1 da coleção de símbolos #define COLLECTION_SYM_PAUSE1 (100) // Pausa do temporizador1 da coleção de símbolos em milissegundos (para rastreamento de símbolos na observação do mercado) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Incremento do temporizador1 de símbolos #define COLLECTION_SYM_COUNTER_ID1 (3) // Identificador da conta do temporizador1 de símbolos //--- Parâmetros do temporizador2 da coleção de símbolos #define COLLECTION_SYM_PAUSE2 (300) // Pausa do temporizador2 da coleção de símbolos em milissegundos (para eventos da lista de símbolos na observação do mercado) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Incremento do contador do temporizador2 de símbolos #define COLLECTION_SYM_COUNTER_ID2 (4) // Identificador da conta do temporizador2 de símbolos //--- Identificadores da lista de coleções #define COLLECTION_HISTORY_ID (0x7778+1) // Identificador da lista de coleção histórica #define COLLECTION_MARKET_ID (0x7778+2) // Identificador da lista de coleção de mercado #define COLLECTION_EVENTS_ID (0x7778+3) // Identificador da lista de coleção de eventos #define COLLECTION_ACCOUNT_ID (0x7778+4) // Identificador da coleção de contas #define COLLECTION_SYMBOLS_ID (0x7778+5) // Identificador da lista de coleção de símbolos //--- Parâmetros de dados para operações de arquivo #define DIRECTORY ("DoEasy\\") // Diretório da biblioteca para colocar as pastas dos objetos de classe //--- Parâmetro de símbolos #define CLR_DEFAULT (0xFF000000) // Cor por padrão //+------------------------------------------------------------------+
Acima, falamos sobre os modos para trabalhar com coleções de símbolos: com o símbolo atual, com uma lista de símbolos predefinida no programa,
com a janela Observação do Mercado e com a lista completa de símbolos disponíveis no servidor.
Definimos todos esses modos na enumeração:
//+------------------------------------------------------------------+ //| Dados para trabalhar com símbolos | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modos de trabalho com símbolos | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Trabalhar apenas com o símbolo atual SYMBOLS_MODE_DEFINES, // Trabalhar com a lista de símbolos definida SYMBOLS_MODE_MARKET_WATCH, // Trabalhar com símbolo da janela Observação do mercado SYMBOLS_MODE_ALL // Trabalhar com a lista completa de símbolos }; //+------------------------------------------------------------------+
No último artigo, identificamos categorias de símbolos pelo qual iremos distribuí-los. No início deste artigo, examinamos uma lista um pouco expandida de categorias de símbolos. Vamos usá-la.
Adicionamos uma enumeração de categorias (status) de símbolos:
//+------------------------------------------------------------------+ // Tipo (status) do símbolo abstrato | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_STATUS { SYMBOL_STATUS_FX, // Símbolo forex SYMBOL_STATUS_FX_MAJOR, // Símbolo forex major SYMBOL_STATUS_FX_MINOR, // Símbolo forex minor SYMBOL_STATUS_FX_EXOTIC, // Símbolo exótico forex SYMBOL_STATUS_FX_RUB, // Símbolo forex/rublo SYMBOL_STATUS_METAL, // Metal SYMBOL_STATUS_INDEX, // Índice SYMBOL_STATUS_INDICATIVE, // Indicativo SYMBOL_STATUS_CRYPTO, // Símbolo de criptomoeda SYMBOL_STATUS_COMMODITY, // Símbolo de commoditie SYMBOL_STATUS_EXCHANGE, // Símbolo de bolsa SYMBOL_STATUS_FUTURES, // Futuros SYMBOL_STATUS_CFD, // Contrato por diferença SYMBOL_STATUS_STOCKS, // Título SYMBOL_STATUS_BONDS, // Obrigação SYMBOL_STATUS_OPTION, // Opção SYMBOL_STATUS_COLLATERAL, // Ativo não negociável SYMBOL_STATUS_CUSTOM, // Símbolo personalizado SYMBOL_STATUS_COMMON // Categoria geral }; //+------------------------------------------------------------------+
Isso conclui a preparação de dados para a coleção de símbolos e as alterações no arquivo Defines.mqh.
As mudanças também afetaram a classe CSymbol que criamos no último
artigo.
Como agora recebemos dados sobre coeficientes
de cobrança de margem para diferentes tipos de ordens através da função SymbolInfoMarginRate(),
e para retorno dos valores solicitados são usadas as variáveis passadas para a função por referência, então precisamos criar essas
variáveis.
Se levarmos em conta que temos oito ordens e, para cada uma delas, podemos obter dois tipos de coeficientes — coeficiente de cobrança de margem inicial e o coeficiente de cobrança de margem de manutenção —, então deve haver 16 variáveis para obter todos esses valores. Portanto, é mais fácil e mais visual criar uma estrutura consistindo em duas estruturas aninhadas: na primeira estrutura serão definidas duas variáveis double para armazenar os coeficientes de cobrança das margens inicial e de manutenção, e na segunda estarão contidas as primeiras estruturas declaradas para armazenar dados sobre os tipos de ordens para os quais precisam ser obtidos os coeficientes.
No arquivo da classe-símbolo Symbol.mqh, na seção privada da classe CSymbol, declaramos essas estruturas e a variável-membro da classe com o tipo da segunda estrutura para acessar a estrutura:
//+------------------------------------------------------------------+ // Classe do símbolo abstrato | //+------------------------------------------------------------------+ class CSymbol : public CObject { private: struct SMarginRate { double Initial; // coeficiente de cobrança de margem inicial double Maintenance; // coeficiente de cobrança da margem de manutenção }; struct SMarginRateMode { SMarginRate Long; // MarginRate de posições longas SMarginRate Short; // MarginRate de posições curtas SMarginRate BuyStop; // MarginRate de ordens BuyStop SMarginRate BuyLimit; // MarginRate de ordens BuyLimit SMarginRate BuyStopLimit; // MarginRate de ordens BuyStopLimit SMarginRate SellStop; // MarginRate de ordens SellStop SMarginRate SellLimit; // MarginRate de ordens SellLimit SMarginRate SellStopLimit; // MarginRate de ordens SellStopLimit }; SMarginRateMode m_margin_rate; // estrutura da taxa de cobrança da margem
À seção privada da classe, adicionamos o método que preenche
todas as propriedades do símbolo para cada coeficiente de cobrança de margem, o
método que inicializa as variáveis das estruturas que armazenam todos o os coeficientes de cobrança de margem, bem como dois métodos
auxiliares
para obter o dia atual da semana e para
obter o número de casas decimais como valor double:
SMarginRateMode m_margin_rate; // estrutura da taxa de cobrança da margem MqlTick m_tick; // Estrutura do tick do símbolo MqlBookInfo m_book_info_array[]; // Matriz de estruturas de dados do livro de ofertas string m_symbol_name; // Nome do símbolo long m_long_prop[SYMBOL_PROP_INTEGER_TOTAL]; // Propriedades de número inteiro double m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL]; // Propriedades reais string m_string_prop[SYMBOL_PROP_STRING_TOTAL]; // Propriedades de string int m_digits_currency; // Casas decimais da moeda da conta int m_global_error; // Código de erro global //--- Retorna o índice da matriz na qual a propriedade (1) double e (2) a propriedade string do símbolo estão realmente localizadas int IndexProp(ENUM_SYMBOL_PROP_DOUBLE property) const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_SYMBOL_PROP_STRING property) const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL; } //--- (1) Preenche todas as propriedades do símbolo "taxa de cobrança de margem", (2) inicializa as taxas bool MarginRates(void); void InitMarginRates(void); //--- Zera todos os dados do objeto-símbolo void Reset(void); //--- Retorna o dia da semana atual ENUM_DAY_OF_WEEK CurrentDayOfWeek(void) const; //--- Retorna o número de casas decimais num valor double int GetDigits(const double value) const; public:
Neste caso, na seção privada da classe declararemos métodos que retornam dados sobre coeficientes de cobrança de margem para cada tipo de
ordem:
//--- Obtém e retorna as propriedades reais do símbolo selecionado a partir de seus parâmetros double SymbolBidHigh(void) const; double SymbolBidLow(void) const; double SymbolVolumeReal(void) const; double SymbolVolumeHighReal(void) const; double SymbolVolumeLowReal(void) const; double SymbolOptionStrike(void) const; double SymbolTradeAccruedInterest(void) const; double SymbolTradeFaceValue(void) const; double SymbolTradeLiquidityRate(void) const; double SymbolMarginHedged(void) const; bool SymbolMarginLong(void); bool SymbolMarginShort(void); bool SymbolMarginBuyStop(void); bool SymbolMarginBuyLimit(void); bool SymbolMarginBuyStopLimit(void); bool SymbolMarginSellStop(void); bool SymbolMarginSellLimit(void); bool SymbolMarginSellStopLimit(void); //--- Obtém e retorna propriedades de string do símbolo selecionado a partir de seus parâmetros
Às vezes, o programa precisa saber se o símbolo existe no servidor de acordo com o nome do símbolo. Nós já temos o método Exist(), que retorna essas informações sobre o símbolo da classe. Sobrecarregamos o método para que ele possa retornar dados de acordo com o nome do símbolo passado. Para isso, declaramos outra forma de chamada de método na seção privada da classe:
//--- Procura o símbolo e retorna um sinalizador indicando que existe no servidor bool Exist(void) const; bool Exist(const string name) const;
E na seção protegida da classe declaramos o método sobrecarregado que retorna o valor da existência do símbolo por seu nome dependendo do tipo de programa (MQL5 ou MQL4):
protected: //--- Construtor paramétrico protegido CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Obtém e retorna as propriedades inteiras do símbolo selecionado a partir de seus parâmetros bool SymbolExists(const string name) const; long SymbolExists(void) const;
Na seção pública da classe, em sua seção para métodos de descrição de propriedades declaramos
um método virtual para registrar uma breve descrição do símbolo no log.
Nós implementamos esse método virtual nos herdeiros
da classe, nos quais são definidas informações de esclarecimento sobre o objeto-símbolo.
//+------------------------------------------------------------------+ // Descrições das propriedades do objeto-símbolo | //+------------------------------------------------------------------+ //--- Retorna uma descrição de uma propriedade - do símbolo - (1) inteira, (2) real e (3) de string string GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property); string GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property); string GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property); //--- Exibe no log uma descrição das propriedades do símbolo (full_prop = true - todas as propriedades, false - apenas suportadas) void Print(const bool full_prop=false); //--- Exibe uma breve descrição do símbolo no log (implementação nos herdeiros) virtual void PrintShort(void) {;} //--- No que diz respeito ao objeto CSymbol, compara todas sua possíveis propriedades (para classificação de listas segundo a propriedade especificada símbolo-objeto)
No último artigo, ao implementar o objeto-símbolo, adicionamos vários métodos de serviço à seção pública da classe.
Adicionamos
mais alguns métodos para retornar as horas de início e de término das seções de
cotação e de negociação,
bem como os
métodos privados retornando um número inteiro de horas, de minutos e de segundos numa
sessão e o método retornando uma descrição da duração da sessão no formato
"HH:MM:SS" :
//--- (1) Adiciona, (2) remove um símbolo da janela Observação do mercado, (3) retorna o sinalizador de sincronização de dados do símbolo bool SetToMarketWatch(void) const { return ::SymbolSelect(this.m_symbol_name,true); } bool RemoveFromMarketWatch(void) const { return ::SymbolSelect(this.m_symbol_name,false); } bool IsSynchronized(void) const { return ::SymbolIsSynchronized(this.m_symbol_name); } //--- Retorna (1) a hora de início e (2) a hora de término da sessão do dia da semana, (3) a hora de início e final do necessário long SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- Retorna (1) a hora de início e (2) a hora de término da sessão do dia da semana, (3) a hora de início e final do pregão requerido long SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- (1) Realiza (1) assinatura do livro de ofertas, (2) fecha o livro de ofertas, (3) preenche os dados do livro de ofertas numa matriz de estruturas bool BookAdd(void) const; bool BookClose(void) const; // --- Retorna (1) uma descrição da duração da sessão em hh:mm:ss, o número de (1) horas, (2) minutos e (3) segundos no tempo da duração da sessão string SessionDurationDescription(const ulong duration_sec) const; private: int SessionHours(const ulong duration_sec) const; int SessionMinutes(const ulong duration_sec) const; int SessionSeconds(const ulong duration_sec) const; public: //+------------------------------------------------------------------+
Na seção pública, na seção de métodos para acesso simplificado às propriedades do objeto-símbolo adicionamos
a segunda forma de chamada de método que retorna o sinalizador indicando que o símbolo existe no servidor (anteriormente
declaramos um método sobrecarregado privado que procurava um símbolo no servidor pelo nome e retornava um sinalizador com o resultado da
pesquisa)
//+------------------------------------------------------------------+ // Métodos para acesso simplificado às propriedades de um objeto-símbolo //+------------------------------------------------------------------+ //--- Propriedades de número inteiro long Status(void) const { return this.GetProperty(SYMBOL_PROP_STATUS); } bool IsCustom(void) const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM); } color ColorBackground(void) const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR); } ENUM_SYMBOL_CHART_MODE ChartMode(void) const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE); } bool IsExist(void) const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST); } bool IsExist(const string name) const { return this.SymbolExists(name); } bool IsSelect(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT); } bool IsVisible(void) const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE); } long SessionDeals(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS); }
Na seção pública, na seção de métodos para acesso simplificado às propriedades reais do símbolo, adicionamos métodos que retornam
todos os coeficientes de cobrança de margem:
//--- Propriedades reais double Bid(void) const { return this.GetProperty(SYMBOL_PROP_BID); } double BidHigh(void) const { return this.GetProperty(SYMBOL_PROP_BIDHIGH); } double BidLow(void) const { return this.GetProperty(SYMBOL_PROP_BIDLOW); } double Ask(void) const { return this.GetProperty(SYMBOL_PROP_ASK); } double AskHigh(void) const { return this.GetProperty(SYMBOL_PROP_ASKHIGH); } double AskLow(void) const { return this.GetProperty(SYMBOL_PROP_ASKLOW); } double Last(void) const { return this.GetProperty(SYMBOL_PROP_LAST); } double LastHigh(void) const { return this.GetProperty(SYMBOL_PROP_LASTHIGH); } double LastLow(void) const { return this.GetProperty(SYMBOL_PROP_LASTLOW); } double VolumeReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL); } double VolumeHighReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL); } double VolumeLowReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL); } double OptionStrike(void) const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE); } double Point(void) const { return this.GetProperty(SYMBOL_PROP_POINT); } double TradeTickValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE); } double TradeTickValueProfit(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT); } double TradeTickValueLoss(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS); } double TradeTickSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE); } double TradeContractSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE); } double TradeAccuredInterest(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST); } double TradeFaceValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE); } double TradeLiquidityRate(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE); } double LotsMin(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN); } double LotsMax(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX); } double LotsStep(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP); } double VolumeLimit(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT); } double SwapLong(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG); } double SwapShort(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT); } double MarginInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL); } double MarginMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE); } double MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } double SessionVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME); } double SessionTurnover(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER); } double SessionInterest(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST); } double SessionBuyOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME); } double SessionSellOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME); } double SessionOpen(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN); } double SessionClose(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE); } double SessionAW(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_AW); } double SessionPriceSettlement(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT); } double SessionPriceLimitMin(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN); } double SessionPriceLimitMax(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX); } double MarginHedged(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED); } double NormalizedPrice(const double price) const; //--- Propriedades de string
Para obter informações sobre as propriedades do símbolo, é necessário que ele seja selecionado na janela "Observação do mercado". Mas pode acontecer que o símbolo não esteja selecionado na janela, mas seja necessário obter suas propriedades. Para fazer isso, precisamos criar um sinalizador indicando se o símbolo foi selecionado na janela 'Observação do mercado' antes de nos acessarmos as suas propriedades. Procedemos de acordo com o esquema: se o símbolo não estiver selecionado, selecionamo-lo, obtemos as propriedades e novamente ocultamos na janela 'Observação do mercado'. Se o símbolo já estiver selecionado, simplesmente obtemos suas propriedades.
Também precisamos inicializar os coeficientes de cobrança de margem no
construtor da classe e
preenchê-los para MQL5. Para MQL4, esses dados não existem e seus
valores permanecem zero após a inicialização.
E adicionamos uma chamada aos métodos para salvar essas propriedades nos campos de
propriedades da classe.
Para fazer isso, adicionamos o código necessário no construtor da classe:
//+------------------------------------------------------------------+ // Construtor paramétrico fechado | //+------------------------------------------------------------------+ CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name) : m_global_error(ERR_SUCCESS) { this.m_symbol_name=name; if(!this.Exist()) { ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\"",": ",TextByLanguage("Erro. Não existe esse símbolo no servidor","Error. There is no such symbol on the server")); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; } bool select=::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); ::ResetLastError(); if(!select) { if(!this.SetToMarketWatch()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Falha ao colocar na Observação do Mercado. Erro: ","Failed to put in the market watch. Error: "),this.m_global_error); } } ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Falha ao obter preços atuais. Erro: ","Could not get current prices. Error: "),this.m_global_error); } //--- Inicialização de dados ::ZeroMemory(this.m_tick); this.Reset(); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.InitMarginRates(); ::ResetLastError(); #ifdef __MQL5__ if(!this.MarginRates()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Falha ao obter coeficientes de cobrança de margem. Erro: ","Failed to get margin rates. Error: "),this.m_global_error); return; } #endif //--- Salvar propriedades de número inteiro this.m_long_prop[SYMBOL_PROP_STATUS] = symbol_status; this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_DIGITS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_DIGITS); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD_FLOAT); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_TRADE_MODE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_MODE); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_EXEMODE); this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SWAP_ROLLOVER3DAYS); this.m_long_prop[SYMBOL_PROP_EXIST] = this.SymbolExists(); this.m_long_prop[SYMBOL_PROP_CUSTOM] = this.SymbolCustom(); this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG] = this.SymbolMarginHedgedUseLEG(); this.m_long_prop[SYMBOL_PROP_ORDER_MODE] = this.SymbolOrderMode(); this.m_long_prop[SYMBOL_PROP_FILLING_MODE] = this.SymbolOrderFillingMode(); this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE] = this.SymbolExpirationMode(); this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE] = this.SymbolOrderGTCMode(); this.m_long_prop[SYMBOL_PROP_OPTION_MODE] = this.SymbolOptionMode(); this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT] = this.SymbolOptionRight(); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); this.m_long_prop[SYMBOL_PROP_CHART_MODE] = this.SymbolChartMode(); this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE] = this.SymbolCalcMode(); this.m_long_prop[SYMBOL_PROP_SWAP_MODE] = this.SymbolSwapMode(); //--- Salvar propriedades reais this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_POINT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Salvar propriedades de linha this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)] = this.m_symbol_name; this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_BASE); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_PROFIT); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_MARGIN); this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_DESCRIPTION); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_PATH); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)] = this.SymbolBasis(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)] = this.SymbolBank(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)] = this.SymbolISIN(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)] = this.SymbolFormula(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)] = this.SymbolPage(); //--- Salvar propriedades inteiras adicionais this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS] = this.SymbolDigitsLot(); //--- if(!select) this.RemoveFromMarketWatch(); } //+------------------------------------------------------------------+
Agora precisamos escrever as implementações de todos os métodos declarados.
Fora do corpo da classe escrevemos a implementação do método que preenche todas as variáveis que armazenam coeficientes de cobrança de
margem:
//+------------------------------------------------------------------+ // Preenche os arrays de taxa de cobrança da margem | //+------------------------------------------------------------------+ bool CSymbol::MarginRates(void) { bool res=true; #ifdef __MQL5__ res &=this.SymbolMarginLong(); res &=this.SymbolMarginBuyStop(); res &=this.SymbolMarginBuyLimit(); res &=this.SymbolMarginBuyStopLimit(); res &=this.SymbolMarginShort(); res &=this.SymbolMarginSellStop(); res &=this.SymbolMarginSellLimit(); res &=this.SymbolMarginSellStopLimit(); #else this.InitMarginRates(); res=false; #endif return res; } //+------------------------------------------------------------------+
No método para MQL5 simplesmente são chamados métodos que lêem
dados sobre coeficientes (a partir das propriedades do símbolo) e os escrevem nas variáveis de estrutura correspondentes, enquanto o
resultado do retorno de todos os métodos é resumido e retornado ao programa de chamada. Os métodos serão discutidos abaixo.
Para MQL4 basta zerar todos os campos da estrutura.
Método de inicialização de campos da estrutura para as propriedades dos valores dos coeficientes de cobrança de margem:
//+------------------------------------------------------------------+ // Inicializa taxas de cobrança de margem | //+------------------------------------------------------------------+ void CSymbol::InitMarginRates(void) { this.m_margin_rate.Long.Initial=0; this.m_margin_rate.Long.Maintenance=0; this.m_margin_rate.BuyStop.Initial=0; this.m_margin_rate.BuyStop.Maintenance=0; this.m_margin_rate.BuyLimit.Initial=0; this.m_margin_rate.BuyLimit.Maintenance=0; this.m_margin_rate.BuyStopLimit.Initial=0; this.m_margin_rate.BuyStopLimit.Maintenance=0; this.m_margin_rate.Short.Initial=0; this.m_margin_rate.Short.Maintenance=0; this.m_margin_rate.SellStop.Initial=0; this.m_margin_rate.SellStop.Maintenance=0; this.m_margin_rate.SellLimit.Initial=0; this.m_margin_rate.SellLimit.Maintenance=0; this.m_margin_rate.SellStopLimit.Initial=0; this.m_margin_rate.SellStopLimit.Maintenance=0; } //+------------------------------------------------------------------+
Aqui todos os campos da estrutura m_margin_rate são simplesmente redefinidos.
Implementação da segunda forma para o chamar o método que retorna o sinalizador que indica se o símbolo existe no servidor:
//+------------------------------------------------------------------+ // Retorna o sinalizador da existência do símbolo | //+------------------------------------------------------------------+ long CSymbol::SymbolExists(void) const { return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXIST) #else this.Exist() #endif); } //+------------------------------------------------------------------+ bool CSymbol::SymbolExists(const string name) const { return(#ifdef __MQL5__ (bool)::SymbolInfoInteger(name,SYMBOL_EXIST) #else this.Exist(name) #endif); } //+------------------------------------------------------------------+
Neste caso, para MQL5 é retornada a propriedade do símbolo SYMBOL_EXIST, já para MQL4 é realizada a busca do símbolo no servidor com a ajuda do segundo método de chamada do método Exist(const string name).
Implementação de métodos que preenchem os coeficientes de cobrança de margem na estrutura para todos os tipos de ordens:
//+------------------------------------------------------------------+ //| Preenche índices de margem para posições longas | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginLong(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY,this.m_margin_rate.Long.Initial,this.m_margin_rate.Long.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para posições curtas | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginShort(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL,this.m_margin_rate.Short.Initial,this.m_margin_rate.Short.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para BuyStop | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP,this.m_margin_rate.BuyStop.Initial,this.m_margin_rate.BuyStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para BuyLimit | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_LIMIT,this.m_margin_rate.BuyLimit.Initial,this.m_margin_rate.BuyLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para BuyStopLimit | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP_LIMIT,this.m_margin_rate.BuyStopLimit.Initial,this.m_margin_rate.BuyStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para SellStop | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP,this.m_margin_rate.SellStop.Initial,this.m_margin_rate.SellStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para SellLimit | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_LIMIT,this.m_margin_rate.SellLimit.Initial,this.m_margin_rate.SellLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Preenche índices de margem para SellStopLimit | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP_LIMIT,this.m_margin_rate.SellStopLimit.Initial,this.m_margin_rate.SellStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+
Neste caso, para MQL5 é chamada a função SymbolInfoMarginRate()
em que são preenchidas as propriedades necessárias que são armazenadas na estrutura m_margin_rate e é retornado o
resultado da função.
Para MQL4, retornamos false.
No método que retorna a descrição das propriedades inteiras do símbolo no bloco de retorno da descrição da cor de segundo plano para o símbolo na janela 'Observação do Mercado', fazemos as alterações:
property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Cor de fundo do símbolo na Observação do Mercado","Background color of the symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : #ifdef __MQL5__ (this.GetProperty(property)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ? TextByLanguage(": (Ausente)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) :
Anteriormente, comparávamos a cor com branco (clrWhite) e, se o valor da cor era maior que o valor da cor "branca", acreditava-se que a cor não estava definida. Já discutimos o porquê de esse método de comparação ser errado, portanto, aqui para determinar a ausência de uma determinada cor de plano de fundo para um símbolo na janela "Observação do mercado", compararemos a cor com a 'cor padrão' ou com a 'cor em falta'.
Para o método que retorna as descrições das propriedades reais do símbolo GetPropertyDescription (propriedade ENUM_SYMBOL_PROP_DOUBLE), adicionamos a saída da descrição de todos os coeficientes de cobrança de margem:
//--- Coeficiente de cobrança de margem inicial da posição Long property==SYMBOL_PROP_MARGIN_LONG_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para posições longas","Coefficient of margin initial charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança de margem inicial da posição Short property==SYMBOL_PROP_MARGIN_SHORT_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para posições curtas","Coefficient of margin initial charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança da margem de manutenção da posição Long property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para posições longas","Coefficient of margin maintenance charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança da margem de manutenção da posição Short property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para posições curtas","Coefficient of margin maintenance charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança de margem inicial da ordem Long property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens BuyStop","Coefficient of margin initial charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens BuyLimit","Coefficient of margin initial charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens BuyStopLimit","Coefficient of margin initial charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança de margem inicial da ordem Short property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens SellStop","Coefficient of margin initial charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens SellLimit","Coefficient of margin initial charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens SellStopLimit","Coefficient of margin initial charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Taxa de margem de manutenção da ordem Long property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem inicial para ordens BuyStop","Coefficient of margin maintenance charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para ordens BuyLimit","Coefficient of margin maintenance charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para ordens BuyStopLimit","Coefficient of margin maintenance charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //--- Coeficiente de cobrança da margem de manutenção da ordem Short property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para ordens SellStop","Coefficient of margin maintenance charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para ordens SellLimit","Coefficient of margin maintenance charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE ? TextByLanguage("Coeficiente de cobrança da margem de manutenção para ordens SellStopLimit","Coefficient of margin maintenance charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Propriedade não suportada",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Não definido)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Propriedade não suportada em MQL4","Property is not supported in MQL4") #endif ) : //---
Implementação da segunda forma de chamar o método que procura o símbolo por seu nome no servidor e retorna o sinalizador que indica se o símbolo existe:
//+------------------------------------------------------------------+ //| Procura o símbolo e retorna um sinalizador indicando que existe no servidor //+------------------------------------------------------------------+ bool CSymbol::Exist(void) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==this.m_symbol_name) return true; return false; } //+------------------------------------------------------------------+ bool CSymbol::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
Implementação do método que conta e retorna o número de casas decimais com um valor double:
//+------------------------------------------------------------------+ //| Retorna o número de casas decimais num valor double | //+------------------------------------------------------------------+ int CSymbol::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
Discutimos esse método no último artigo. Aqui, ele foi simplesmente colocado num método separado, pois requer cálculos repetidos para vários valores — para o lote mínimo e para a etapa de alteração do lote.
Implementação de métodos que retornam a hora de início/término da sessão de cotação desde o início do dia:
//+------------------------------------------------------------------+ //| Retorna a hora de início da sessão | //| em segundos desde o início do dia | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Retorna o tempo em segundos desde o início do dia | //| antes do final da sessão | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Retorna o horário de início e término da sessão requerida | //+------------------------------------------------------------------+ bool CSymbol::GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
Para os dois primeiros métodos são passados o índice de sessão e odia da semana, para o terceiro são transferidas adicionalmente as variáveis de tipo datetime, em que são registrados os dados sobre o início e o fim da sessão requerida obtida através da função SymbolInfoSessionQuote().
Por conveniência, se -1 for transferido como o dia da semana, serão coletados os dados da sessão para o dia atual da semana. O índice da sessão
deve começar do zero. A hora é retornada como o número de segundos desde o início do dia, determinado pelo parâmetro
day_of_week. Assim, sempre é possível saber a hora real solicitada adicionando à hora do início do dia o número de segundos obtidos a
partir do método.
Os métodos para obter os horários das sessões de negociação são implementados da mesma maneira:
//+------------------------------------------------------------------+ //| Retorna a hora de início da sessão de negociação | //| em segundos desde o início do dia | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Retorna o tempo em segundos desde o início do dia | //| antes do final do pregão | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Retorna o horário de início e término da sessão de negociação requerida //+------------------------------------------------------------------+ bool CSymbol::GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
Nestes métodos, tudo é semelhante aos descritos acima, exceto que aqui, para obter os dados necessários, é usada a função SymbolInfoSessionTrade().
Implementação de um método que retorna o dia atual da semana como um valor de enumeração ENUM_DAY_OF_WEEK:
//+------------------------------------------------------------------+ //| Retorna o dia atual da semana | //+------------------------------------------------------------------+ ENUM_DAY_OF_WEEK CSymbol::CurrentDayOfWeek(void) const { MqlDateTime time={0}; ::TimeCurrent(time); return(ENUM_DAY_OF_WEEK)time.day_of_week; } //+------------------------------------------------------------------+
Aqui tudo é simples, declaramos as estruturas da data e do tempo,
acessamos a função
TimeCurrent(), cuja segunda maneira de chamada preenche a
estrutura da data e do tempo, transferida para a função, e, como resultado, retornamos o
dia da semana a partir da estrutura
preenchida.
Implementação do método que retorna o número de segundos no tempo da duração da sessão especificada:
//+------------------------------------------------------------------+ //| Retorna o número de segundos no tempo da duração da sessão | //+------------------------------------------------------------------+ int CSymbol::SessionSeconds(const ulong duration_sec) const { return int(duration_sec % 60); } //+------------------------------------------------------------------+
Para o método é transferido o número de segundos e é retornado o restante da divisão pelo número de minutos neste intervalo de tempo.
Implementação do método que retorna o número de minutos no tempo da duração da sessão especificada:
//+------------------------------------------------------------------+ //| Retorna o número de minutos no tempo de duração da sessão | //+------------------------------------------------------------------+ int CSymbol::SessionMinutes(const ulong duration_sec) const { return int((duration_sec-this.SessionSeconds(duration_sec)) % 3600)/60; } //+------------------------------------------------------------------+
Para o método é transferido o número de segundos e é retornado o número calculado de minutos neste intervalo de tempo exceto pelo número de segundosnão múltiplos de um minuto.
Implementação do método que retorna o número de horas no tempo da duração da sessão especificada:
//+------------------------------------------------------------------+ //| Retorna o número de horas no tempo da duração da sessão | //+------------------------------------------------------------------+ int CSymbol::SessionHours(const ulong duration_sec) const { return int(duration_sec-this.SessionSeconds(duration_sec)-this.SessionMinutes(duration_sec))/3600; } //+------------------------------------------------------------------+
Para o método é transferido o número de segundos e é
retornado o número de horas neste intervalo de tempo
exceto pelo número de segundos não múltiplos de um minuto e o
número de minutos, não múltiplos de uma hora.
Implementação do método que retorna uma descrição da duração da sessão como "HH:MM:SS":
//+------------------------------------------------------------------+ //| Retorna uma descrição da duração da sessão em hh:mm:ss | //+------------------------------------------------------------------+ string CSymbol::SessionDurationDescription(const ulong duration_sec) const { int sec=this.SessionSeconds(duration_sec); int min=this.SessionMinutes(duration_sec); int hour=this.SessionHours(duration_sec); return ::IntegerToString(hour,2,'0')+":"+::IntegerToString(min,2,'0')+":"+::IntegerToString(sec,2,'0'); } //+------------------------------------------------------------------+
Aqui apenas obtemos a duração da sessão em segundos, obtemos
a duração da sessão em segundos, minutos e horas,
e exibimos uma mensagem com o formato Horas:Minutos:Segundos usando a função
IntegerToString()com
tamanho do comprimento da string para horas, minutos e segundos iguais a dois
dígitos e o preenchimento "0", caso haja um único dígito nos valores de horas, minutos ou segundos.
Por
exemplo, se recebermos 2 horas, será mostrado como 02.
Como modificamos levemente os status dos objetos-símbolos, corrigiremos o método que exibe a descrição desse status:
//+------------------------------------------------------------------+ //| Retorna a descrição do statu | //+------------------------------------------------------------------+ string CSymbol::GetStatusDescription() const { return ( this.Status()==SYMBOL_STATUS_FX ? TextByLanguage("Símbolo Forex","Forex symbol") : this.Status()==SYMBOL_STATUS_FX_MAJOR ? TextByLanguage("Símbolo Forex major","Forex major symbol") : this.Status()==SYMBOL_STATUS_FX_MINOR ? TextByLanguage("Símbolo Forex minor","Forex minor symbol") : this.Status()==SYMBOL_STATUS_FX_EXOTIC ? TextByLanguage("Símbolo Forex exotic","Forex Exotic Symbol") : this.Status()==SYMBOL_STATUS_FX_RUB ? TextByLanguage("Símbolo Forex/Rublo","Forex symbol RUB") : this.Status()==SYMBOL_STATUS_METAL ? TextByLanguage("Metal","Metal") : this.Status()==SYMBOL_STATUS_INDEX ? TextByLanguage("Índice","Index") : this.Status()==SYMBOL_STATUS_INDICATIVE ? TextByLanguage("Indicativo","Indicative") : this.Status()==SYMBOL_STATUS_CRYPTO ? TextByLanguage("Criptomoeda","Crypto symbol") : this.Status()==SYMBOL_STATUS_COMMODITY ? TextByLanguage("Símbolo Commoditie","Commodity symbol") : this.Status()==SYMBOL_STATUS_EXCHANGE ? TextByLanguage("Símbolo bolsista","Exchange symbol") : this.Status()==SYMBOL_STATUS_FUTURES ? TextByLanguage("Futuros","Furures") : this.Status()==SYMBOL_STATUS_CFD ? TextByLanguage("Contrato por diferença","Contract For Difference") : this.Status()==SYMBOL_STATUS_STOCKS ? TextByLanguage("Título","Stocks") : this.Status()==SYMBOL_STATUS_BONDS ? TextByLanguage("Obrigação","Bonds") : this.Status()==SYMBOL_STATUS_OPTION ? TextByLanguage("Opção","Option") : this.Status()==SYMBOL_STATUS_COLLATERAL ? TextByLanguage("Ativo não negociável","Collateral") : this.Status()==SYMBOL_STATUS_CUSTOM ? TextByLanguage("Símbolo personalizado","Custom symbol") : this.Status()==SYMBOL_STATUS_COMMON ? TextByLanguage("Símbolo de grupo compartilhado","Common group symbol") : ::EnumToString((ENUM_SYMBOL_STATUS)this.Status()) ); } //+------------------------------------------------------------------+
No método para atualizar todos os dados de símbolos,
acrescentaremos, para MQL5, a obtenção de coeficientes de cobrança de margem para todos os tipos de ordens e posições.
Como,
para MQL4, eles não são usados, seus valores serão zero após a inicialização no construtor da classe:
//+------------------------------------------------------------------+ //| Atualiza todos os dados de símbolos que podem mudar | //+------------------------------------------------------------------+ void CSymbol::Refresh(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); return; } #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); return; } #endif //--- Atualizar propriedades de número inteiro this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); //--- Atualizar propriedades reais this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; } //+------------------------------------------------------------------+
Neste caso, para MQL5 chamamos imediatamente o método para obter
dados sobre os coeficientes de cobrança de margem MarginRates(), e se pelo menos um dos coeficientes não tiver sido recebido (o método
retornar
false), então apenas escrevemos o
código de erro na variável que armazena o código de erro da classe e, sem mensagem, saímos do método.
Não exibimos mensagem
de erro no log, uma vez que o método opera no temporizador e, se ocorrer um recebimento incorreto de dados de repente, o log será rapidamente
preenchido com mensagens de lixo sobre o mesmo erro. Além disso, como tal código de erro sempre pode ser obtido na classe CEngine, evitaremos
a obrigação de recebê-lo e processá-lo.
No final do método todos os dados obtidos sobre os coeficientes são
registrados nos campos das propriedades correspondentes do objeto-símbolo.
Pela mesma razão descrita acima, excluímos -do método para atualizar os dados
da cotação- a string contendo a exibição da mensagem de erro no log:
//+------------------------------------------------------------------+ //| Atualiza os dados da cotação para o símbolo | //+------------------------------------------------------------------+ void CSymbol::RefreshRates(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Falha ao obter preços atuais. Erro: ","Could not get current prices. Error: "),this.m_global_error); return; } //--- Atualizar propriedades de número inteiro this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); //--- Atualizar propriedades reais this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); } //+------------------------------------------------------------------+
Agora o método ficará assim:
//+------------------------------------------------------------------+ //| Atualiza os dados da cotação para o símbolo | //+------------------------------------------------------------------+ void CSymbol::RefreshRates(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); return; } //--- Atualizar propriedades de número inteiro this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); //--- Atualizar propriedades reais this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); } //+------------------------------------------------------------------+
Isso conclui a modificação da classe de símbolo abstrato CSymbol.
Examinamos as mudanças mais importantes e significativas nos métodos de classe, com exceção das correções menores que foram feitas, mas, não descritas aqui, porque se tratam apenas de alguns erros ortográficos e "semânticos", principalmente nos métodos de descrição de propriedades. Adicionalmente, eles podem ser vistos nos arquivos anexados ao artigo.
Agora precisamos criar objetos herdeiros da classe base do símbolo abstrato. São precisamente esses objetos, distribuídos por categorias,
que colocaremos na coleção de objetos-símbolos.
Objetos descendentes do objeto abstrato base 'símbolo'
Voltemos um pouco para examinar as categorias de símbolos que mencionamos e determinar os nomes respectivos das classes herdadas da classe base CSymbol:
- Símbolo Forex — classe CSymbolFX
- Símbolo Forex maior— classe CSymbolFXMajor
- Símbolo Forex menor — classe CSymbolFXMinor
- Símbolo Forex exótico — classe CSymbolFXExotic
- Símbolo Forex rublo — classe CSymbolFXRub
- Metal — classe CSymbolMetall
- Índice — classe CSymbolIndex
- Indicativo — classe CSymbolIndicative
- Símbolo criptomoeda — classe CSymbolCrypto
- Símbolo commoditie — classe CSymbolCommodity
- Símbolo bolsista — classe CSymbolExchange
- Futuro — classe CSymbolFutures
- Contrato por diferença (CFD) — classe CSymbolCFD
- Ação — classe CSymbolStocks
- Obrigação — classe CSymbolBonds
- Opção — classe CSymbolOption
- Ativo não negociável — classe CSymbolCollateral
- Símbolo personalizado — classe CSymbolCustom
- Categoria geral — classe CSymbolCommon
Na pasta da biblioteca \MQL5\Include\DoEasy\Objects\Symbols\, criamos a nova classe CSymbolFX com o nome do
arquivo
SymbolFX.mqh. Sua classe base deve ser a classe de símbolo abstrato CSymbol.
Declaramos imediatamente todos os métodos necessários para que a classe funcione:
//+------------------------------------------------------------------+ //| SymbolFX.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Símbolo Forex | //+------------------------------------------------------------------+ class CSymbolFX : public CSymbol { public: //--- Construtor CSymbolFX(const string name) : CSymbol(SYMBOL_STATUS_FX,name) {} //--- Propriedades de símbolo inteiro suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Propriedades reais do símbolo suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Propriedades de string do símbolo suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Exibe uma breve descrição do símbolo virtual void PrintShort(void); }; //+------------------------------------------------------------------+
Para o construtor de classe transferimos o nome
do símbolo, já na lista de inicialização do construtor de classe enviamos
para a classe base a categoria de símbolo (seu status)
'Símbolo Forex' e o
nome do símbolo que é passado ao construtor da classe CSymbolFX quando
criado.
Métodos virtuais de manutenção de objeto com propriedades inteiras,
reais e de string
foram declarados na classe base, porém nós vamos implementá-los nas classes herdeiras. Método virtual PrintShort(),
também declarado na classe base e implementado na classe herdeira, exibirá informações breves sobre o símbolo no log.
Olhando para o futuro, eu diria que quase todos esses métodos são quase os mesmos para todas as classes descendentes e podem ser feitos na classe base sem criar nenhuma classe descendente. Mas, neste caso, tal alteração nestes métodos para cada um dos grupos de símbolos iria se tornar menos flexível. Por isso, decidiu-se fazer a divisão em categorias através de classes herdeiras, para que, no futuro, se necessário, seja possível alterar cada uma dessas classes separadamente, o que é muito mais simples e rápido.
Implementação do método que retorna o sinalizador de suporte de objeto-símbolo de uma propriedade inteira:
//+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST #ifdef __MQL4__ || property==SYMBOL_PROP_CUSTOM || property==SYMBOL_PROP_SESSION_DEALS || property==SYMBOL_PROP_SESSION_BUY_ORDERS || property==SYMBOL_PROP_SESSION_SELL_ORDERS || property==SYMBOL_PROP_VOLUME || property==SYMBOL_PROP_VOLUMEHIGH || property==SYMBOL_PROP_VOLUMELOW || property==SYMBOL_PROP_TICKS_BOOKDEPTH || property==SYMBOL_PROP_OPTION_MODE || property==SYMBOL_PROP_OPTION_RIGHT || property==SYMBOL_PROP_BACKGROUND_COLOR #endif ) return false; return true; } //+------------------------------------------------------------------+
Para o método é transferida a propriedade inteira verificada
e, para MQL5 e MQL4, se a propriedade transferida for "Existência do Símbolo",
retornamos
false , afinal, se um símbolo é criado, ele existe, e não precisamos que essa propriedade
seja exibida no log, muito menos que seja pesquisada e classificada. Todas as outras verificações se aplicam
somente a MQL4, enquanto é retornado false
ao transferir uma propriedade de símbolo não suportada para um método em MQL4.
Se a propriedade transferida não estiver
entre as propriedades listadas no teste, significa que ela é suportada, enquanto nós retornamos
true.
Implementação do método que retorna o sinalizador de suporte de objeto-símbolo de uma propriedade real:
//+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( #ifdef __MQL5__ (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) //--- __MQL4__ #else property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW || property==SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT || property==SYMBOL_PROP_TRADE_TICK_VALUE_LOSS || property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW || property==SYMBOL_PROP_VOLUME_LIMIT || property==SYMBOL_PROP_MARGIN_LONG_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SHORT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_SESSION_VOLUME || property==SYMBOL_PROP_SESSION_TURNOVER || property==SYMBOL_PROP_SESSION_INTEREST || property==SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_OPEN || property==SYMBOL_PROP_SESSION_CLOSE || property==SYMBOL_PROP_SESSION_AW || property==SYMBOL_PROP_SESSION_PRICE_SETTLEMENT || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX || property==SYMBOL_PROP_VOLUME_REAL || property==SYMBOL_PROP_VOLUMEHIGH_REAL || property==SYMBOL_PROP_VOLUMELOW_REAL || property==SYMBOL_PROP_OPTION_STRIKE || property==SYMBOL_PROP_TRADE_ACCRUED_INTEREST || property==SYMBOL_PROP_TRADE_FACE_VALUE || property==SYMBOL_PROP_TRADE_LIQUIDITY_RATE #endif ) return false; return true; } //+------------------------------------------------------------------+
Aqui a lógica é a mesma do método anterior. No entanto, primeiro, verificamos a propriedade resultante para MQL5:
se ela for uma das propriedades do preço da última transação (Last) e
o gráfico for construído com base em preços Bid, todas essas
propriedades serão iguais a zero e, portanto, neste caso não serão suportadas.
Fazemos o mesmo com as propriedades do preço Bid quando o gráfico for
baseado em preços Last, neste caso todas as propriedades do preço Bid não serão suportadas.
Para
MQL4 agimos exatamente da mesma maneira que no método anterior — ao passar para o método uma propriedade de símbolo evidentemente
não suportada, retornamos
false.
Implementação do método que retorna o sinalizador de suporte de objeto-símbolo de uma propriedade de string:
//+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { if( #ifdef __MQL5__ property==SYMBOL_PROP_FORMULA && !this.IsCustom() #else property==SYMBOL_PROP_BASIS || property==SYMBOL_PROP_BANK || property==SYMBOL_PROP_ISIN || property==SYMBOL_PROP_FORMULA || property==SYMBOL_PROP_PAGE #endif ) return false; return true; } //+------------------------------------------------------------------+
Neste caso, tudo é o mesmo que nos dois anteriores, quer dizer, para
MQL5, se a propriedade transferida for "Fórmula para Calcular Símbolo
Personalizado" e este símbolo não for personalizado,
retornamos
false, uma vez que a propriedade não é suportada. Em seguida, verificamos as propriedades
dos símbolo obviamente não suportadas
para MQL4 e retornamos false
se transferida uma propriedade não suportada em MQL4.
Método para exibir no log uma breve descrição do símbolo:
//+------------------------------------------------------------------+ //| Registra uma breve descrição do símbolo no log | //+------------------------------------------------------------------+ void CSymbolFX::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
O método simplesmente registra no log uma linha que consiste numa descrição de string do status do símbolo e dos seus nomes.
As outras classes derivadas são construídas exatamente da mesma maneira e têm os mesmos métodos com a mesma implementação.
A diferença
está na
classe de símbolo personalizado, pois esse tipo de símbolo definitivamente não está em MQL4, portanto, todas as verificações tem
a ver apenas com MQL5:
//+------------------------------------------------------------------+ //| SymbolCustom.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Símbolo personalizado | //+------------------------------------------------------------------+ class CSymbolCustom : public CSymbol { public: //--- Construtor CSymbolCustom(const string name) : CSymbol(SYMBOL_STATUS_CUSTOM,name) {} //--- Propriedades de símbolo inteiro suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Propriedades reais do símbolo suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Propriedades de string do símbolo suportadas virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Exibe uma breve descrição do símbolo virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST) return false; return true; } //+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) ) return false; return true; } //+------------------------------------------------------------------+ //| Retorna true se o símbolo suportar a propriedade | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Registra uma breve descrição do símbolo no log | //+------------------------------------------------------------------+ void CSymbolCustom::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
Com isso, concluímos o desenvolvimento das classes herderias CSymbol.
A implementação das demais classes
herdeiras pode ser vista no final do artigo nos arquivos anexados.
Como precisamos pesquisar e classificar a coleção de símbolos, devemos criar a funcionalidade necessária para isso. Abrimos o arquivo Select.mqh,
localizado na pasta da biblioteca
\MQL5\Include\DoEasy\Services\, e fazemos adições a ele.
Primeiro, inserimos
a classe de símbolo abstrato:
//+------------------------------------------------------------------+ //| Select.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Objects\Orders\Order.mqh" #include "..\Objects\Events\Event.mqh" #include "..\Objects\Accounts\Account.mqh" #include "..\Objects\Symbols\Symbol.mqh" //+------------------------------------------------------------------+
Na seção pública da classe, declaramos todos os métodos necessários para
pesquisar e classificar:
//+------------------------------------------------------------------+ //| Classe para selecionar objetos que atendem aos critérios | //+------------------------------------------------------------------+ class CSelect { private: //--- Método para comparar duas quantidades template<typename T> static bool CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode); public: //+------------------------------------------------------------------+ //| Métodos de trabalho com ordens | //+------------------------------------------------------------------+ //--- Retorna uma lista de ordens nas quais uma das propriedades de (1) número inteiro, (2) real e (3) de string satisfaz o critério especificado static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Retorna o índice da ordem na lista com o valor máximo de propriedade (1) inteira, (2) real e (3) propriedade de string da ordem static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //--- Retorna o índice da ordem na lista com o valor mínimo da propriedade (1) inteira, (2) real e (3) de string para a ordem static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //+------------------------------------------------------------------+ //| Métodos de trabalho com eventos | //+------------------------------------------------------------------+ //--- Retorna a lista dos eventos que têm uma das propriedades (1) inteiras, (2) reais e (3) de string que satisfaz o critério especificado static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Retorna o índice do evento na lista com o valor máximo para a propriedade (1) inteira, (2) real e (3) de string do evento static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //--- Retorna o índice do evento na lista com o valor mínimo para a propriedade (1) inteira, (2) real e (3) de string do evento static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //+------------------------------------------------------------------+ //| Métodos de trabalho com contas | //+------------------------------------------------------------------+ //--- Retorna a lista das contas com uma das propriedades (1) inteiras, (2) reais e (3) de string que satisfaz o critério especificado static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Retorna o índice do evento na lista com o valor máximo para a propriedade (1) inteira, (2) real e (3) de string do evento static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //--- Retorna o índice do evento na lista com o valor mínimo para a propriedade (1) inteira, (2) real e (3) de string do evento static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //+------------------------------------------------------------------+ //| Métodos de trabalho com símbolos | //+------------------------------------------------------------------+ //--- Retorna a lista dos símbolos com uma das propriedades (1) inteiras, (2) reais e (3) de string que satisfaz o critério especificado static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Retorna o índice do símbolo na lista com o valor máximo para a propriedade (1) inteira, (2) real e (3) de string da ordem static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- Retorna o índice do símbolo na lista com o valor mínimo para a propriedade (1) inteira, (2) real e (3) de string da ordem static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- }; //+------------------------------------------------------------------+
Fora da classe, escrevemos sua implementação:
//+------------------------------------------------------------------+ //| Métodos de trabalho com listas de símbolos | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Retorna uma lista de símbolos contendo uma das propriedades inteiras //| que atendem ao critério especificado | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); int total=list_source.Total(); for(int i=0; i<total; i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; long obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Retorna uma lista de símbolos contendo uma das propriedades reais| //| que atendem ao critério especificado | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; double obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Retorna uma lista de símbolos contendo uma das propriedades de string //| que atendem ao critério especificado | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; string obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor máximo da propriedade inteira | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); long obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor máximo da propriedade real | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); double obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor máximo da propriedade de string | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); string obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor mínimo da propriedade inteira | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_INTEGER property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); long obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor mínimo da propriedade real | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_DOUBLE property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); double obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Retorna o índice de um símbolo numa lista | //| com valor mínimo da propriedade de string | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_STRING property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); string obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+
Temos esse tipo de métodos para cada classe-coleção, além disso, seu funcionamento foi considerado na terceira
parte da descrição da biblioteca ao criar a classe CSelect, por isso não vamos nos debruçar na sua análise.
Agora estamos prontos para criar a classe-coleção de símbolos.
Para trabalhar com uma coleção de símbolos do programa,
podem-se usar quatro modos:
- Trabalhar com apenas um símbolo,
- Trabalhar com uma lista de símbolos,
- Trabalhar com a janela "Observação do Mercado",
- Trabalhar com uma lista completa de símbolos no servidor.
Para que a classe de coleção de símbolos“saiba” com o que trabalhar, usaremos o seguinte esquema:
No programa — em
suas configurações, é especificada a enumeração de métodos para trabalhar com símbolos. Esse pode ser um dos quatro modos de operação
mencionados.
O programa também deve ter um array de string, que será preenchido com uma função da biblioteca assim:
- se for usado apenas um símbolo, o array conterá apenas o símbolo atual,
- se for usada apenas uma lista personalizada de símbolos, que também pode estar nas configurações do programa e cujos símbolos
estão separados por vírgulas, o array será preenchido com símbolos desta linha; se nesta linha houver apenas um símbolo ou a lista
estiver vazia, o trabalho será com o símbolo atual
- se for usada a Observação do Mercado, no array, em sua única célula, em vez do nome do símbolo, aparecerá "MARKET_WATCH"
- se for usada uma lista completa de símbolos no servidor, no array, em vez do nome do símbolo, aparecerá "ALL"
Tudo isso será feito automaticamente, enquanto o usuário precisará apenas selecionar o modo para trabalhar com a coleção de símbolos, bem como criar pelo menos um array de string e no máximo uma array de string e uma string predefinidos nas configurações.
Classe para a coleção de símbolos
Na pasta da biblioteca \MQL5\Include\DoEasy\Collections\ criamos a nova classe CSymbolsCollection no
arquivo
SymbolsCollection.mqh.
A classe base para ela deve ser uma classe
de objeto da biblioteca padrão
CObject.
Imediatamente inserimos todos os arquivos de classe necessários no arquivo recém-criado:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Coleção de ordens e transações históricas | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: public: //--- Construtor CSymbolsCollection(); }; //+------------------------------------------------------------------+
E para as classes-coleções de biblioteca que já se tornaram padrão adicionamos os membros-variáveis da classe e do método:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Coleção de ordens e transações históricas | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // Lista de todos os objetos-símbolo public: //--- Retorna a lista completa de coleções "como está" CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Retorna a lista da propriedade (1) inteira, (2) real e de (3) string selecionada que satisfaz o critério comparado CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Construtor CSymbolsCollection(); }; //+------------------------------------------------------------------+
Nós já consideramos todas essas variáveis e métodos ao criar as coleções passadas. Eu acho que não devemos nos debruçar sobre eles repetidamente.
Vamos adicionar todas as outras variáveis e métodos necessários para o funcionamento da classe-coleção de símbolos:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Coleção de ordens e transações históricas | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // Lista de todos os objetos-símbolo ENUM_SYMBOLS_MODE m_mode_list; // Modo de trabalho com listas de símbolos int m_delta_symbol; // Diferença no número de símbolos em comparação com a verificação anterior int m_last_num_symbol; // Número de símbolos na janela Observação do mercado na verificação anterior int m_global_error; // Código de erro global //--- Retorna o sinalizador indicando que o objeto-símbolo existe na lista contendo todos os símbolos bool IsPresentSymbolInList(const string symbol_name); //--- Cria um objeto-símbolo e o coloca na lista bool CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Retorna o tipo de lista usado para os símbolos (Observação do mercado/Servidor) ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]); //--- Determina de acordo com o nome e retorna se o símbolo pertence ao grupo ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name) const; //--- Retorna se o símbolo pertence à categoria de acordo com os critérios do usuário ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name) const; //--- Retorna se o símbolo pertence à categoria de acordo com o cálculo de garantia ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name) const; //--- Retorna se o símbolo pertence aos (1) majos, (2) minors, (3) extics, (4) rublo predefinidos //--- (5) indicativos, (6) metais, (7) commodities, (8) índice, (9) criptomoedas, (10) opções bool IsPredefinedFXMajor(const string name) const; bool IsPredefinedFXMinor(const string name) const; bool IsPredefinedFXExotic(const string name) const; bool IsPredefinedFXRUB(const string name) const; bool IsPredefinedIndicative(const string name) const; bool IsPredefinedMetall(const string name) const; bool IsPredefinedCommodity(const string name) const; bool IsPredefinedIndex(const string name) const; bool IsPredefinedCrypto(const string name) const; bool IsPredefinedOption(const string name) const; //--- Procura o símbolo e retorna um sinalizador indicando que existe no servidor bool Exist(const string name) const; public: //--- Retorna a lista completa de coleções "como está" CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Retorna a lista da propriedade (1) inteira, (2) real e de (3) string selecionada que satisfaz o critério comparado CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Retorna o número de símbolos na Observação do mercado int NewSymbols(void) const { return this.m_delta_symbol; } //--- Retorna o modo de trabalho com a lista de símbolos ENUM_SYMBOLS_MODE ModeSymbolsList(void) const { return this.m_mode_list; } //--- Construtor CSymbolsCollection(); //--- Define a lista de símbolos usados bool SetUsedSymbol(const string &symbol_used_array[]); //--- Atualiza (1) todos, (2) dados de cotação para os símbolos da coleção void Refresh(void); void RefreshRates(void); }; //+------------------------------------------------------------------+
A classe deve saber com qual lista de símbolos deve trabalhar: símbolo atual, conjunto de símbolos especificado pelo usuário, lista de
símbolos na janela "Observação do Mercado" ou lista completa de todos os símbolos no servidor. Variável-membro da classe
m_mode_list armazena um dos modos mencionados para trabalhar
com símbolos.
Ao trabalhar com a lista de símbolos da janela 'Observação do Mercado', é necessário monitorar essa lista constantemente (isso será
implementado no próximo artigo) e conhecer o
número de símbolos na verificação anterior e, consequentemente, qual
a mudança nesse número ao adicionar/remover símbolo(s) na lista da Observação do Mercado, para reconstruir a lista da coleção de
símbolos
m_list_all_symbols atempadamente e continuar a trabalhar com eles corretamente.
Como nas coleções anteriores,
introduzimos uma nova variável-membro da classe que armazena
código de erro, que se pode "ver" na classe base da biblioteca CEngine e
processar correta e atempadamente.
Ao criar um novo objeto-símbolo e adicioná-lo à coleção, é necessário verificar se o mesmo símbolo não está na lista. Para fazer isso, é
usado o método
IsPresentSymbolInList().
Para criar um novo símbolo e adicioná-lo à
coleção, é usado o método
CreateNewSymbol ().
Como a coleção de símbolos funciona em quatro
modos de listas de símbolos, é declarado o método
TypeSymbolsList () para determinar qual desses modos usar.
Antes
de criar um novo símbolo, primeiro é preciso identificar e definir o grupo ao qual ele pertence ou ao qual o usuário o associa. Para determinar
o grupo de símbolos (seu status), usamos o método
SymbolStatus().
Ao determinar o status de um símbolo, seu nome é
pesquisado primeiro nos arrays personalizados especificados usando o método
StatusByCustomPredefined().
Depois, se o método retornar o status
"geral", o status do símbolo será determinado pelo tipo de cálculo de garantia com o método
StatusByCalcMode().
Para
pesquisar segundo arrays personalizados e para determinar se um símbolo pertence a determinada categoria atribuída pelo usuário, são
utilizados métodos auxiliares que retornam o sinalizador que indica se o símbolo pertencente a maiores, menores, índices e outros grupos.
O
método
Exist() retorna o sinalizador que indica se o símbolo existe no
servidor.
O método NewSymbols() será necessário para retornar o número de
novos símbolos, adicionados ou removidos da janela Observação do Mercado, já o método
ModeSymbolsList() retorna para o programa chamado o modo trabalhando
com uma das quatro listas (símbolo atual, conjunto de símbolos predefinidos, lista da Observação do Mercado e lista completa de símbolos no
servidor).
O método SetUsedSymbol() aceita um array de símbolos ou uma
descrição do modo de lista de símbolos dentro do array transferido e cria uma lista de símbolos.
O método Refresh() atualiza todos os dados de todos os símbolos da
coleção que podem ser alterados e o método
RefreshRates() atualiza apenas os dados de cotação de todos os símbolos
da coleção. Ambos os métodos devem ser chamados a partir do temporizador do objeto principal da biblioteca CEngine.
Desse modo, definimos todos os métodos necessários para a operação da classe de coleção de símbolos neste estágio. Agora consideremos sua construção.
Implementação do construtor de classe:
//+------------------------------------------------------------------+ //| Construtor | //+------------------------------------------------------------------+ CSymbolsCollection::CSymbolsCollection(void) : m_last_num_symbol(0),m_delta_symbol(0),m_mode_list(SYMBOLS_MODE_CURRENT) { this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID); } //+------------------------------------------------------------------+
Na lista de inicialização do construtor, inicializamos o número de
símbolos na última verificação, a diferença entre o número de símbolos atual e o
anterior e definimos o modo "trabalhar com o símbolo atual".
No
corpo da classe,
classificamos a lista da coleção de símbolo por nome, limpamos
a lista e damos a ela o identificador "lista de coleção de símbolos".
Método para atualizar todos os dados de todos os símbolo da coleção:
//+------------------------------------------------------------------+ //| Atualiza todos os dados de símbolos da coleção | //+------------------------------------------------------------------+ void CSymbolsCollection::Refresh(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.Refresh(); } } //+------------------------------------------------------------------+
No ciclo, segundo o número de símbolos na coleção, obtemos o próximo símbolo da lista da coleção e atualizamos seus dados usando o método Refresh() da classe CSymbol, que estudamos no último artigo.
Método para atualizar os dados de cotação de todos os símbolos da coleção:
//+------------------------------------------------------------------+ //| Atualiza os dados de cotação dos símbolos da coleção | //+------------------------------------------------------------------+ void CSymbolsCollection::RefreshRates(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.RefreshRates(); } } //+------------------------------------------------------------------+
No ciclo, pelo número de símbolo da coleção, obtemos o próximo símbolo da lista da coleção e atualizamos seus dados usando o método RefreshRates() da classe CSymbol.
Método para criar um novo objeto-símbolo e colocá-lo na lista de coleção de símbolos:
//+------------------------------------------------------------------+ //| Cria um objeto-símbolo e o coloca numa lista | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name) { if(this.IsPresentSymbolInList(name)) { return true; } if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !this.Exist(name) #endif ) { string t1=TextByLanguage("Erro de entrada: não há símbolos ","Input error: no "); string t2=TextByLanguage(" no servidor"," symbol on the server"); ::Print(DFUN,t1,name,t2); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; return false; } CSymbol *symbol=NULL; switch(symbol_status) { case SYMBOL_STATUS_FX : symbol=new CSymbolFX(name); break; // Símbolo forex case SYMBOL_STATUS_FX_MAJOR : symbol=new CSymbolFXMajor(name); break; // Símbolo forex major case SYMBOL_STATUS_FX_MINOR : symbol=new CSymbolFXMinor(name); break; // Símbolo forex minor case SYMBOL_STATUS_FX_EXOTIC : symbol=new CSymbolFXExotic(name); break; // Símbolo exótico forex case SYMBOL_STATUS_FX_RUB : symbol=new CSymbolFXRub(name); break; // Símbolo forex/rublo case SYMBOL_STATUS_METAL : symbol=new CSymbolMetall(name); break; // Metal case SYMBOL_STATUS_INDEX : symbol=new CSymbolIndex(name); break; // Índice case SYMBOL_STATUS_INDICATIVE : symbol=new CSymbolIndicative(name); break; // Indicativo case SYMBOL_STATUS_CRYPTO : symbol=new CSymbolCrypto(name); break; // Símbolo de criptomoeda case SYMBOL_STATUS_COMMODITY : symbol=new CSymbolCommodity(name); break; // Símbolo de commoditie case SYMBOL_STATUS_EXCHANGE : symbol=new CSymbolExchange(name); break; // Símbolo de bolsa case SYMBOL_STATUS_FUTURES : symbol=new CSymbolFutures(name); break; // Futuro case SYMBOL_STATUS_CFD : symbol=new CSymbolCFD(name); break; // Contrato por diferença case SYMBOL_STATUS_STOCKS : symbol=new CSymbolStocks(name); break; // Título case SYMBOL_STATUS_BONDS : symbol=new CSymbolBonds(name); break; // Obrigação case SYMBOL_STATUS_OPTION : symbol=new CSymbolOption(name); break; // Opção case SYMBOL_STATUS_COLLATERAL : symbol=new CSymbolCollateral(name); break; // Ativo não negociável case SYMBOL_STATUS_CUSTOM : symbol=new CSymbolCustom(name); break; // Símbolo personalizado default : symbol=new CSymbolCommon(name); break; // Resto } if(symbol==NULL) { ::Print(DFUN,TextByLanguage("Falha ao criar o objeto-símbolo ","Failed to create symbol object "),name); return false; } if(!this.m_list_all_symbols.Add(symbol)) { string t1=TextByLanguage("Falha ao adicionar símbolo ","Failed to add "); string t2=TextByLanguage(" na lista"," symbol to the list"); ::Print(DFUN,t1,name,t2); delete symbol; return false; } return true; } //+------------------------------------------------------------------+
Para o método são transferidos o status e o
nome do símbolo, se esse símbolo já estiver na lista da coleção de
símbolos, depois não fazendo nada "silenciosamente" retornamos true,
pois não há erro e o símbolo não precisar ser adicionado, pois já existe.
Depois, verificamos se o símbolo existe no servidor por seu nome e, se ele não estiver,
exibimos uma mensagem indicando sua ausência,
definimos o código de erro como "símbolo desconhecido" e retornamos
false.
Se o símbolo existir, então dependendo
do statuspassado para o método, criamos um novo objeto-símbolo. Para criar um objeto-símbolo, usamos as classes herdadas do símbolo
abstrato correspondentes ao status transferido.
Em caso de falha ao criar o objeto, exibimos uma mensagem sobre
isso e
retornamos false.
Se
o novo objeto-símbolo for criado com sucesso,
adicionamo-lo à lista de coleção de símbolos e retornamos
true após a adição bem-sucedida,
ou exibimos uma mensagem de erro e
retornamos falseem
caso de falha.
Implementação do método que retorna o sinalizador que indica se o símbolo existe na lista da coleção:
//+------------------------------------------------------------------+ //| Retorna o sinalizador da existência do símbolo | //| de acordo com o seu nome na lista de todos os símbolos | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInList(const string symbol_name) { CArrayObj *list=dynamic_cast<CListObj*>(&this.m_list_all_symbols); list.Sort(SORT_BY_SYMBOL_NAME); list=CSelect::BySymbolProperty(list,SYMBOL_PROP_NAME,symbol_name,EQUAL); return(list==NULL || list.Total()==0 ? false : true); } //+------------------------------------------------------------------+
Para o método é passado o nome do símbolo desejado, depois, a lista é classificada pelo nome do símbolo e filtrada pelo nome transferido. Se a lista não estiver vazia, na lista será encontrado um símbolo com tal nome, e retornamos true, caso contrário, retornamos false .
Implementação do método que define a lista de símbolos da coleção:
//+------------------------------------------------------------------+ //| Define a lista de símbolos usados | //+------------------------------------------------------------------+ bool CSymbolsCollection::SetUsedSymbol(const string &symbol_used_array[]) { this.m_mode_list=this.TypeSymbolsList(symbol_used_array); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); //--- É usado penas o símbolo atual if(this.m_mode_list==SYMBOLS_MODE_CURRENT) { string name=::Symbol(); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); return this.CreateNewSymbol(status,name); } else { bool res=true; //--- É usada uma lista predefinida de símbolos if(this.m_mode_list==SYMBOLS_MODE_DEFINES) { int total=::ArraySize(symbol_used_array); for(int i=0;i<total;i++) { string name=symbol_used_array[i]; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- É usada a lista completa de símbolos do servidor else if(this.m_mode_list==SYMBOLS_MODE_ALL) { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) { string name=::SymbolName(i,false); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- É usada a lista de símbolos da janela "Observação do mercado" else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH) { int total=::SymbolsTotal(true); for(int i=0;i<total;i++) { string name=::SymbolName(i,true); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } } return false; } //+------------------------------------------------------------------+
O método cria uma lista-coleção de símbolos, dependendo do conteúdo do array
de símbolos passados para ela. Primeiro, é definido um método de lista
de símbolos (símbolo único/conjunto de símbolos personalizado/Observação do Mercado/lista completa), a seguir, a lista
é limpa e ordenada por nome.
Se for
usado apenas o símbolo atual, então
- definimos o status do símbolo de acordo com o seu nome
e
- retornamos o resultado da criação de um novo objeto-símbolo e adicionamo-lo à lista de coleção de símbolos.
Se for usada uma lista predefinida de símbolos, então
- num ciclo, usando o array de nomes de símbolos passados para o método, obtemos o próximo nome do símbolo da matriz
- determinamos o status do símbolo por seu nome
- adicionamos à variável retornada o resultado da criação e adição do objeto-símbolo à lista-coleção de símbolos
- se o símbolo não puder ser criado ou adicionado à lista , vamos para o próximo
- no final do ciclo, retornamos o estado da variável na qual foram
registrados os resultados da criação dos símbolos da coleção
Os outros dois modos são processados da mesma maneira que o modo de lista predefinida. Somente, em vez do array passado para o método, pegamos os símbolo a partir da janela Observação do Mercado ou da lista completa de símbolo no servidor.
Implementação do método que retorna o modo para trabalhar com listas de símbolos:
//+------------------------------------------------------------------+ //| Retorna o tipo de lista de símbolos usada (Market Watch / Server)| //+------------------------------------------------------------------+ ENUM_SYMBOLS_MODE CSymbolsCollection::TypeSymbolsList(const string &symbol_used_array[]) { int total=::ArraySize(symbol_used_array); if(total<1) return SYMBOLS_MODE_CURRENT; string type=::StringSubstr(symbol_used_array[0],13); return ( type=="MARKET_WATCH" ? SYMBOLS_MODE_MARKET_WATCH : type=="ALL" ? SYMBOLS_MODE_ALL : (total==1 && symbol_used_array[0]==::Symbol() ? SYMBOLS_MODE_CURRENT : SYMBOLS_MODE_DEFINES) ); } //+------------------------------------------------------------------+
Para o método é passado um array com nomes de símbolos ou
com uma descrição dos modos para trabalhar com listas.
Se for passado um array vazio, retornamos o modo para trabalhar apenas com o
símbolo atual.
Em seguida, obtemos seu conteúdo da célula zero do array e
- se, numa substring começando no índice 13, estiver a entrada "MARKET_WATCH", retornamos o modo para trabalhar com a janela "Observação do Mercado".
- Se aparecer a entrada "ALL", retornamos o modo para trabalhar com uma lista completa de símbolos.
- Caso contrário,
- se no array houver apenas uma entrada e
tiver o nome do símbolo atual, retornamos o modo para trabalhar somente com o símbolo atual.
- Bem, na última das opções possíveis, retornamos o modo para trabalhar
com uma lista predefinida.
Implementação do método que retorna se o símbolo pertence ao grupo de acordo com seu nome:
//+------------------------------------------------------------------+ //| Define de acordo com o nome e retorna se o símbolo pertence ao grupo //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::SymbolStatus(const string symbol_name) const { ENUM_SYMBOL_STATUS status=this.StatusByCustomPredefined(symbol_name); return(status==SYMBOL_STATUS_COMMON ? this.StatusByCalcMode(symbol_name) : status); } //+------------------------------------------------------------------+
O nome do símbolo é transferido para o método. Em seguida, é
verificado se ele pertence aos grupos personalizados especificados. Se,
como resultado, for retornado o status "grupo geral", procuramos o grupo de
acordo com a propriedade do símbolo "modo de cálculo de garantia". No final, retornamos
o status recebido. A propósito, pode ser equiparado a um dos grupos de acordo com o modo 'calcular lucro e margem' ou pode permanecer no
grupo geral de símbolos.
Como resultado, pode acontecer que quer o símbolo terá o status de grupo personalizado; quer poderá ser atribuído a ele um grupo de acordo com o método
de cálculo de garantia se não estava nos grupos personalizados; quer o símbolo permanecerá no grupo geral se não for possível
determiná-lo no grupo em questão.
Implementação de métodos que retornam o sinalizador que indica se um símbolo pertence a grupos personalizados específicos:
//+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos majors | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMajor(const string name) const { int total=::ArraySize(DataSymbolsFXMajors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMajors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos minors | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMinor(const string name) const { int total=::ArraySize(DataSymbolsFXMinors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMinors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos exotics | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXExotic(const string name) const { int total=::ArraySize(DataSymbolsFXExotics); for(int i=0;i<total;i++) if(name==DataSymbolsFXExotics[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos de rublos | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXRUB(const string name) const { int total=::ArraySize(DataSymbolsFXRub); for(int i=0;i<total;i++) if(name==DataSymbolsFXRub[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos indicadores | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndicative(const string name) const { int total=::ArraySize(DataSymbolsFXIndicatives); for(int i=0;i<total;i++) if(name==DataSymbolsFXIndicatives[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos metais | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedMetall(const string name) const { int total=::ArraySize(DataSymbolsMetalls); for(int i=0;i<total;i++) if(name==DataSymbolsMetalls[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos commodities | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCommodity(const string name) const { int total=::ArraySize(DataSymbolsCommodities); for(int i=0;i<total;i++) if(name==DataSymbolsCommodities[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence aos índices | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndex(const string name) const { int total=::ArraySize(DataSymbolsIndexes); for(int i=0;i<total;i++) if(name==DataSymbolsIndexes[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence às criptomoedas | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCrypto(const string name) const { int total=::ArraySize(DataSymbolsCrypto); for(int i=0;i<total;i++) if(name==DataSymbolsCrypto[i]) return true; return false; } //+------------------------------------------------------------------+ //| Retorna se o símbolo pertence às opções | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedOption(const string name) const { int total=::ArraySize(DataSymbolsOptions); for(int i=0;i<total;i++) if(name==DataSymbolsOptions[i]) return true; return false; } //+------------------------------------------------------------------+
Dependendo do nome do método (no grupo personalizado que está sendo verificado), os métodos simplesmente pesquisam se existe um símbolo cujo nome é
passado para o método no array personalizado correspondente ao seu grupo.
Se esse símbolo for encontrado no array, será retornadotrue.
Caso contrário,
false.
Método que retorna o status do símbolo de acordo com o fato de ele existir em grupos personalizados:
//+------------------------------------------------------------------+ //| Retorna a categoria segundo os critérios do usuário | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCustomPredefined(const string symbol_name) const { return ( this.IsPredefinedFXMajor(symbol_name) ? SYMBOL_STATUS_FX_MAJOR : this.IsPredefinedFXMinor(symbol_name) ? SYMBOL_STATUS_FX_MINOR : this.IsPredefinedFXExotic(symbol_name) ? SYMBOL_STATUS_FX_EXOTIC : this.IsPredefinedFXRUB(symbol_name) ? SYMBOL_STATUS_FX_RUB : this.IsPredefinedOption(symbol_name) ? SYMBOL_STATUS_OPTION : this.IsPredefinedCommodity(symbol_name) ? SYMBOL_STATUS_COMMODITY : this.IsPredefinedCrypto(symbol_name) ? SYMBOL_STATUS_CRYPTO : this.IsPredefinedMetall(symbol_name) ? SYMBOL_STATUS_METAL : this.IsPredefinedIndex(symbol_name) ? SYMBOL_STATUS_INDEX : this.IsPredefinedIndicative(symbol_name) ? SYMBOL_STATUS_INDICATIVE : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
Para o método é passado o nome do símbolo e em
cada grupo personalizado é alternadamente verificado se ele existe usando os métodos acima. Assim que um símbolo é encontrado em
qualquer um dos grupos, é retornado o status correspondente ao grupo onde o símbolo é encontrado.
Se nenhum símbolo for encontrado nos grupos, será retornado o status "grupo geral
de símbolos".
Método que retorna se o símbolo pertence a um grupo pelo método de cálculo de garantia:
//+------------------------------------------------------------------+ //| Retorna se pertence à categorias de cálculo de fundos de garantia| //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCalcMode(const string symbol_name) const { ENUM_SYMBOL_CALC_MODE calc_mode=(ENUM_SYMBOL_CALC_MODE)::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_CALC_MODE); return ( calc_mode==SYMBOL_CALC_MODE_EXCH_OPTIONS_MARGIN ? SYMBOL_STATUS_OPTION : calc_mode==SYMBOL_CALC_MODE_SERV_COLLATERAL ? SYMBOL_STATUS_COLLATERAL : calc_mode==SYMBOL_CALC_MODE_FUTURES ? SYMBOL_STATUS_FUTURES : calc_mode==SYMBOL_CALC_MODE_CFD || calc_mode==SYMBOL_CALC_MODE_CFDINDEX || calc_mode==SYMBOL_CALC_MODE_CFDLEVERAGE ? SYMBOL_STATUS_CFD : calc_mode==SYMBOL_CALC_MODE_FOREX || calc_mode==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE ? SYMBOL_STATUS_FX : calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS || calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX ? SYMBOL_STATUS_STOCKS : calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS || calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS_MOEX ? SYMBOL_STATUS_BONDS : calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES || calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS ? SYMBOL_STATUS_FUTURES : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
Para o método é passado o nome do símbolo, depois, para
este símbolo obtemos o método de cálculo de garantia e, em seguida, dependendo
do valor recebido, retornamos o status do símbolo. Se nenhum dos métodos
de cálculo tiver sido identificado, retornamos o status "grupo geral de símbolos".
Método que procura o símbolo no servidor e retorna um sinalizador indicando sua presença:
//+------------------------------------------------------------------+ //| Procura o símbolo e retorna um sinalizador indicando que existe no servidor //+------------------------------------------------------------------+ bool CSymbolsCollection::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
A classe de coleção de símbolos está pronta. Agora precisamos pô-la a funcionar. Tudo começa com a classe CEngine, ela é iniciada e gerenciada a partir dela. Faremos as alterações necessárias.
Inserimos o arquivo da classe de coleção de símbolos ao arquivo da classe CEngine e declaramos o objeto-coleção de símbolos e os métodos necessários:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/pt/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/pt/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Arquivos incluídos | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" //+------------------------------------------------------------------+ //| Classe base da biblioteca | //+------------------------------------------------------------------+ class CEngine : public CObject { private: CHistoryCollection m_history; // Coleção de ordens e transações históricas CMarketCollection m_market; // Coleção de ordens e transações de mercado CEventsCollection m_events; // Coleção de eventos CAccountsCollection m_accounts; // Coleção de contas CSymbolsCollection m_symbols; // Coleção de símbolos CArrayObj m_list_counters; // Lista dos contadores de temporizador int m_global_error; // Código de erro globla bool m_first_start; // Sinalizador da primeira inicialização bool m_is_hedge; // Sinalizador de conta de cobertura bool m_is_tester; // Sinalizador de trabalho no testador bool m_is_market_trade_event; // Sinalizador de evento de negociação na conta bool m_is_history_trade_event; // Sinalizador de evento de negociação no histórico da conta bool m_is_account_event; // Sinalizador do evento de alteração de conta ENUM_TRADE_EVENT m_last_trade_event; // Último evento de negociação na conta ENUM_ACCOUNT_EVENT m_last_account_event; // Último evento nas propriedades da conta //--- Retorna o índice do contador por ID int CounterIndex(const int id) const; //--- Retorna (1) o sinalizador da primeira inicialização, (2) a presença do sinalizador no evento de negociação bool IsFirstStart(void); //--- Trabalho com eventos (1) de ordens, de transações e posições, (2) de contas void TradeEventsControl(void); void AccountEventsControl(void); //--- (1) Trabalho com coleções de símbolos e (2) de eventos da lista de símbolos na janela de observação do mercado void SymbolEventsControl(void); void MarketWatchEventsControl(void); //--- Retorna a última (1) ordem pendente a mercado, (2) ordem a mercado, (3) última posição, (4) posição de acordo com o ticket COrder *GetLastMarketPending(void); COrder *GetLastMarketOrder(void); COrder *GetLastPosition(void); COrder *GetPosition(const ulong ticket); //--- Retorna a última (1) ordem pendente excluída, (2) ordem a mercado histórica, (3) última posição, (4) posição histórica (a mercado ou pendente) de acordo com o ticket COrder *GetLastHistoryPending(void); COrder *GetLastHistoryOrder(void); COrder *GetHistoryOrder(const ulong ticket); //--- Retorna (1) a primeira e a (2) última ordem a mercado histórica da lista de ordens e posições, (3) a última transação COrder *GetFirstOrderPosition(const ulong position_id); COrder *GetLastOrderPosition(const ulong position_id); COrder *GetLastDeal(void); public: //--- Retorna a lista de (1) posições a mercado, (2) ordens pendentes e (3) ordens a mercado CArrayObj *GetListMarketPosition(void); CArrayObj *GetListMarketPendings(void); CArrayObj *GetListMarketOrders(void); //--- Retorna a lista de (1) ordens históricas, (2) ordens pendentes excluídas e (3) transações (4) e todas as ordens a mercado de acordo com o seu ID CArrayObj *GetListHistoryOrders(void); CArrayObj *GetListHistoryPendings(void); CArrayObj *GetListDeals(void); CArrayObj *GetListAllOrdersByPosID(const ulong position_id); //--- Retorna a lista (1) de contas, (2) de eventos de contas, (3) o evento de alteração da conta de acordo com o seu índice de lista //--- (4) conta atual, (5) descrição do evento CArrayObj *GetListAllAccounts(void) { return this.m_accounts.GetList(); } CArrayInt *GetListAccountEvents(void) { return this.m_accounts.GetListChanges(); } ENUM_ACCOUNT_EVENT GetAccountEventByIndex(const int index) { return this.m_accounts.GetEvent(index); } CAccount *GetAccountCurrent(void); string GetAccountEventDescription(ENUM_ACCOUNT_EVENT event); //--- Retorna a lista de eventos usados CArrayObj *GetListAllUsedSymbols(void) { return this.m_symbols.GetList(); } //--- Retorna a lista de ordens, de transações e deposições CArrayObj *GetListAllOrdersEvents(void) { return this.m_events.GetList(); } //--- Redefine o último evento de negociação void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Retorna (1) o último evento de negociação, (2) o último evento nas propriedades da conta, (3) o sinalizador de conta de cobertura, (4) o sinalizador de trabalho no testador ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { return this.m_last_account_event; } bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } bool IsAccountsEvent(void) const { return this.m_accounts.IsAccountEvent(); } //--- Retorna o código de evento da conta int GetAccountEventsCode(void) const { return this.m_accounts.GetEventCode(); } //--- Retorna o código de erro global do CEngine int GetError(void) const { return this.m_global_error; } //--- Cria um contador de temporizador void CreateCounter(const int id,const ulong frequency,const ulong pause); //--- Temporizador void OnTimer(void); //--- Define a lista de símbolos usados bool SetUsedSymbols(const string &array_symbols[]) { return this.m_symbols.SetUsedSymbol(array_symbols); } //--- Construtor/Destrutor CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+
No método SymbolEventsControl() atualizaremos os dados de
cotação de todos os símbolos da coleção, já no método
MarketWatchEventsControl() atualizaremos os outros dados de todos os
símbolos da coleção e monitoraremos os eventos na janela 'Observação do Mercado' (na classe de eventos da coleção de símbolos no próximo
artigo)
O método GetListAllUsedSymbols() retorna para o programa
chamado a lista completa da coleção de símbolos usando o método GetList() da classe CSymbolsCollection.
O método SetUsedSymbols() chama o método com o mesmo nome
SetUsedSymbol() da classe CSymbolsCollection, que, por sua vez, preenche a lista de coleções com objetos-símbolo de todos os símbolos
usados no programa.
Consideremos a construção desses métodos.
No construtor da classe, criamos contadores, o primeiro
temporizador e o
segundo da coleção de símbolos. No primeiro, atualizaremos os
dados de cotação de todos os símbolos da coleção e, no segundo, os dados restantes do símbolo e controlaremos o rastreamento de eventos na
janela 'Observação do Mercado'.
//+------------------------------------------------------------------+ //| Construtor CEngine | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT),m_global_error(ERR_SUCCESS) { this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_is_tester=::MQLInfoInteger(MQL_TESTER); this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE); this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE); this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1); this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Falha ao criar o temporizador. Erro: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Falha ao criar o temporizador. Erro: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } #endif } //+------------------------------------------------------------------+
No manipulador OnTimer() da classe escrevemos strings para trabalhar com temporizadores de coleção de símbolos:
//+------------------------------------------------------------------+ //| Temporizador CEngine | //+------------------------------------------------------------------+ void CEngine::OnTimer(void) { //--- Temporizador de coleções para ordens e transações históricas, para ordens e posições a mercado int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Se não for um testador if(!this.IsTester()) { //--- Se a pausa terminar, trabalhamos com os eventos das coleções de ordens, de transações e de posições if(counter.IsTimeDone()) this.TradeEventsControl(); } //--- Se for o testador, trabalhamos com os eventos das coleções de acordo com o tick else this.TradeEventsControl(); } } //--- Temporizador de coleções para contas index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Se não for um testador if(!this.IsTester()) { //--- Se a pausa terminar, trabalhamos com os eventos das coleções de contas if(counter.IsTimeDone()) this.AccountEventsControl(); } //--- Se for o testador, trabalhamos com os eventos das coleções de acordo com o tick else this.AccountEventsControl(); } } //--- Temporizador1 da coleção de símbolos (atualização de dados de cotação dos símbolos na coleção) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Se não for um testador if(!this.IsTester()) { //--- Se a pausa terminar, atualizamos os dados de cotações para todos os símbolos na coleção if(counter.IsTimeDone()) this.SymbolEventsControl(); } //--- Se for o testador, atualizamos todos os dados de cotação para todos os símbolos na coleção de acordo com o tick else this.SymbolEventsControl(); } } //--- Temporizador2 da coleção de símbolos (atualização de todos os dados para os símbolos na coleção e acompanhamento de evento da lista de símbolos na janela de observação do mercado) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Se não for um testador if(!this.IsTester()) { //--- Se a pausa terminar if(counter.IsTimeDone()) { //--- atualizamos os dados de todos os símbolos na coleção this.m_symbols.Refresh(); //--- Se trabalhamos co uma lista da Observação do mercado, verificamos os eventos da janela Observação do mercado if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- Se for o testador, atualizamos os dados de todos os símbolos na coleção de acordo com o tick else this.m_symbols.Refresh(); } } } //+------------------------------------------------------------------+
Aqui, toda a lógica está escrita nos comentários do código, e acho que não faz sentido insistir em sua re-análise.
O método que trabalha com a coleção de símbolos nesta implementação simplesmente atualiza
os dados de cotação dos símbolo da coleção por meio do método RefreshRates da classe CSymbolsCollection:
//+------------------------------------------------------------------+ //| Trabalhando com uma coleção de símbolos | //+------------------------------------------------------------------+ void CEngine::SymbolEventsControl(void) { this.m_symbols.RefreshRates(); } //+------------------------------------------------------------------+
O método para trabalhar com eventos da janela 'Observação do mercado' nesta implementação não faz nada, apenas verifica
se é chamado a partir do testador e sai se funcionar no testador (no testador, não faz sentido rastrear os eventos da janela
Observação do Mercado):
//+------------------------------------------------------------------+ //| Trabalhando com eventos da lista de símbolos na janela de observação do mercado //+------------------------------------------------------------------+ void CEngine::MarketWatchEventsControl(void) { if(this.IsTester()) return; //--- Acompanhamento de eventos da janela "Observação do mercado" //--- } //+------------------------------------------------------------------+
Faremos todo o trabalho que tem a ver com eventos de coleção de símbolos no próximo artigo.
Estas são todas as alterações necessárias na classe CEngine.
Como precisamos passar para a classe de coleção de símbolos o modo para trabalhar com símbolos necessário, precisamos de uma função que determine o modo operacional e preencha o array correspondente de símbolos que serão transferidos para o objeto principal da biblioteca CEngine.
Abrimos o arquivo de função de serviço DELib.mqh da pasta \MQL5\Include\DoEasy\Services\ e escrevemos nele a função necessária:
//+------------------------------------------------------------------+ //| Prepara um array de símbolos para uma coleção de símbolos | //+------------------------------------------------------------------+ bool CreateUsedSymbolsArray(const ENUM_SYMBOLS_MODE mode_used_symbols,string defined_used_symbols,string &used_symbols_array[]) { //--- Se o trabalho com o símbolo atual if(mode_used_symbols==SYMBOLS_MODE_CURRENT) { //--- Escrevemos o nome do símbolo atual numa única célula do array ArrayResize(used_symbols_array,1); used_symbols_array[0]=Symbol(); return true; } //--- Se estiver trabalhando com um conjunto de símbolos predefinido (da string defined_used_symbols) else if(mode_used_symbols==SYMBOLS_MODE_DEFINES) { //--- Definimos o separador vírgula string separator=","; //--- Substituímos os separadores errados pelos corretos if(StringFind(defined_used_symbols,";")>WRONG_VALUE) StringReplace(defined_used_symbols,";",separator); if(StringFind(defined_used_symbols,":")>WRONG_VALUE) StringReplace(defined_used_symbols,":",separator); if(StringFind(defined_used_symbols,"|")>WRONG_VALUE) StringReplace(defined_used_symbols,"|",separator); if(StringFind(defined_used_symbols,"/")>WRONG_VALUE) StringReplace(defined_used_symbols,"/",separator); if(StringFind(defined_used_symbols,"\\")>WRONG_VALUE) StringReplace(defined_used_symbols,"\\",separator); if(StringFind(defined_used_symbols,"'")>WRONG_VALUE) StringReplace(defined_used_symbols,"'",separator); if(StringFind(defined_used_symbols,"-")>WRONG_VALUE) StringReplace(defined_used_symbols,"-",separator); if(StringFind(defined_used_symbols,"`")>WRONG_VALUE) StringReplace(defined_used_symbols,"`",separator); //--- Contanto que haja espaços, deletamos while(StringFind(defined_used_symbols," ")>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols," ",""); //--- Contanto que haja delimitadores duplos (após remover espaços entre eles), mudamos para um delimitador while(StringFind(defined_used_symbols,separator+separator)>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols,separator+separator,separator); //--- Se ficar um separador antes do primeiro símbolo na string, substituímos por um separador if(StringFind(defined_used_symbols,separator)==0) StringSetCharacter(defined_used_symbols,0,32); //--- Se ficar um separador após o último símbolo na string, mudamos por um separador if(StringFind(defined_used_symbols,separator)==StringLen(defined_used_symbols)-1) StringSetCharacter(defined_used_symbols,StringLen(defined_used_symbols)-1,32); //--- Removemos todos os itens desnecessários à esquerda e à direita #ifdef __MQL5__ StringTrimLeft(defined_used_symbols); StringTrimRight(defined_used_symbols); //--- __MQL4__ #else defined_used_symbols=StringTrimLeft(defined_used_symbols); defined_used_symbols=StringTrimRight(defined_used_symbols); #endif //--- Preparamos o array ArrayResize(used_symbols_array,0); ResetLastError(); //--- dividimos a string em separadores (vírgula) e inserimos todas as substrings encontradas no array int n=StringSplit(defined_used_symbols,StringGetCharacter(separator,0),used_symbols_array); //--- se não encontrarmos nada, exibimos uma mensagem sobre isso (neste caso, será selecionado automaticamente o trabalho com o símbolo atual) if(n<1) { string err= (n==0 ? DFUN_ERR_LINE+TextByLanguage("Erro. A string de símbolos predefinidos está vazia, será usado ","Error. String of predefined symbols is empty, the symbol will be used: ")+Symbol() : DFUN_ERR_LINE+TextByLanguage("Falha ao preparar array de símbolos usados. Erro","Failed to create an array of used characters. Error ")+(string)GetLastError() ); Print(err); return false; } } //--- Se o trabalho com a janela "Observação do mercado" ou com uma lista inteira else { //--- inserimos o nome do modo de trabalho (mode_used_symbols) numa única célula do array ArrayResize(used_symbols_array,1); used_symbols_array[0]=EnumToString(mode_used_symbols); } return true; } //+------------------------------------------------------------------+
Para o método são passados o modo de coleção de símbolos,
que deve ser definido nas configurações do programa ou de maneira "hard-coded" (se a seleção do modo não for necessária), a
lista de símbolos separados por vírgula necessária para
trabalhar (ou uma string vazia) e a
matriz na qual será inserida a lista de símbolos ou o modo de operação (para modos
de operação com Observação do Mercado e com uma lista completa de símbolos no servidor) e que serão enviados à classe CEngine para definir o
modo de operação da biblioteca com símbolos.
Todas as ações executadas pela função com a lista e com o array são descritas em detalhes diretamente na listagem e não faz sentido
considerá-las separadamente.
Isso completa o desenvolvimento da classe de coleção de símbolos e estamos prontos para testá-la.
Teste para a coleção de símbolos
Para testar a coleção, pegamos no EA do último artigo e o salvamos com o novo nome \MQL5\Experts\TestDoEasy\ Part15\TestDoEasyPart15_1.mq5.
Imediatamente nos parâmetros de entrada, adicionamos a seleção do modo de trabalho com os símbolos da biblioteca e a variável de string armazenando a lista de símbolos personalizados necessários para trabalhar se selecionado esse modo nas configurações:
//--- input variables input ulong InpMagic = 123; // Magic number input double InpLots = 0.1; // Lots input uint InpStopLoss = 50; // StopLoss in points input uint InpTakeProfit = 50; // TakeProfit in points input uint InpDistance = 50; // Pending orders distance (points) input uint InpDistanceSL = 50; // StopLimit orders distance (points) input uint InpSlippage = 0; // Slippage in points input double InpWithdrawal = 10; // Withdrawal funds (in tester) input uint InpButtShiftX = 40; // Buttons X shift input uint InpButtShiftY = 10; // Buttons Y shift input uint InpTrailingStop = 50; // Trailing Stop (points) input uint InpTrailingStep = 20; // Trailing Step (points) input uint InpTrailingStart = 0; // Trailing Start (points) input uint InpStopLossModify = 20; // StopLoss for modification (points) input uint InpTakeProfitModify = 60; // TakeProfit for modification (points) input ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list input string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) //--- global variables
À lista de variáveis globais adicionamos uma variável para armazenar
uma lista de símbolos personalizados e um array de string para passar
uma lista de símbolos para a biblioteca:
//--- global variables CEngine engine; #ifdef __MQL5__ CTrade trade; #endif SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ulong magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint slippage; bool trailing_on; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; string used_symbols; string array_used_symbols[]; //+------------------------------------------------------------------+
No manipulador OnInit() do EA atribuímos uma lista personalizada a uma
variável para armazená-la, preenchemos o array de símbolos personalizados
e o enviamos para a biblioteca:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Ao chamar esta função, no logo é exibida uma lista de constantes de enumeração, //--- definida no arquivo DELib.mqh nas strings 22 e 25, para verificar se as constantes são corretas //EnumNumbersTest(); //--- Configurando variáveis globais do EA prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"; for(int i=0;i<TOTAL_BUTT;i++) { butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i); butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i); } lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0)); magic_number=InpMagic; stoploss=InpStopLoss; takeprofit=InpTakeProfit; distance_pending=InpDistance; distance_stoplimit=InpDistanceSL; slippage=InpSlippage; trailing_stop=InpTrailingStop*Point(); trailing_step=InpTrailingStep*Point(); trailing_start=InpTrailingStart; stoploss_to_modify=InpStopLossModify; takeprofit_to_modify=InpTakeProfitModify; //--- Preenchendo o array de símbolos usados used_symbols=InpUsedSymbols; CreateUsedSymbolsArray(InpModeUsedSymbols,used_symbols,array_used_symbols); //--- Configurando o tipo de lista de símbolos usada na coleção de símbolos engine.SetUsedSymbols(array_used_symbols); //--- Verificando e removendo objetos gráficos não excluídos do EA
A função SetUsedSymbols(), discutida acima, criará um array de símbolo para enviá-lo para a classe de coleção de símbolos. Dependendo do modo selecionado, o array poderá conter quer o símbolo atual quer uma lista personalizada de símbolos quer uma descrição de string do modo de operação com a janela "Observação do Mercado" ou com uma lista completa de símbolos no servidor.
No final do manipulador OnInit(), inserimos o código para verificar rapidamente as listas de símbolos criados pela classe de coleção de símbolos:
//--- Configurando parâmetros da classe de negociação CTrade #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Verificação rápida da coleção de objetos-símbolos CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); symbol.PrintShort(); if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH) symbol.Print(); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Neste caso, obtemos a lista completa dos símbolos da coleção, no ciclo, na lista resultante obtemos outro símbolo, atualizamos todos os dados e imprimimos a descrição do símbolo no log - primeiro breve e depois se não estiver selecionado o modo "Trabalhar com a janela Observação do Mercado" ou "Trabalhar com a lista completa de símbolos no servidor", então imprimimos uma descrição completa das propriedades do símbolo no log.
Executamos o EA na janela do terminal e selecionamos o modo "Trabalhar com símbolos do Observação do Mercado" nas configurações. Como resultado, no log será exibida uma lista com breves descrições sobre todos os símbolos da coleção criada pela classe de coleção de símbolos:
2019.06.27 10:01:52.756 Ação ALNU 2019.06.27 10:01:52.756 Ação SU25075RMFS1 2019.06.27 10:01:52.756 Obrigação SU46022RMFS8 2019.06.27 10:01:52.756 Obrigação SU26214RMFS5 2019.06.27 10:01:52.756 Ação AESL 2019.06.27 10:01:52.756 Ação 123456.bin 2019.06.27 10:01:52.756 Ação ARMD 2019.06.27 10:01:52.757 Obrigação SU46018RMFS6 2019.06.27 10:01:52.757 Ação GAZP 2019.06.27 10:01:52.757 Metal XAUUSD 2019.06.27 10:01:52.757 Ação EURRUB_TOD 2019.06.27 10:01:52.757 Ação GBPRUB_TOM 2019.06.27 10:01:52.757 Futuro Si-9.19 2019.06.27 10:01:52.757 Futuro RTS-3.20 2019.06.27 10:01:52.758 Símbolo Forex menor USDNOK 2019.06.27 10:01:52.758 Símbolo Forex maior USDJPY 2019.06.27 10:01:52.758 Símbolo Forex maior EURUSD 2019.06.27 10:01:52.758 Símbolo Forex menor USDCZK 2019.06.27 10:01:52.758 Símbolo Forex maior USDCAD 2019.06.27 10:01:52.758 Símbolo Forex menor USDZAR 2019.06.27 10:01:52.758 Símbolo Forex menor USDSEK 2019.06.27 10:01:52.758 Símbolo Forex maior AUDUSD 2019.06.27 10:01:52.758 Símbolo Forex menor USDDKK 2019.06.27 10:01:52.758 Símbolo Forex maior NZDUSD 2019.06.27 10:01:52.759 Símbolo Forex menor USDPLN 2019.06.27 10:01:52.759 Símbolo Forex maior GBPUSD 2019.06.27 10:01:52.759 Símbolo Forex USDRUR 2019.06.27 10:01:52.759 Símbolo Forex exótico USDMXN 2019.06.27 10:01:52.759 Símbolo Forex USDHUF 2019.06.27 10:01:52.759 Símbolo Forex menor USDTRY 2019.06.27 10:01:52.759 Símbolo Forex menor USDHKD 2019.06.27 10:01:52.760 Símbolo Forex maior USDCHF 2019.06.27 10:01:52.760 Símbolo Forex menor USDSGD
Agora verificamos a busca de valores definidos na coleção de símbolos.
Renomeamos o EA e o salvamos com o novo nome
\MQL5\Experts\TestDoEasy\
Part15\TestDoEasyPart15_2.mq5.
No manipulador OnInit(), alteramos o código para verificar rapidamente a lista de símbolos da coleção. Excluímos a lista de símbolos no log, deixando apenas a atualização de dados de símbolos de coleção e adicionamos as linhas para obter o swap máximo e mínimo das posições longas e curtas, e a dispersão máxima e mínima dos símbolos na coleção. Exibimos os dados resultantes no log:
//--- Configurando parâmetros da classe de negociação CTrade #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Verificação rápida da coleção de objetos-símbolos CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); } } //--- Obtendo valores máximo e mínimo //--- obtemos as propriedades da conta atual (precisamos do número de casas decimais para a moeda da conta) CAccount *account=engine.GetAccountCurrent(); if(account!=NULL) { int index_min=0, index_max=0, dgc=(int)account.CurrencyDigits(); //--- Se o trabalho com a janela "Observação do mercado", na lista deixamos apenas os símbolos visíveis if(InpModeUsedSymbols==SYMBOLS_MODE_MARKET_WATCH) list=CSelect::BySymbolProperty(list,SYMBOL_PROP_VISIBLE,true,EQUAL); //--- swap mínimo/máximo de posições longas index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_LONG); // índice do símbolo na lista de coleções que contém o valor mínimo de swap para as posições longas index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_LONG); // índice do símbolo na lista de coleções que contém o valor máximo de swap para as posições longas if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Swap mínimo para as posições longas do símbolo ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Swap máximo para as posições longas do símbolo ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); } //--- swap mínimo/máximo de posições curtas index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_SHORT); // índice do símbolo na lista de coleções que contém o valor mínimo de swap para as posições cortas index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_SHORT); // índice do símbolo na lista de coleções que contém o valor máximo de swap para as posições cortas if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Swap mínimo para as posições curtas do símbolo ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Swap máximo para as posições curtas do símbolo ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); } // --- spread mínimo/máximo index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SPREAD); // índice do símbolo na lista de coleções que contém o valor mínimo de spread index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SPREAD); // índice do símbolo na lista de coleções que contém o valor máximo de spread if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Spread mínimo do símbolo ",symbol.Name()," = ",symbol.Spread()); symbol=list.At(index_max); if(symbol!=NULL) Print("Spread máximo do símbolo ",symbol.Name()," = ",symbol.Spread()); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Compilamos e executamos o EA no gráfico do terminal. Nas configurações, optamos por trabalhar com a lista completa de símbolos no servidor. Depois de criar a lista completa de coleção de símbolos no servidor (levará algum tempo), o log exibirá informações sobre o swap máximo e mínimo de posições longas e curtas e sobre a distribuição máxima e mínima de todos os símbolos na lista de coleção de símbolos:
2019.06.27 10:36:28.885 Swap mínimo para as posições longas do símbolo USDZAR = -192.9 2019.06.27 10:36:28.885 Swap máximo para as posições longas do símbolo USDMXN = 432.7 2019.06.27 10:36:28.886 Swap mínimo para as posições curtas do símbolo XAUUSD = -17.8 2019.06.27 10:36:28.886 Swap máximo para as posições curtas do símbolo USDMXN = 200.0 2019.06.27 10:36:28.886 Spread mínimo para o símbolo SU52001RMFS3 = 0 2019.06.27 10:36:28.886 Spread máximo para o símbolo GBPRUB_TOM = 3975
O que vem agora?
No próximo artigo, desenvolveremos uma classe de evento de coleção de símbolos.
Abaixo estão anexados todos os arquivos da versão atual da biblioteca e os arquivos do EA de teste. Você pode baixá-los e testar tudo sozinho.
Se você tiver perguntas, comentários e sugestões, poderá expressá-los nos comentários do artigo.
Artigos desta série:
Parte 1. Conceito, gerenciamento de dados e primeiros resultadosParte 2. Coleção do histórico de ordens e negócios
Parte 3. Coleção de ordens e posições de mercado, busca e ordenação
Parte 4. Eventos de Negociação. Conceito
Parte 5. Classes e coleções de eventos de negociação. Envio de eventos para o programa
Parte 6. Eventos da conta netting
Parte 7. Eventos de ativação da ordem stoplimit, preparação da funcionalidade para os eventos de modificação de ordens e posições
Parte 8. Eventos de modificação de ordens e posições
Parte 9. Compatibilidade com a MQL4 - preparação dos dados
Parte 10. Compatibilidade com a MQL4 - eventos de abertura de posição e ativação de ordens pendentes
Parte 11. Compatibilidade com a MQL4 - eventos de encerramento de posição
Parte 12. Implementação da classe de objeto "conta" e da coleção de objetos da conta
Parte 13. Eventos do objeto conta
Parte 14. O objeto símbolo
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/7041
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso