![Трейдминатор 3: восстание торговых роботов](https://c.mql5.com/i/articles/overlay.png)
Трейдминатор 3: восстание торговых роботов
Пролог
Давным-давно на далеком далеком форуме (MQL5) вышли в печать две статьи: "Генетические алгоритмы - это просто" автора joo и "Доктор трейдлав..." моего авторства. В первой статье автор дал нам в руки мощнейший инструмент оптимизации чего-бы то ни было, в том числе торговых стратегий - генетический алгоритм, реализованный средствами языка MQL5.
Используя его, я во второй статье попытался применить его для написания самооптимизирующего эксперта. Написание статьи завершено постановкой следующей задачи: создать эксперт (самооптимизирующийся, само собой разумеется), который может не только подобрать оптимальные параметры для какой-то определенной торговой системы, но и выбрать саму оптимальную стратегию из числа уже написанных стратегий. Посмотрим же, возможно ли это сделать, и если возможно - то как?
Сказки торговых роботов
Итак, сформулируем общие требования к самооптимизирующемуся экперту.
Он должен уметь (на исторических данных):
- выбрать лучшую из описаных стратегий;
- выбрать лучший финансовый инструмент;
- выбрать лучший размер депозита для торговли с учетом финансового рычага;
- выбрать лучшие параметры индикаторов в выбранной стратегии.
Далее, в реальной жизни он должен уметь:
- открывать и закрывать позиции;
- выбирать размер позиции;
- принимать решение о необходимости новой оптимизации.
На рисунке ниже предложена принципиальная схема такого эксперта.
Детальная схема со связями во вложении в архиве MQL5Article.zip файл MQLArticle.pdf
Помня, что нельзя объять необъятное, сразу же узаботимся внесением ограничений в логику эксперта. Договоримся, что (ВАЖНО):
- Принимать торговые решения эксперт будет при наступлении нового бара (на любом, выбраном нами таймфрейме).
- Исходя из п.1, но не только, эксперт будет закрывать сделки только по сигналам индикаторов, не используя TakeProfit и StopLoss и, соответственно, не используя TralingStop.
- Условие для начала новой оптимизации: просадка по балансу более установленного на этапе инициализации уровня. Здесь важно понимать, что это лично моё условие и каждый из Вас волен написать своё условие.
- Фитнесс-функция моделирует торговлю на истории и максимизирует смоделированный баланс при условии того, что относительная просадка по балансу смоделированных торгов ниже какого-то задаваемого уровня. Здесь также важно понимать, что это лично моя фитнесс-функция и каждый из Вас волен написать свою.
- Ограничим количество оптимизируемых параметров кроме трёх общих (стратегия, инструмет, доля депо) пятью для параметров индикаторных буферов. Такое ограничение логически вытекает из максимального количества индикаторных буферов для встроенных технических индикаторов. Если Вы собираетесь описывать стратегии, использующие пользовательские индикаторы с большим количеством индикаторных буферов, просто измените переменную OptParamCount в файле main.mq5 на нужное количество.
Теперь, когда требования пределены и ограничения наложены, можно посмотреть и на код, реализующий всё это.
Начнём с функции, где всё крутится.
void OnTick() { if(isNewBars()==true) { trig=false; switch(strat) { case 0: {trig=NeedCloseMA() ; break;}; //Количество строк case должно быть равным количеству стратегий case 1: {trig=NeedCloseSAR() ; break;}; case 2: {trig=NeedCloseStoch(); break;}; default: {trig=NeedCloseMA() ; break;}; } if(trig==true) { if(GetRelDD()>maxDD) //Если просадка баланса превысила допустимую: { GA(); //Вызываем функцию генетической оптимизации GetTrainResults(); //Получаем оптимизированные параметры maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); //Отсчет просадки будем теперь вести не от максимума баланса,... //...а от текущего баланса } } switch(strat) { case 0: {trig=NeedOpenMA() ; break;}; //Количество строк case должно быть равным количеству стратегий case 1: {trig=NeedOpenSAR() ; break;}; case 2: {trig=NeedOpenStoch(); break;}; default: {trig=NeedOpenMA() ; break;}; } Print(TimeToString(TimeCurrent()),";","Main:OnTick:isNewBars(true)", ";","strat=",strat); } }
Что здесь? Как и нарисовано на схеме, смотрим на каждом тике, не случился ли новый бар? Если случился, то, зная, какая сейчас выбрана стратегия, вызываем характерную именно для этой стратегии функцию проверки наличия открытой позиции и, при необходимости, её закрытие. Допустим, сейчас наилучшая стратегия на пробой SAR, соответственно, вызовется и функция NeedCloseSAR:
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); }
Любая функция закрытия позиции должна быть булевой и при закрытии позиции возвращать true. Это позволит следующему блоку кода функции OnTick() принять решение о необходимости начала новой оптимизации:
if(trig==true) { if(GetRelDD()>maxDD) //Если просадка баланса превысила допустимую: { GA(); //Вызываем функцию генетической оптимизации GetTrainResults(); //Получаем оптимизированные параметры maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); //Отсчет просадки будем теперь вести не от максимума баланса,... //...а от текущего баланса } }
Получаем текущую просадку по балансу, сравниваем с максимально возможной, если превысила - новая оптимизация (GA()). Функция GA() в свою очередь вызовет сердце всего эксперта - фитнесс-функцию FitnessFunction(int chromos) модуля GAModule.mqh:
void FitnessFunction(int chromos) //Фитнесс-функция для генетического оптимизатора:... //...выбирает стратегию, инструмент, долю депо,... //...параметры индикаторных буфферов;... //...можно оптимизировать что-угодно, но... //...необходимо внимательно следить за количествами генов { double ff=0.0; //Непосредственно фитнесс-функция strat=(int)MathRound(Colony[GeneCount-2][chromos]*StratCount); //ГА выбирает стратегию //Для режима прогона советника в тестере используем следующий код... z=(int)MathRound(Colony[GeneCount-1][chromos]*3); //ГА выбирает инструмент 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;}; } //..а для реального режима предыдущий код комментим, а нижеследующий раскомментим (выбор инструментов происходит в окне MarketWatch) /* z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));//ГА выбирает инструмент s=SymbolName(z,true); */ optF=Colony[GeneCount][chromos]; //ГА выбирает долю депо switch(strat) { case 0: {ff=FFMA( Colony[1][chromos], //Количество строк case должно быть равным количеству стратегий 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]); }
В зависимости от текущей выбранной стратегии вызывается модуль расчета фитнесс-функции, специфичный для какой-то конкретной стратегии. Например, ГА выбрал стохастик, будет вызвана функция FFStoch() и ей переданы оптимизирующие параметры индикаторных буферов:
double FFStoch(double par1,double par2,double par3,double par4,double par5) { int b; bool FFtrig=false; //Есть открытая позиция? string dir=""; //Направление открытой позиции double OpenPrice; //Цена открытия позиции double t=cap; //Текущий баланс double maxt=t; //Максимальный баланс double aDD=0.0; //Абсолютная просадка double rDD=0.000001; //Относительная просадка 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--) //Откуда начинаем копировать историю { 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); }
Фитнесс-функция стохастика вернёт значение смоделированного баланса основной функции, та передаст их Генетическому алгоритму. В какой то момент времени ГА примет решение об окончании оптимизации и функцией GetTrainResults() мы вернем основной программе оптимальные в текущий момент значения стратегии (допустим - скользящие средние), инструмента, доли депо и параметров индикаторых буферов, а также создадим для дальнейшей работы в реале индикаторы:
void GetTrainResults() //Получаем лучшие параметры { strat=(int)MathRound(Chromosome[GeneCount-2]*StratCount); //Запоминаем лучшую стратегию //Для режима прогона советника в тестере используем следующий код... z=(int)MathRound(Chromosome[GeneCount-1]*3); //Запоминаем лучший инструмент 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;}; } //..а для реального режима предыдущий код комментим, а нижеследующий раскомментим (выбор инструментов происходит в окне MarketWatch) /* z=(int)MathRound(Chromosome[GeneCount-1]*(SymbolsTotal(true)-1)); //Запоминаем лучший инструмент s=SymbolName(z,true); */ optF=Chromosome[GeneCount]; //Запоминаем лучшую долю депо switch(strat) { case 0: {GTRMA( Chromosome[1], //Количество строк case должно быть равным количеству стратегий 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); }
Теперь всё возвращается в то место, где всё крутится (OnTick()): зная, какая стратегия сейчас наилучшая, проверяется, не пора ли в рынок:
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); }
Круг замкнулся.
Проверим, как работает? Вот отчет за 2011 год на часовках по четырём мажорам: EURUSD, GBPUSD, USDCHF, USDJPY:
Отчет Тестера стратегий |
||||||||||||
InstaForex-Server (Build 567) |
||||||||||||
Настройки |
||||||||||||
Советник: | Main | |||||||||||
Символ: | EURUSD | |||||||||||
Период: | H1 (2011.01.01 - 2011.12.31) | |||||||||||
Входные параметры: | trainDD=0.50000000 | |||||||||||
maxDD=0.20000000 | ||||||||||||
Брокер: | InstaForex Companies Group | |||||||||||
Валюта: | USD | |||||||||||
Начальный депозит: | 10 000.00 | |||||||||||
Плечо: | 1:100 | |||||||||||
Результаты |
||||||||||||
Качество истории: | 100% | |||||||||||
Бары: | 6197 | Тики: | 1321631 | |||||||||
Чистая прибыль: | -538.74 | Общая прибыль: | 3 535.51 | Общий убыток: | -4 074.25 | |||||||
Прибыльность: | 0.87 | Матожидание выигрыша: | -89.79 | Уровень маржи: | 85.71% | |||||||
Фактор восстановления: | -0.08 | Коэффициент Шарпа: | 0.07 | Результат OnTester: | 0 | |||||||
Просадка баланса: | ||||||||||||
Абсолютная просадка по балансу: | 4 074.25 | Максимальная просадка по балансу: | 4 074.25 (40.74%) | Относительная просадка по балансу: | 40.74% (4 074.25) | |||||||
Просадка средств: | ||||||||||||
Абсолютная просадка по средствам: | 4 889.56 | Максимальная просадка по средствам: | 6 690.90 (50.53%) | Относительная просадка по средствам: | 50.53% (6 690.90) | |||||||
Всего трейдов: | 6 | Короткие трейды (% выигравших): | 6 (16.67%) | Длинные трейды (% выигравших): | 0 (0.00%) | |||||||
Всего сделок: | 12 | Прибыльные трейды (% от всех): | 1 (16.67%) | Убыточные трейды (% от всех): | 5 (83.33%) | |||||||
Самый большой прибыльный трейд: | 3 535.51 | Самый большой убыточный трейд: | -1 325.40 | |||||||||
Средний прибыльный трейд: | 3 535.51 | Средний убыточный трейд: | -814.85 | |||||||||
Максимальное количество непрерывных выигрышей (прибыль): | 1 (3 535.51) | Максимальное количество непрерывных проигрышей (убыток): | 5 (-4 074.25) | |||||||||
Максимальная непрерывная прибыль (число выигрышей): | 3 535.51 (1) | Максимальная непрерывный убыток (число проигрышей): | -4 074.25 (5) | |||||||||
Средний непрерывный выигрыш: | 1 | Средний непрерывный проигрыш: | 5 | |||||||||
Ордера |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Время открытия | Ордер | Символ | Тип | Объем | Цена | S / L | T / P | Время | Состояние | Комментарий | ||
2011.01.03 01:00 | 2 | USDCHF | sell | 28.21 / 28.21 | 0.9321 | 2011.01.03 01:00 | filled | |||||
2011.01.03 03:00 | 3 | USDCHF | buy | 28.21 / 28.21 | 0.9365 | 2011.01.03 03:00 | filled | |||||
2011.01.03 06:00 | 4 | USDCHF | sell | 24.47 / 24.47 | 0.9352 | 2011.01.03 06:00 | filled | |||||
2011.01.03 09:00 | 5 | USDCHF | buy | 24.47 / 24.47 | 0.9372 | 2011.01.03 09:00 | filled | |||||
2011.01.03 13:00 | 6 | USDCHF | sell | 22.99 / 22.99 | 0.9352 | 2011.01.03 13:00 | filled | |||||
2011.01.03 16:00 | 7 | USDCHF | buy | 22.99 / 22.99 | 0.9375 | 2011.01.03 16:00 | filled | |||||
2011.01.03 18:00 | 8 | USDJPY | sell | 72.09 / 72.09 | 81.57 | 2011.01.03 18:00 | filled | |||||
2011.01.03 21:00 | 9 | USDJPY | buy | 72.09 / 72.09 | 81.66 | 2011.01.03 21:00 | filled | |||||
2011.01.04 01:00 | 10 | USDJPY | sell | 64.54 / 64.54 | 81.67 | 2011.01.04 01:00 | filled | |||||
2011.01.04 02:00 | 11 | USDJPY | buy | 64.54 / 64.54 | 81.78 | 2011.01.04 02:00 | filled | |||||
2011.10.20 21:00 | 12 | USDCHF | sell | 56.30 / 56.30 | 0.8964 | 2011.10.20 21:00 | filled | |||||
2011.10.21 12:00 | 13 | USDCHF | buy | 56.30 / 56.30 | 0.8908 | 2011.10.21 12:00 | filled | |||||
Сделки |
||||||||||||
Время | Сделка | Символ | Тип | Направление | Объем | Цена | Ордер | Комиссия | Своп | Прибыль | Баланс | Комментарий |
2011.01.01 00:00 | 1 | balance | 0.00 | 0.00 | 10 000.00 | 10 000.00 | ||||||
2011.01.03 01:00 | 2 | USDCHF | sell | in | 28.21 | 0.9321 | 2 | 0.00 | 0.00 | 0.00 | 10 000.00 | |
2011.01.03 03:00 | 3 | USDCHF | buy | out | 28.21 | 0.9365 | 3 | 0.00 | 0.00 | -1 325.40 | 8 674.60 | |
2011.01.03 06:00 | 4 | USDCHF | sell | in | 24.47 | 0.9352 | 4 | 0.00 | 0.00 | 0.00 | 8 674.60 | |
2011.01.03 09:00 | 5 | USDCHF | buy | out | 24.47 | 0.9372 | 5 | 0.00 | 0.00 | -522.19 | 8 152.41 | |
2011.01.03 13:00 | 6 | USDCHF | sell | in | 22.99 | 0.9352 | 6 | 0.00 | 0.00 | 0.00 | 8 152.41 | |
2011.01.03 16:00 | 7 | USDCHF | buy | out | 22.99 | 0.9375 | 7 | 0.00 | 0.00 | -564.02 | 7 588.39 | |
2011.01.03 18:00 | 8 | USDJPY | sell | in | 72.09 | 81.57 | 8 | 0.00 | 0.00 | 0.00 | 7 588.39 | |
2011.01.03 21:00 | 9 | USDJPY | buy | out | 72.09 | 81.66 | 9 | 0.00 | 0.00 | -794.53 | 6 793.86 | |
2011.01.04 01:00 | 10 | USDJPY | sell | in | 64.54 | 81.67 | 10 | 0.00 | 0.00 | 0.00 | 6 793.86 | |
2011.01.04 02:00 | 11 | USDJPY | buy | out | 64.54 | 81.78 | 11 | 0.00 | 0.00 | -868.11 | 5 925.75 | |
2011.10.20 21:00 | 12 | USDCHF | sell | in | 56.30 | 0.8964 | 12 | 0.00 | 0.00 | 0.00 | 5 925.75 | |
2011.10.21 12:00 | 13 | USDCHF | buy | out | 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. |
Поясню зоны, выделенные на графике (пояснялки взяты из анализа логов):
- После старта советника Генетический алгоритм выбрал стратегию Пробой SAR на валютной паре USDCHF с долей депо в торговле 28%, поторговал до вечера третьего января, слил более 20% баланса и начал повторную оптимизацию.
- Теперь советник решил торговать Пробой SAR по USDJPY, но уже на весь депо (98%). Понятное дело, на долго его не хватило и уже четвертого утром он начал уже третью оптимизацию.
- Теперь его решение - торговать золотой и мёртвый крест по скользящим средним на USDCHF опять же на весь депо. И ждал он первый мёртвый крест аж до 20-го октября, и продал по максимуму, и отыграл все убытки. После этого до конца года условий на вход советник более не видел...
Продолжение следует?
Возможно ли продолжение? Каким может быть следующее поколение экспертов? Эксперт, который сам и изобретает стратегии, и выбирает лучшую... И если продолжить, то и деньгами распоряжается сам, докупает себе по железной части мозгов побольше, канал потолще...
Предупреждение о рисках:
Это краткое заявление не раскрывает абсолютно все виды риска и другие значимые аспекты при совершении сделок на изменение валютных соотношений с кредитным плечом. Вы должны понимать природу заключаемых сделок и связанных с этим рисков и учитывать собственные возможности. Тщательно обдумайте, подходит ли Вам работа на валютном рынке, соответствует ли она Вашему опыту, целям, финансовым ресурсам и другим обстоятельствам.
Форекс является не только высокодоходным, но и высокорискованным рынком. В условиях маржинальной торговли сравнительно небольшое изменение курса инструмента может оказать значительное влияние на состояние торгового счета трейдера, в результате чего может быть понесен убыток в размере начального депозита и любых средств, дополнительно внесенных им на счет для поддержания открытых позиций. Вы не должны рисковать тем, что не готовы потерять. Перед началом торговли, пожалуйста, убедитесь, что понимаете все риски и учитываете свой уровень опыта. Если нужно, воспользуйтесь независимым советом.
Лицензии:
Модуль UGAlib.mqh написан и распространяется на условиях лицензии BSD Андреем Дик aka joo.
Эксперт, вспомогательные модули, прилагаемые к этой статье, написаны и распространяются на условиях BSD автором Roman Rich. Текст лицензии в файле Lic.txt.
![Интервью с Александром Арашкевичем (ATC 2011)](https://c.mql5.com/2/0/AAA777_avatar.png)
![Преобразование Бокса-Кокса](https://c.mql5.com/2/0/Cox-Box-transformation_MQL5.png)
![Избавляемся от балласта самодельных DLL](https://c.mql5.com/2/0/DLL_MQL5_2.png)
![Создание советников при помощи Expert Advisor Visual Wizard](https://c.mql5.com/2/0/Expert_Advisor_Visual_Wizard.png)
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Понятно , что в статье рассказано не все . Вопрос простой стоит копать в этом направлении, есть там устойчивая на форварде ТС, или нет только мираж.
Понятно , что в статье рассказано не все . Вопрос простой стоит копать в этом направлении, есть там устойчивая на форварде ТС, или нет только мираж.
В статьях, как правило, показывают схему. ТС должен каждый разработать сам и попробовать через описанный метод усовершенствовать её. Кто же готовую систему выложит? Так не честно будет по отношению к себе. :)
Никто не просит готовую систему. Спрашиваю, авторам удалось создать на этой технологии устойчивый советник да или нет. Этого достаточно для продолжения собственных исследований, в целях экономии времени или есть смысл копать в другом направлении.