![Trademinator 3: ascensão das máquinas comerciais](https://c.mql5.com/i/articles/overlay.png)
Trademinator 3: ascensão das máquinas comerciais
Prólogo
Era uma vez em um fórum distante (MQL5) dois artigos: ""Algoritmos Genéticos - é fácil!"" por Joo e "Dr. Tradelove..." que por mim foram publicados. No primeiro artigo, o autor nos equipou com uma poderosa ferramenta para otimizar qualquer coisa que você precisasse, incluindo estratégias de negociação - um algoritmo genético implementado por meio da linguagem MQL5.
Usando este algoritmo, no segundo artigo eu tentei desenvolver um Expert Advisor com auto-otimização baseado nele. O artigo termina com a formulação da seguinte tarefa: criar um Expert Advisor (auto-otimização, é claro), o que não só é possível selecionar os melhores parâmetros para um sistema de negociação particular, mas também escolher a melhor estratégia de todas as estratégias desenvolvidas. Vamos ver se é possível e, se for, como então.
Contos de robôs comerciais
Em primeiro lugar, nós formulamos os requisitos gerais para um Expert Advisor com auto-otimização.
Deve ser capaz de (com base em dados históricos):
- Selecionar a melhor estratégia entre as descritas;
- Escolher o melhor instrumento financeiro;
- Escolher o melhor tamanho do depósito para o comércio com correção de alavanca;
- Escolher os melhores parâmetros de indicadores da estratégia selecionada.
Além disso, na vida real, ela deve ser capaz de:
- Abrir e fechar posições;
- Escolher o tamanho da posição;
- Decidir se uma nova otimização é necessária.
A figura abaixo mostra um diagrama esquemático do Expert Advisor proposto.
Um esquema detalhado com limites está no arquivo anexado Scheme_en.
Tendo em mente que é impossível compreender a imensidão, nós introduzimos restrições na lógica Expert Advisor. Concordamos que (importante):
- O Expert Advisor tomará decisões comerciais mediante a ocorrência de uma nova barra (em qualquer período de tempo que selecionarmos).
- Com base no p.1, mas não limitado a ele, o Expert Advisor fechará negócios apenas nos sinais indicadores não usando o Obter Lucro e Parada Protetora e, consequentemente, não usando o Limite Móvel.
- A condição para iniciar uma nova otimização: um abaixamento do saldo é maior que o valor predefinido durante a inicialização do nível. Por favor, note que esta é a minha condição pessoal, e cada um pode escolher sua condição específica.
- A função de aptidão modela comércio no histórico e maximiza o balanço modelado, desde que o abaixamento relativo do saldo das operações simuladas está abaixo de um determinado nível predefinido. Também note que esta é a minha função de aptidão pessoal, e você pode escolher a sua específica.
- Nós limitamos o número de parâmetros a serem otimizados, com exceção dos três mais gerais (estratégia, instrumento e quota de depósito) para cinco para os parâmetros de indicadores buffers. Essa limitação segue logicamente o número máximo de indicadores buffers para os indicadores técnicos internos. Se você for descrever as estratégias que usam indicadores personalizados com um grande número de indicadores buffers, basta alterar a variável OptParamCount no arquivo main.mq5 para a quantidade desejada.
Agora que os requisitos são especificados e limitações selecionadas, você pode examinar o código que implementa tudo isso.
Vamos começar com a função onde tudo é executado.
void OnTick() { if(isNewBars()==true) { trig=false; switch(strat) { case 0: {trig=NeedCloseMA() ; break;}; //The number of case strings must be equal to the number of strategies case 1: {trig=NeedCloseSAR() ; break;}; case 2: {trig=NeedCloseStoch(); break;}; default: {trig=NeedCloseMA() ; break;}; } if(trig==true) { if(GetRelDD()>maxDD) //If a balance drawdown is above the max allowed value: { GA(); //Call the genetic optimization function GetTrainResults(); //Get the optimized parameters maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); //Now count the drawdown not from the balance maximum... //...but from the current balance } } switch(strat) { case 0: {trig=NeedOpenMA() ; break;}; //The number of case strings must be equal to the number of strategies case 1: {trig=NeedOpenSAR() ; break;}; case 2: {trig=NeedOpenStoch(); break;}; default: {trig=NeedOpenMA() ; break;}; } Print(TimeToString(TimeCurrent()),";","Main:OnTick:isNewBars(true)", ";","strat=",strat); } }
O que é aqui? Tal como foi estabelecido no diagrama, observamos cada tick, se existe uma nova barra. Se houver, então, sabendo qual estratégia é escolhida agora, chamamos a sua função específica para verificar se há uma posição aberta e fechá-la, se necessário. Suponha agora que a melhor estratégia de avanço é SAR, respectivamente, a função NeedCloseSAR será chamada:
bool NeedCloseSAR() { CopyBuffer(SAR,0,0,count,SARBuffer); CopyOpen(s,tf,0,count,o); Print(TimeToString(TimeCurrent()),";","StrategySAR:NeedCloseSAR", ";","SAR[0]=",SARBuffer[0],";","SAR[1]=",SARBuffer[1],";","Open[0]=",o[0],";","Open[1]=",o[1]); if((SARBuffer[0]>o[0]&&SARBuffer[1]<o[1])|| (SARBuffer[0]<o[0]&&SARBuffer[1]>o[1])) { if(PositionsTotal()>0) { ClosePosition(); return(true); } } return(false); }
Qualquer função de fechamento de posição deve ser booleana e retornar verdadeira quando fechar uma posição. Isso permite o próximo bloco de código da função OnTick() decidir se uma nova otimização é necessária:
if(trig==true) { if(GetRelDD()>maxDD) //If the balance drawdown is above the max allowed one: { GA(); //Call the genetic optimization function GetTrainResults(); //Get optimized parameters maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); //Now count the drawdown not from the balance maximum... //...but from the current balance } }
Obter o atual abaixamento de balanço e compará-lo com o máximo permitido. Se ele excedeu o valor máximo, executar uma nova otimização (GA()). A função GA() por sua vez, chama o centro do Expert Advisor - a função de aptidão FitnessFunction(int chromos) do módulo GAModule.mqh:
void FitnessFunction(int chromos) //A fitness function for the genetic optimizer:... //...selects a strategy, symbol, deposit share,... //...parameters of indicator buffers;... //...you can optimize whatever you need, but... //...watch carefully the number of genes { double ff=0.0; //The fitness function strat=(int)MathRound(Colony[GeneCount-2][chromos]*StratCount); //GA selects a strategy //For EA testing mode use the following code... z=(int)MathRound(Colony[GeneCount-1][chromos]*3); //GA selects a symbol switch(z) { case 0: {s="EURUSD"; break;}; case 1: {s="GBPUSD"; break;}; case 2: {s="USDCHF"; break;}; case 3: {s="USDJPY"; break;}; default: {s="EURUSD"; break;}; } //..for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window) /* z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));//GA selects a symbol s=SymbolName(z,true); */ optF=Colony[GeneCount][chromos]; //GA selects a deposit share switch(strat) { case 0: {ff=FFMA( Colony[1][chromos], //The number of case strings must be equal to the number of strategies Colony[2][chromos], Colony[3][chromos], Colony[4][chromos], Colony[5][chromos]); break;}; case 1: {ff=FFSAR( Colony[1][chromos], Colony[2][chromos], Colony[3][chromos], Colony[4][chromos], Colony[5][chromos]); break;}; case 2: {ff=FFStoch(Colony[1][chromos], Colony[2][chromos], Colony[3][chromos], Colony[4][chromos], Colony[5][chromos]); break;}; default: {ff=FFMA( Colony[1][chromos], Colony[2][chromos], Colony[3][chromos], Colony[4][chromos], Colony[5][chromos]); break;}; } AmountStartsFF++; Colony[0][chromos]=ff; Print(TimeToString(TimeCurrent()),";","GAModule:FitnessFunction", ";","strat=",strat,";","s=",s,";","optF=",optF, ";",Colony[1][chromos],";",Colony[2][chromos],";",Colony[3][chromos],";",Colony[4][chromos],";",Colony[5][chromos]); }
Dependendo da estratégia selecionada, o módulo de cálculo da função de aptidão que é específico para uma determinada estratégia, é chamado. Por exemplo, o GA escolheu um estocástico, FFStoch() será chamado, e otimização de parâmetros de indicadores buffers será transferido a ele:
double FFStoch(double par1,double par2,double par3,double par4,double par5) { int b; bool FFtrig=false; //Is there an open position? string dir=""; //Direction of the open position double OpenPrice; //Position Open price double t=cap; //Current balance double maxt=t; //Maximum balance double aDD=0.0; //Absolute drawdown double rDD=0.000001; //Relative drawdown Stoch=iStochastic(s,tf,(int)MathRound(par1*MaxStochPeriod)+1, (int)MathRound(par2*MaxStochPeriod)+1, (int)MathRound(par3*MaxStochPeriod)+1,MODE_SMA,STO_CLOSECLOSE); StochTopLimit =par4*100.0; StochBottomLimit=par5*100.0; dig=MathPow(10.0,(double)SymbolInfoInteger(s,SYMBOL_DIGITS)); leverage=AccountInfoInteger(ACCOUNT_LEVERAGE); contractSize=SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE); b=MathMin(Bars(s,tf)-1-count-MaxMAPeriod,depth); for(from=b;from>=1;from--) //Where to start copying of history { CopyBuffer(Stoch,0,from,count,StochBufferMain); CopyBuffer(Stoch,1,from,count,StochBufferSignal); if((StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1])|| (StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1])) { if(FFtrig==true) { if(dir=="BUY") { CopyOpen(s,tf,from,count,o); if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0; if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t; if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt; } if(dir=="SELL") { CopyOpen(s,tf,from,count,o); if(t>0) t=t+t*optF*leverage*(OpenPrice-o[1])*dig/contractSize; else t=0; if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t; if((maxt>0)&&(aDD/maxt>rDD)) rDD=aDD/maxt; } FFtrig=false; } } if(StochBufferMain[0]>StochBufferSignal[0]&&StochBufferMain[1]<StochBufferSignal[1]&&StochBufferMain[1]>StochTopLimit) { CopyOpen(s,tf,from,count,o); OpenPrice=o[1]; dir="SELL"; FFtrig=true; } if(StochBufferMain[0]<StochBufferSignal[0]&&StochBufferMain[1]>StochBufferSignal[1]&&StochBufferMain[1]<StochBottomLimit) { CopyOpen(s,tf,from,count,o); OpenPrice=o[1]; dir="BUY"; FFtrig=true; } } Print(TimeToString(TimeCurrent()),";","StrategyStoch:FFStoch", ";","K=",(int)MathRound(par1*MaxStochPeriod)+1,";","D=",(int)MathRound(par2*MaxStochPeriod)+1, ";","Slow=",(int)MathRound(par3*MaxStochPeriod)+1,";","TopLimit=",StochTopLimit,";","BottomLimit=",StochBottomLimit, ";","rDD=",rDD,";","Cap=",t); if(rDD<=trainDD) return(t); else return(0.0); }
A função de aptidão do estocástico retorna um equilíbrio simulado para a função principal, que vai passá-lo para o algoritmo genético. Em algum ponto no tempo a GA decide acabar com a otimização, e usando a função GetTrainResults(), retornamos os melhores valores atuais da estratégia (por exemplo - médias móveis), símbolo, a quota de depósito e parâmetros dos indicadores de buffers para o programa básico, bem como criamos indicadores para comércio real adicional:
void GetTrainResults() //Get the best parameters { strat=(int)MathRound(Chromosome[GeneCount-2]*StratCount); //Remember the best strategy //For EA testing mode use the following code... z=(int)MathRound(Chromosome[GeneCount-1]*3); //Remember the best symbol switch(z) { case 0: {s="EURUSD"; break;}; case 1: {s="GBPUSD"; break;}; case 2: {s="USDCHF"; break;}; case 3: {s="USDJPY"; break;}; default: {s="EURUSD"; break;}; } //...for real mode, comment the previous code and uncomment the following one (symbols are selected in the MarketWatch window) /* z=(int)MathRound(Chromosome[GeneCount-1]*(SymbolsTotal(true)-1)); //Remember the best symbol s=SymbolName(z,true); */ optF=Chromosome[GeneCount]; //Remember the best deposit share switch(strat) { case 0: {GTRMA( Chromosome[1], //The number of case strings must be equal to the number of strategies Chromosome[2], Chromosome[3], Chromosome[4], Chromosome[5]) ; break;}; case 1: {GTRSAR( Chromosome[1], Chromosome[2], Chromosome[3], Chromosome[4], Chromosome[5]) ; break;}; case 2: {GTRStoch(Chromosome[1], Chromosome[2], Chromosome[3], Chromosome[4], Chromosome[5]) ; break;}; default: {GTRMA( Chromosome[1], Chromosome[2], Chromosome[3], Chromosome[4], Chromosome[5]) ; break;}; } Print(TimeToString(TimeCurrent()),";","GAModule:GetTrainResults", ";","strat=",strat,";","s=",s,";","optF=",optF, ";",Chromosome[1],";",Chromosome[2],";",Chromosome[3],";",Chromosome[4],";",Chromosome[5]); } void GTRMA(double par1,double par2,double par3,double par4,double par5) { MAshort=iMA(s,tf,(int)MathRound(par1*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); MAlong =iMA(s,tf,(int)MathRound(par2*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN); CopyBuffer(MAshort,0,from,count,ShortBuffer); CopyBuffer(MAlong, 0,from,count,LongBuffer ); Print(TimeToString(TimeCurrent()),";","StrategyMA:GTRMA", ";","MAL=",(int)MathRound(par2*MaxMAPeriod)+1,";","MAS=",(int)MathRound(par1*MaxMAPeriod)+1); }
Agora que tudo está de volta ao lugar onde tudo está funcionando (OnTick()): sabendo que estratégia é agora a melhor, é verificado se é hora de ir para o mercado:
bool NeedOpenMA() { CopyBuffer(MAshort,0,0,count,ShortBuffer); CopyBuffer(MAlong, 0,0,count,LongBuffer ); Print(TimeToString(TimeCurrent()),";","StrategyMA:NeedOpenMA", ";","LB[0]=",LongBuffer[0],";","LB[1]=",LongBuffer[1],";","SB[0]=",ShortBuffer[0],";","SB[1]=",ShortBuffer[1]); if(LongBuffer[0]>LongBuffer[1]&&ShortBuffer[0]>LongBuffer[0]&&ShortBuffer[1]<LongBuffer[1]) { request.type=ORDER_TYPE_SELL; OpenPosition(); return(false); } if(LongBuffer[0]<LongBuffer[1]&&ShortBuffer[0]<LongBuffer[0]&&ShortBuffer[1]>LongBuffer[1]) { request.type=ORDER_TYPE_BUY; OpenPosition(); return(false); } return(true); }
O círculo fechou-se.
Vamos ver como funciona. Aqui está um relatório de 2011 sobre o período de tempo de 1 hora, com quatro pares principais: EURUSD, GBPUSD, USDCHF, USDJPY:
Relatório do testador de estratégia |
||||||||||||
InstaForex-Server (Build 567) |
||||||||||||
Configurações |
||||||||||||
Especialista: | Principal | |||||||||||
Símbolo: | EURUSD | |||||||||||
Período: | H1 (2011.01.01 - 2011.12.31) | |||||||||||
Parâmetros de entrada: | trainDD=0.50000000 | |||||||||||
maxDD=0.20000000 | ||||||||||||
Corretor: | Empresas do grupo InstaForex | |||||||||||
Moeda: | USD | |||||||||||
Depósito Inicial: | 10 000.00 | |||||||||||
Alavancagem: | 1:100 | |||||||||||
Resultados |
||||||||||||
Qualidade do histórico: | 100% | |||||||||||
Barras: | 6197 | Ticks: | 1321631 | |||||||||
Lucro total da rede: | -538,74 | Lucro bruto: | 3 535.51 | Prejuízo bruto: | -4 074.25 | |||||||
Fator lucro: | 0,87 | Pagamento esperado: | -89,79 | Nível de margem: | 85,71% | |||||||
Fator de recuperação: | -0,08 | Taxa do especialista: | 0,07 | Resultado onTester: | 0 | |||||||
Queda de balanço: | ||||||||||||
Queda absoluta de balanço: | 4 074.25 | Queda máxima de balanço: | 4 074.25 (40.74%) | Queda relativa de balanço: | 40.74% (4 074.25) | |||||||
Queda de lucro líquido: | ||||||||||||
Queda absoluta de lucro líquido: | 4 889.56 | Queda máxima de lucro líquido: | 6 690.90 (50.53%) | Queda relativa de lucro líquido: | 50.53% (6 690.90) | |||||||
Total de negócios: | 6 | Negócios curtos ( ganho 0%): | 6 (16.67%) | Negócios longos ( ganho 0%): | 0 (0.00%) | |||||||
Total de negócios: | 12 | Negócios lucrativos ( % do total): | 1 (16.67%) | Negócios com prejuízo ( % do total): | 5 (83.33%) | |||||||
Negócio com maior lucro: | 3 535.51 | Negócio com maior perda: | -1 325.40 | |||||||||
Lucro médio de negociação: | 3 535.51 | Perda comercial média: | -814,85 | |||||||||
Máximo de ganhos consecutivos: | 1 (3 535.51) | Máximo de perdas consecutivas: | 5 (-4 074.25) | |||||||||
Máximo de lucro consecutivo (contagem): | 3 535.51 (1) | Máximo de prejuízo consecutivo (contagem): | -4 074.25 (5) | |||||||||
Médias de ganhos consecutivos: | 1 | Médias de perdas consecutivas: | 5 | |||||||||
Pedidos |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Tempo aberto | Ordem | Símbolo | Tipo | Volume | Preço | S / L | T / P | Tempo | Estado | Comentário | ||
2011.01.03 01:00 | 2 | USDCHF | venda | 28.21 / 28.21 | 0,9321 | 2011.01.03 01:00 | preenchido | |||||
2011.01.03 3:00 | 3 | USDCHF | compra | 28.21 / 28.21 | 0,9365 | 2011.01.03 3:00 | preenchido | |||||
2011.01.03 6:00 | 4 | USDCHF | venda | 24.47 / 24.47 | 0,9352 | 2011.01.03 6:00 | preenchido | |||||
2011.01.03 9:00 | 5 | USDCHF | compra | 24.47 / 24.47 | 0,9372 | 2011.01.03 9:00 | preenchido | |||||
2011.01.03 13:00 | 6 | USDCHF | venda | 22.99 / 22.99 | 0,9352 | 2011.01.03 13:00 | preenchido | |||||
2011.01.03 16:00 | 7 | USDCHF | compra | 22.99 / 22.99 | 0,9375 | 2011.01.03 16:00 | preenchido | |||||
2011.01.03 18:00 | 8 | USDJPY | venda | 72.09 / 72.09 | 81,57 | 2011.01.03 18:00 | preenchido | |||||
2011.01.03 21:00 | 9 | USDJPY | compra | 72.09 / 72.09 | 81,66 | 2011.01.03 21:00 | preenchido | |||||
2011.01.04 01:00 | 10 | USDJPY | venda | 64.54 / 64.54 | 81,67 | 2011.01.04 01:00 | preenchido | |||||
2011.01.04 2:00 | 11 | USDJPY | compra | 64.54 / 64.54 | 81,78 | 2011.01.04 2:00 | preenchido | |||||
2011.10.20 21:00 | 12 | USDCHF | venda | 56.30 / 56.30 | 0,8964 | 2011.10.20 21:00 | preenchido | |||||
2011.10.21 12:00 | 13 | USDCHF | compra | 56.30 / 56.30 | 0,8908 | 2011.10.21 12:00 | preenchido | |||||
Negócios |
||||||||||||
Tempo | Negócio | Símbolo | Tipo | Direção | Volume | Preço | Ordem | Comissão | Troca | Lucro | Saldo | Comentário |
2011.01.01 00:00 | 1 | saldo | 0,00 | 0,00 | 10 000.00 | 10 000.00 | ||||||
2011.01.03 01:00 | 2 | USDCHF | venda | em | 28,21 | 0,9321 | 2 | 0,00 | 0,00 | 0,00 | 10 000.00 | |
2011.01.03 3:00 | 3 | USDCHF | compra | fora | 28,21 | 0,9365 | 3 | 0,00 | 0,00 | -1 325.40 | 8 674.60 | |
2011.01.03 6:00 | 4 | USDCHF | venda | em | 24,47 | 0,9352 | 4 | 0,00 | 0,00 | 0,00 | 8 674.60 | |
2011.01.03 9:00 | 5 | USDCHF | compra | fora | 24,47 | 0,9372 | 5 | 0,00 | 0,00 | -522,19 | 8 152.41 | |
2011.01.03 13:00 | 6 | USDCHF | venda | em | 22,99 | 0,9352 | 6 | 0,00 | 0,00 | 0,00 | 8 152.41 | |
2011.01.03 16:00 | 7 | USDCHF | compra | fora | 22,99 | 0,9375 | 7 | 0,00 | 0,00 | -564,02 | 7 588.39 | |
2011.01.03 18:00 | 8 | USDJPY | venda | em | 72,09 | 81,57 | 8 | 0,00 | 0,00 | 0,00 | 7 588.39 | |
2011.01.03 21:00 | 9 | USDJPY | compra | fora | 72,09 | 81,66 | 9 | 0,00 | 0,00 | -794,53 | 6 793.86 | |
2011.01.04 01:00 | 10 | USDJPY | venda | em | 64,54 | 81,67 | 10 | 0,00 | 0,00 | 0,00 | 6 793.86 | |
2011.01.04 2:00 | 11 | USDJPY | compra | fora | 64,54 | 81,78 | 11 | 0,00 | 0,00 | -868,11 | 5 925.75 | |
2011.10.20 21:00 | 12 | USDCHF | venda | em | 56,30 | 0,8964 | 12 | 0,00 | 0,00 | 0,00 | 5 925.75 | |
2011.10.21 12:00 | 13 | USDCHF | compra | fora | 56,30 | 0,8908 | 13 | 0,00 | -3,78 | 3 539.29 | 9 461.26 | |
0,00 | -3,78 | -534,96 | 9 461.26 | |||||||||
Copyright 2001-2011, MetaQuotes Software Corp. |
Deixe-me explicar a zona que é marcada na tabela (explicações são tomadas a partir da análise do log):
- Após o início do Expert Advisor, o algoritmo genético selecionou a estratégia revolucionária SAR no USDCHF com uma parte do depósito no comércio igual a 28%, então negociou até a noite de 3 de Janeiro, perdeu mais de 20% do saldo e começou a reotimização.
- Em seguida, o Expert Advisor decidiu negociar SAR revolucionário no USDJPY, mas com todo o depósito (98%). Naturalmente, não poderia negociar longo e, portanto, começou a sua terceira otimização na manhã do dia 04 de janeiro.
- Desta vez, decidiu comercializar cruzamento dourado e morto de médias móveis no USDCHF mais uma vez para todo o depósito. E esperou pelo primeiro cruzamento morto até 20 de outubro, e vendeu-o ao máximo, e ganhou de volta tudo o que perdeu. Depois disso, até o final do ano, o Expert Advisor não viu condições favoráveis para entrar no mercado.
Para ser continuado?
Pode ser continuado? Qual seria a próxima geração de Expert Advisors? O Expert Advisor que inventa estratégias e seleciona a melhor entre elas. E, além disso, pode administrar dinheiro, comprar o mais poderoso hardware, canal e assim por diante ...
Aviso de risco:
Esta breve declaração não revela completamente todos os riscos e outros aspectos significativos da moeda de negociação forex na margem. Você deve entender a natureza da negociação e da extensão da sua exposição ao risco. Você deve considerar cuidadosamente se o comércio é adequado para você, tendo em conta a sua experiência, objetivos, recursos financeiros e outras circunstâncias relevantes.
Forex não é apenas um mercado lucrativo, mas também altamente arriscado. Em termos de margem comercial, flutuações relativamente pequenas do câmbio podem ter um impacto significativo sobre a conta do comerciante, o que resulta em uma perda igual ao depósito inicial e quaisquer fundos adicionalmente depositados na conta para manter posições em aberto. Você não deve investir dinheiro que você não pode arcar com as despesas de perder. Antes de decidir negociar, por favor, certifique-se de que você compreendeu todos os riscos e leve em conta o seu nível de experiência. Se necessário, procure aconselhamento independente.
Licenças:
Módulo UGAlib.mqh é desenvolvido e distribuído sob a licença BSD por Andrey Dik aka Joo.
O Expert Advisor e módulos auxiliares ligados a este artigo são desenvolvidos e distribuído sob a licença BSD pelo autor Roman Rich. O texto da licença está disponível no arquivo Lic.txt.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/350
![Código MQL5 de segurança: proteção de senha, geradores de chaves, limites de tempo, licenças remotas e técnicas de codificação de chave de licença de EA avançadas](https://c.mql5.com/2/0/MQL5_protection_methods.png)
![Criando Expert Advisors usando o assistente visual Expert Advisor](https://c.mql5.com/2/0/Expert_Advisor_Visual_Wizard.png)
![Promova seus projetos de desenvolvimento utilizando bibliotecas EX5](https://c.mql5.com/2/0/Use_ex5_libraries.png)
![Previsão de séries temporais utilizando suavização exponencial (continuação)](https://c.mql5.com/2/0/Exponent_Smoothing2.png)
![MQL5 - Linguagem para estratégias de negociação inseridas no terminal do cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- 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