Помогите с несложной задачкой на mql4

 

Нет сильных навыков в программировании,но основы вроде как знаю. Написал я несколько функций. Например,

void OnTick ()

{ Trailing();  } 

 int Trailing()

{ kod }

И таких функций, как трейлинг, очень много, занимающие большое место.

Покажите на этом конкретном примере, как перенести эти функции в какой-то файл, ...не совсем понял куда и что переносить и в какой файл-то?

И потом, как включить этот файл в советник #include и импортировать функции #import  из включенного файла? Думаю многим понадобиться эта информация, для упрощения своих советников.

В справочнике есть примеры, но я не пойму как использовать сразу #include и #import вместе; и в какой отдельный файл нужно переносить функции?

 

include и import не обязательно вместе использовать. Можно или include или import использовать. Можно и вместе, конечно, но они не связаны между собой.

Проще всего include. Создаем файл mqh, сохраняем в папке include. Потом подключаем его: 

#include <filename.mqh>

После этого вызываем функции из этого файла точно так же, как будто они находятся в основном файле. 

Имя файла в угловых скобках означает, что подключаемый файл находиться в папке include.

Можно и в кавычках писать имя, например:

#include "filename.mqh"

В кавычках путь относительно основного файл. В этом примере - в той же папке, что и основной файл.

 
Dmitry Fedoseev:

include и import не обязательно вместе использовать. Можно или include или import использовать. Можно и вместе, конечно, но они не связаны между собой.

Проще всего include. Создаем файл mqh, сохраняем в папке include. Потом подключаем его: 

После этого вызываем функции из этого файла точно так же, как будто они находятся в основном файле. 

Имя файла в угловых скобках означает, что подключаемый файл находиться в папке include.

Можно и в кавычках писать имя, например:

В кавычках путь относительно основного файл. В этом примере - в той же папке, что и основной файл.

Дополню. import  - это импортирование функций из заранее скомпилированного файла библиотеки, который находится в папке MQL4\Libraries, например, MQL4\Libraries\PrintLabel.ex4.
Основной смысл в том, что функции из такого файла можно передавать другим без исходников, например, продавать в Маркете, как библиотеку. Пожалуй, в случае с программирования на MQL других особых выгод нет.

Когда файл подключается через include, происходит вот что. Перед компиляцией препроцессор тупо вставляет текст включаемого файла в основной файл и уже потом компилирует. То есть это именно ваш вариант. Вот полезный пример, файл у меня лежит в личной папке MQL4\Include\AvLib\Errors.mqh, чтобы не путался с остальными в MQL4\Include, тоже советую сделать свою папку. 

//+------------------------------------------------------------------+
//|                                                       Errors.mqh |
//|                                               Alexey Volchanskiy |
//|                                         https://mql.gnomio.com/  |
//+------------------------------------------------------------------+
#property copyright "Alexey Volchanskiy"
#property link      "http://www..ru"
#property strict

#include <stderror.mqh>
#include <stdlib.mqh>

// узнает код последней ошибки и возвращает строку с описанием
// код ошибки возвращается, т.к. передается по ссылке
string GetMyLastError(int &err)
{
   err = GetLastError();
   string serr = ErrorDescription(err);
   ResetLastError();
   return(serr);
}

// узнает код последней ошибки и возвращает строку с описанием
string GetMyLastError() // можно задавать несколько функций с одинаковыми именами, но разными параметрами
{
   int err = GetLastError();
   string serr = ErrorDescription(err);
   ResetLastError();
   return(serr);
}

 И теперь его можно подключать и использовать

 

