12:34 Написание и тестирование экспертов | |
Написание и тестирование экспертов в торговой системе MetaTrader имеет ряд особенностей. Перед открытием позиции необходимо проверить, есть ли свободные деньги на счете. Если денег на счете недостаточно, то операция по открытию позиции закончится неудачно. При этом только при тестировании значение "FreeMargin" должно быть обязательно не меньше 1000, поскольку при тестировании цена одного лота составляет 1000. view plaincopy to clipboardprint if(AccountFreeMargin() < 1000) return(0); //денег нет – выходим Доступ к историческим данным можно получить, используя индексированные предопределенные массивы Time, Open, Low, High, Close, Volume. Исторически сложилось так, что индекс в этих массивах растет от конца к началу. Т.е., самые последние данные имеют индекс 0. Индекс 1 означает данные со смещением один период назад, индекс 2 - два периода назад, 3 - три периода назад и т.д.. view plaincopy to clipboardprint // если Close на прошлом баре меньше, чем // Close на позапрошлом баре if(Close[1] < Close[2]) return(0); Возможна также организация доступа к историческим данным по другим временным интервалам и даже по другим валютным парам. Для получения таких данных следует предварительно определить одномерный массив и выполнить операцию копирования с помощью функции "ArrayCopySeries". Причем при вызове функции можно передавать меньшее количество параметров и не указывать параметры по умолчанию. view plaincopy to clipboardprint double eur_close_m1[]; int number_copied = ArrayCopySeries(eur_close_m1, MODE_CLOSE, "EURUSD", PERIOD_M1); При написании эксперта так же, как и при создании любой другой программы, бывает необходим вывод некоторой дополнительной отладочной информации. Язык MQL4 предоставляет несколько возможностей для вывода такой информации. Функция "Alert" выводит на экран диалоговое окно, содержащее определённые пользователем данные. view plaincopy to clipboardprint Alert("FreeMargin grows to ", AccountFreeMargin(), "!"); Функция "Comment" выводит в левый верхний угол графика определённые пользователем данные. Символьная последовательность "\n" используется для перевода строки. view plaincopy to clipboardprint Comment("FreeMargin is ", AccountFreeMargin(), "."); Функция "Print" печатает определённые пользователем данные в системный журнал. view plaincopy to clipboardprint Print("FreeMargin is ", AccountFreeMargin(), "."); Для получения информации об ошибках в программах очень полезной является функция "GetLastError". Например, операция с ордером всегда возвращает номер тикета. Если номер тикета равен 0 (возникла какая-то ошибка при выполнении операции), то для определения дополнительной информации об ошибке необходимо вызвать функцию "GetLastError": view plaincopy to clipboardprint int iTickNum = 0; int iLastError = 0; ... iTickNum = OrderSend(Symbol(), OP_BUY, g_Lots, Ask, 3, 0, Ask + g_TakeProfit * g_Points); if(iTickNum <= 0) { iLastError = GetLastError(); if(iLastError != ERR_NO_ERROR) Alert("Some Message"); } Следует помнить, что вызов функции "GetLastError" выдает код последней ошибки и обнуляет ее значение. Поэтому повторный последовательный вызов этой функции всегда будет возвращать значение 0. Как определить начало очередного бара? (Это бывает необходимо, чтобы узнать, что предыдущий бар только что сформировался.) Существует несколько способов. Первый способ основан на проверке количества баров: view plaincopy to clipboardprint static int prevbars = 0; ... if(prevbars == Bars) return(0); prevbars = Bars; ... Этот способ может не сработать при подкачке истории. То есть, количество баров изменилось, а "предыдущий" еще не сформировался. В этом случае можно усложнить проверку на разницу между значениями, равную единице. Следующий способ основан на том, что значение "Volume" формируется на основе количества тиков, пришедших для каждого бара, и первый тик означает, что у вновь формирующегося бара значение "Volume" равно 1: view plaincopy to clipboardprint if( Volume[0] > 1) return(0); ... Этот способ может не сработать при слишком интенсивном поступлении ценовых тиков. Дело в том, что обработка приходящих ценовых тиков производится в отдельном потоке. И если этот поток занят во время поступления очередного тика, то во избежание излишней загрузки вычислительных ресурсов этот пришедший тик не обрабатывается! В этом случае можно также усложнить проверку, используя сохранение предыдущего значения "Volume". Третий способ основан на времени открытия бара: view plaincopy to clipboardprint static datetime prevtime=0; ... if(prevtime == Time[0]) return(0); prevtime = Time[0]; ... Это - самый надежный способ. Он сработает при любых обстоятельствах. Пример работы с файлом типа "CSV": view plaincopy to clipboardprint int h1; h1 = FileOpen("my_data.csv", MODE_CSV | MODE_WRITE, ";"); if(h1 < 0) { Print("Unable to open file my_data.csv"); return(false); } FileWrite(h1, High[1], Low[1], Close[1], Volume[1]); FileClose(h1); Некоторые пояснения к коду. Сначала открывается файл формата "CSV". В случае ошибки открытия файла происходит выход из программы. В случае успешного открытия файла производится стирание его содержимого, запись данных в файл и последующее закрытие файла. Если необходимо сохранить содержимое открываемого файла, то следует использовать режим открытия MODE_READ: view plaincopy to clipboardprint int h1; h1 = FileOpen("my_data.csv", MODE_CSV | MODE_WRITE | MODE_READ, ";"); if(h1 < 0) { Print("Unable to open file my_data.csv"); return(false); } FileSeek(h1, 0, SEEK_END); FileWrite(h1, High[1], Low[1], Close[1], Volume[1]); FileClose(h1); В этом примере запись производится в конец файла. Для этого сразу после его открытия мы воспользовались функцией "FileSeek". | |
Категория: Все про советники | Просмотров: 784 | |
Всего комментариев: 0 | |