Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Тестирование стратегий по расписанию с автоподстановкой результата в советника
Slava, 2013.04.10 15:04
Вот пример. В OnTester советник отсылает 2 фрейма - история сделок и история, на которой он работал.
double OnTester() { BalanceInTime balance[]; double balance_current=TesterStatistics(STAT_INITIAL_DEPOSIT); uint data_count=0; MqlRates rates[]; //--- CopyRates(Symbol(),Period(),D'2010.12.01 0:00',D'2013.01.01 0:00',rates); //--- запросим всю торговую историю HistorySelect(0,TimeCurrent()); uint deals_total=HistoryDealsTotal(); if(deals_total!=257) { if(deals_total>0) { ulong ticket=0; ArrayResize(balance,deals_total); //--- собираем данные о сделках for(uint i=0; i<deals_total; i++) { if((ticket=HistoryDealGetTicket(i))>0) { long entry =HistoryDealGetInteger(ticket,DEAL_ENTRY); double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT) balance_current+=profit; balance[data_count].date=HistoryDealGetInteger(ticket,DEAL_TIME); balance[data_count].entry=(ENUM_DEAL_ENTRY)entry; balance[data_count].price=HistoryDealGetDouble(ticket,DEAL_PRICE); balance[data_count].balance=balance_current; data_count++; } } if(data_count<deals_total) ArrayResize(balance,data_count); } FrameAdd(MQL5InfoString(MQL5_PROGRAM_NAME),1,data_count,balance); //--- FrameAdd(MQL5InfoString(MQL5_PROGRAM_NAME),2,ArraySize(rates),rates); } //--- return(double(deals_total)); }
В OnTesterDeinit приём и обработка всех фреймов первого и второго типа
void OnTesterDeinit() { string name; ulong pass; long id; double value; int handle,i; BalanceInTime balance[]; MqlRates rates[]; //--- FrameFirst(); FrameFilter("",1); while(FrameNext(pass,name,id,value,balance)) { handle=FileOpen(name+"_"+string(id)+"_"+IntegerToString(pass,5,'0')+".txt",FILE_WRITE|FILE_CSV|FILE_ANSI); if(handle!=INVALID_HANDLE) { for(i=0; i<ArraySize(balance); i++) FileWrite(handle,balance[i].date,EnumToString(balance[i].entry),DoubleToString(balance[i].price,5),DoubleToString(balance[i].balance,2)); FileClose(handle); } } //--- FrameFirst(); FrameFilter("",2); while(FrameNext(pass,name,id,value,rates)) { handle=FileOpen(name+"_"+string(id)+"_"+IntegerToString(pass,5,'0')+".txt",FILE_WRITE|FILE_CSV|FILE_ANSI); if(handle!=INVALID_HANDLE) { for(i=0; i<ArraySize(rates); i++) FileWrite(handle,rates[i].time,DoubleToString(rates[i].open,5),DoubleToString(rates[i].high,5),DoubleToString(rates[i].low,5),DoubleToString(rates[i].close,5),string(rates[i].tick_volume)); FileClose(handle); } } //--- }
И пояснение к нему
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Slava, 2019.04.18 07:44
OnTesterPass вызывается, когда пришёл хотя бы один фрейм. Может прийти пачка фреймов. Поэтому в OnTesterPass надо принимать фреймы в цикле, а не по одному. Но если "после последнего раза - ни разу", то OnTesterPass не вызывается.
Оптимизация прекращается, когда пришёл последний результат. Фреймы могут поступить позднее, особенно если в фрейме передаётся большое количество данных или если передаётся сразу несколько фреймов на один проход. Поэтому в OnTesterDeinit, которая запускается по завершению оптимизации нужно организовывать приём оставшихся фреймов. Тоже в цикле.
Это - нормальная здоровая логика.
Я несколько раз давал примеры приёма фреймов именно в OnTesterDeinit, а не только в OnTesterPass. И именно приём сложных фреймов разных типов
FrameFilter предназначен для сложных фреймов. OnTesterPass реагирует только на один фрейм из прохода. Поэтому рекомендовал бы использовать только по подному фрейму на проход.
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Frames:
Чтение фреймов из mqd-файлов результатов Оптимизации.
Автор: fxsaber