#include <AvLib\Errors.mqh>
// пример вырезан из класса по управлению ордерами, но смысл будет ясен. WriteMsg пишет результат открытия ордера в лог-файл

    // открывает ордер с проверкой и нормализацией данных 
    COrder* OpenOrderWithCheck(string symbol, int cmd, double volume, double price, int slippage = 0, double stoploss = 0, double takeprofit = 0,
        string comment = NULL, int magic = 0, datetime expiration = 0, color arrow_color = CLR_NONE)
    {
        // При открытии рыночного ордера (OP_SELL или OP_BUY) в качестве цены открытия могут использоваться 
        // только самые последние цены Bid (для продажи) или Ask (для покупки). 
        if(NearOrderExist(symbol, cmd, magic, price)) // проверка на то, что уже есть открытый ордер по близкой цене
            return NULL;
        TypeOfOrder ordType = toPending;
        int dig = (int)MarketInfo(symbol, MODE_DIGITS);         // Количество знаков после запятой по инструменту
        if (cmd == OP_BUY)
        {
            price = MarketInfo(symbol, MODE_ASK);
            ordType = toMarket;
        }
        if (cmd == OP_SELL)
        {
            price = MarketInfo(symbol, MODE_BID);
            ordType = toMarket;
        }
        price = NormalizeDouble(price, dig);
        double minlot = MarketInfo(symbol, MODE_MINLOT);   // Минимальный размер лота
        double lotstep = MarketInfo(symbol, MODE_LOTSTEP); // Шаг изменения размера лота 
        double maxlot = MarketInfo(symbol, MODE_MAXLOT);   // Максимальный размер лота 

        int lot = (int)(volume / lotstep); // округлили до целого числа шагов изменения лота
        volume = lot * lotstep;   // теперь имеем правильный объем, кратный шагу изменения лота 
        if (volume < minlot)
        {
            volume = minlot;
            Alert("OpenOrder()", "Объем меньше минимального, задаю минимальное значение = ", volume, " лот(а)");
        }
        if (volume > maxlot)
        {
            volume = maxlot;
            Alert("OpenOrder()", "Объем больше максимального, задаю максимальное значение = ", volume, " лот(а)");
        }

        if (arrow_color == CLR_NONE && (cmd == OP_BUY || cmd == OP_BUYSTOP || cmd == OP_BUYLIMIT))
            arrow_color = m_colorBuy;
        if (arrow_color == CLR_NONE && (cmd == OP_SELL || cmd == OP_SELLSTOP || cmd == OP_SELLLIMIT))
            arrow_color = m_colorSell;
        
        ResetLastError();
        int ticket;
        uint dt1, timeOpen;
        dt1 = GetTickCount(); 
        if(m_orderModifyAfterOpen)
            ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0, comment, magic, expiration, arrow_color);
        else    
        {
            CalcStoplossAndTakeprofit(symbol, cmd, price, stoploss, takeprofit);
            ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
        }    
        timeOpen = GetTickCount() - dt1;

        COrder* pOrd = NULL;
        if (ticket < 0)
        {
            string err = GetMyLastError();
            Print("Ошибка открытия ордера, ", err);
            WriteMsg("ERROR!!!", cmd, -1, symbol, "OpenOrderWithCheck - ошибка открытия ордера: " + err);
            return pOrd;
        }
        else
        {
            WriteMsg("  Open", cmd, ticket, symbol, "  timeOpen= " + IntegerToString(timeOpen) + "  volume= " + DoubleToStr(volume, 2) + "  Price= " + DoubleToStr(price, dig) + "  SL= " + DoubleToStr(stoploss, dig) + "  TP= " + DoubleToStr(takeprofit, dig));
            ResetLastError();
            if(m_orderModifyAfterOpen && OrderSelect(ticket, SELECT_BY_TICKET))
            {
                price = OrderOpenPrice();
                CalcStoplossAndTakeprofit(symbol, cmd, price, stoploss, takeprofit);
                int counter = ORDER_MODIFY_REPEAT;
                bool result = false;
                while(!result && counter-- > 0)
                {
                    dt1 = GetTickCount(); 
                    result = OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color);
                    timeOpen = GetTickCount() - dt1;
                    WriteMsg("  Modify", cmd, ticket, symbol, "  timeModify= " + IntegerToString(timeOpen) + "  SL= " + DoubleToStr(stoploss, dig) + "  TP= " + DoubleToStr(takeprofit, dig));
                    Sleep(ORDER_MODIFY_REPEAT_SLEEP_TIME);
                }
            }    
            
            if (OrderSelect(ticket, SELECT_BY_TICKET))
            {
                price = OrderOpenPrice();
                datetime ordOpenTime = OrderOpenTime();
                // нужно запрашивать реальный объем, т.к. на счетах ECN при посылке ордера с большим объемом может открыться несколько ордеров
                // с разными объемами и разными ценами из-за того, что в стакане просто нет заявки с нужным лотом по запрошенной цене
                volume = OrderLots();
                stoploss = OrderStopLoss();
                takeprofit = OrderTakeProfit();
                pOrd = AddOrder(ordType, ticket, symbol, cmd, volume, price, ordOpenTime, magic, stoploss, takeprofit, comment, expiration, arrow_color);
                WriteMsg("Opened", cmd, ticket, symbol, "volume= " + DoubleToStr(volume, 2) + "  Price= " + DoubleToStr(price, dig) + "  SL= " + DoubleToStr(stoploss, dig) + "  TP= " + DoubleToStr(takeprofit, dig));
            }
        }
        return (pOrd);
    }
//**************

// пишет информацию об отрытом ордере в лог-файлы
    void WriteMsg(string msg0, int cmd, int orderTicket, string orderSymbol, string msg1)
    {
        string dts = TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS);
        string op;
        switch (cmd)
        {
        case OP_BUY:        op = "BUY"; break;
        case OP_SELL:       op = "SELL"; break;
        case OP_BUYLIMIT:   op = "BUYLIMIT"; break;
        case OP_BUYSTOP:    op = "BUYSTOP"; break;
        case OP_SELLLIMIT:  op = "SELLLIMIT"; break;
        case OP_SELLSTOP:   op = "SELLSTOP"; break;
        default:            op = "NONE"; break;
        }
        if (m_hLogAllOrders > 0)
            FileWrite(m_hLogAllOrders, dts, "  " + msg0, "  Ticket= " + IntegerToString(orderTicket), "  " + op, "  " + orderSymbol, "  " + msg1);
        if (m_hLogOrders > 0)
            FileWrite(m_hLogOrders, dts, "  ", msg0, "  ", orderTicket, "  ", op, "  ", orderSymbol, "  ", msg1);
    }
 
Dmitry Fedoseev:

include и import не обязательно вместе использовать. Можно или include или import использовать. Можно и вместе, конечно, но они не связаны между собой.

Проще всего include. Создаем файл mqh, сохраняем в папке include. Потом подключаем его: 

После этого вызываем функции из этого файла точно так же, как будто они находятся в основном файле. 

Имя файла в угловых скобках означает, что подключаемый файл находиться в папке include.

Можно и в кавычках писать имя, например:

В кавычках путь относительно основного файл. В этом примере - в той же папке, что и основной файл.

 как именно соединить эти 2 функции?
Если я хочу брать из этого файла функции, и не хочу  возиться с файлами по папкам. А чтобы все компилировалось в 1 и легко распространялось?
 

Откомпилированный файл не требует таскать за собой подключаемые файлы. Хоть сколько файлов подключается к советнику или индикатору, откомпилированный  файл будет один.

Какие две функции соединять? include и import? Это не функции. Их не надо соединять, они независимы.

Что значит брать функцию из файла и не возиться с файлами?  

Использование  import потребует таскать за собой библиотеку. Так что не пользуйтесь import'ом, пользуйтесь include'ом