| / | Статьи |
Cтатьи
Примеры
Основы создания хеджирующего эксперта
Авторизуйтесь или зарегистрируйтесь , чтобы добавить новую статью
|
Основы создания хеджирующего эксперта [ en ]Введение
Я собираюсь изложить основную идею создания простого хеджирующего эксперта. Вот основные данные о хеджирующем советнике:
Всё вышеизложенное - несложные понятия, которые должны быть известны хеджерам на рынке Forex для использования хеджирующего эксперта в MT4. Теперь можно приступить к его созданию. Кодируем хеджирующий эксперт шаг за шагомШаг 1: Входные параметры
До того как начать создание хеджирующего эксперта, мы должны выбрать 2 коррелирующих символа, т.е.:
В данной статье я выбрала свою любимую хедж-пару: EURJPY и GBPJPY. Её символы всегда двигаются в одинаковом направлении, что упрощает установку хеджирующего ордера. Теперь давайте начнём. Для создания хеджирующего эксперта нужно ознакомиться с входными переменными, описанными ниже. // это нужно для блокировки функции отправки ордера (sending function), но // не для блокировки функции close. extern bool BlockOpening = false; extern string BaseSymbol = "EURJPY";//первый символ extern string H_Symbol = "GBPJPY";//второй символ extern bool MoveSameWay = true;//двигаются они в одном направлении или нет extern int CorPeriod = 5;//предпочитаемый период корреляции extern double BaseLotSize = 1.5;//размер лота первого символа extern double H_LotsSize = 1.0;//размер лота второго символа extern double ExpectProfit$ = 137;//ожидаемая прибыль в валюте USD //допустимый проигрыш в USD в случае возникновения ошибки extern double AcceptableLoss$ = -77; extern string ExpectCor = "______";//ожидаемая корреляция для хеджирования //это большее значение ожидаемой корреляции (expect cor), оно должно быть больше, чем "And" extern double Between = 1.05; extern double And = 0.9;//это более низкий уровень expect cor extern string MISC = "______";//немного больше extern int MagicNo = 318;//предпочитаемjt магическое число (magic number) extern bool ShowStatus = true;//показать актуальное состояние хеджирования //проиграть звук, когда выполнились функции SendH и CloseH extern bool PlayAudio = false; Шаг 2: Объявление переменных
Ниже представлены переменные, используемые в нашем эксперте, и я хочу дать пояснения по переменным, необходимые для понимания работы эксперта. int BSP // спред базового символа , HSP // спред хеджирующего символа , gsp , BOP = -1 // тип ордера базового символа , HOP = -1 // тип ордера хеджирующего символа , up = 0 , Hcnt = 0 , u = 0 , d = 0 , day = 0 , sent=0 , firstopen , expire; double Lot , BaseOpen // цена открытия ордера базового символа , HOpen // цена открытия ордера хеджирующего символа , BPt // значение пункта для базового символа , HPt // значение пункта для хеджирующего символа , BSwapL // значение свопа для покупки базового символа , BSwapS // значение свопа для продажи базового символа , HSwapL // значение свопа для покупки хеджированного символа , HSwapS; // значение свопа для продажи хеджированного символа bool SResult = false, BResult = false, H1.profitswap, H2.profitswap, H3.profitswap; bool SwapMode = true, allmeetcor = false, BlockOpen = false, buy,sell,cleared = false; string H1.string = "", H2.string = "", H3.string = "", OrdComment = "", candletxt,tdstxt = ""; Шаг 3: Получение всех необходимых статических параметров
Теперь зададим некоторые статические значения, которые будут объявлены в части init(). //+------------------------------------------------------------------+ //| функция инициализации эксперта | //+------------------------------------------------------------------+ int init() { //---- BSP = MarketInfo(BaseSymbol,MODE_SPREAD); HSP = MarketInfo(H_Symbol ,MODE_SPREAD); BPt = MarketInfo(BaseSymbol,MODE_POINT); HPt = MarketInfo(H_Symbol ,MODE_POINT); BSwapL = MarketInfo(BaseSymbol,MODE_SWAPLONG); BSwapS = MarketInfo(BaseSymbol,MODE_SWAPSHORT); HSwapL = MarketInfo(H_Symbol,MODE_SWAPLONG); HSwapS = MarketInfo(H_Symbol,MODE_SWAPSHORT); //---- return(0); } Шаг 4: Полезные функции
Прежде чем перейти к самой интересной части, функции "start()", начнём с функций, используемых в этом эксперте. Но, пожалуйста, обратите внимание на то, что все функции останутся за пределами функции start(). 1. Корреляционная функция Начнём с функций расчёта корреляции. Ниже приведены функции, которые применял разработчик выложенного в свободный доступ корреляционного индикатора (igorad2004@list.ru) и модифицированного нами для более лёгкого использования в данном эксперте. Так что нам больше не придётся вызывать коэффициент корреляции из внешнего индикатора. Неплохо? //+------------------------------------------------------------------+ //| КОРРЕЛЯЦИЯ | //+------------------------------------------------------------------+ double symboldif(string symbol, int shift) { return(iClose(symbol, 1440, shift) - iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, PRICE_CLOSE, shift)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double powdif(double val) { return(MathPow(val, 2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double u(double val1,double val2) { return((val1*val2)); } //+------------------------------------------------------------------+ //| Вот настоящая корреляционная функция, которую нужно вызвать | //+------------------------------------------------------------------+ double Cor(string base, string hedge) { double u1=0,l1=0,s1=0; for(int i = CorPeriod - 1; i >= 0; i--) { u1 += u(symboldif(base, i), symboldif(hedge, i)); l1 += powdif(symboldif(base, i)); s1 += powdif(symboldif(hedge, i)); } if(l1*s1 > 0) return(u1 / MathSqrt(l1*s1)); } //+------------------------------------------------------------------+ Переменная CorPeriod является внешней и входной переменной, что позволяет нам настроить её. Когда вам понадобится рассчитать корреляцию между двумя символами, просто вызовите функцию Cor(string base,string hedge), например, так: Cor(EURJPY,GBPJPY). Согласитесь, это несложно. 2. Функция отправки хеджа На мой взгляд, управлять отправкой хеджа проще путём создания функции SendH, описанной ниже. //+------------------------------------------------------------------+ //| ОТПРАВКА ХЕДЖА | //+------------------------------------------------------------------+ bool SendH(string symbol, int op, double lots, double price, int sp, string comment, int magic) { if(OrderSend(symbol , op , lots , price , sp , 0 , 0 , comment , magic , 0 , CLR_NONE) > 0) { return(true); if(PlayAudio) PlaySound("expert.wav"); } else { Print(symbol, ": ", magic, " : " , ErrorDescription(GetLastError())); return(false); } } //+------------------------------------------------------------------+ Здесь вы можете более подробно ознакомиться с функцией OrderSend. Функция ErrorDescription(GetLastError()), приведённая выше, заставляет наш эксперт сообщать нам, какая ошибка имела место во время работы торговой функции. Чтобы воспользоваться функцией описания ошибки, необходимо включить файл "stdlib.mqh", поместив следующий код: //+------------------------------------------------------------------+ //| MyHedge.mq4 | //| myHedge | //| http://dailyh.blogspot.com/ | //+------------------------------------------------------------------+ #property copyright "myHedge" #property link "http://dailyh.blogspot.com/" #include <stdlib.mqh> //+------------------------------------------------------------------+ Чтобы воспользоваться ею, просто вызовите функцию "ErrorDescription()", как показано выше. 3. Функция закрытия хеджа Помимо отправки ордеров, нам нужна функция, которая бы закрывала все хеджирующие ордера по достижении ими ожидаемого уровня прибыли. Вот она, пожалуйста: //+------------------------------------------------------------------+ //| ЗАКРЫТИЕ ХЕДЖА | //+------------------------------------------------------------------+ bool CloseHedge(int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) SResult = true; } } if(SResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseHedge Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+ Эта функция закроет только ордера с одинаковым магическим числом (magic number), то есть она не будет влиять на хеджирующие ордера с другими магическими числами. Так что беспокоиться на самом деле не о чем. Перед использованием функции закрытия нам нужно определить, "сколько у нас теперь есть" при помощи функции, описанной ниже. 4. Функция нахождения общей прибыли //+------------------------------------------------------------------+ //| ОБЩАЯ ПРИБЫЛЬ (TOTAL PROFIT) | //+------------------------------------------------------------------+ double TotalCurProfit(int magic) { double MyCurrentProfit = 0; for(int cnt = 0 ; cnt < OrdersTotal() ; cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderMagicNumber() == magic) { MyCurrentProfit += (OrderProfit() + OrderSwap()); } } return(MyCurrentProfit); } //+------------------------------------------------------------------+ Как и в случае с функцией закрытия, для определения прибыли от хеджирования нам нужно следить только за ордерами с одинаковым магическим числом, чтобы правильно закрывать их. Чтобы воспользоваться ими, просто напишите код такого вида: if(TotalCurProfit(318) > 100) CloseHedge(318); Все значения прибыли рассчитываются в долларах США. Как следует из вышеуказанной строки, если общая прибыль ордеров с магическим номером 318 превышает $100, они будут закрыты. Для открытия хеджирующего ордера нам нужно знать, что нет никакого другого ордера, установленного по тому же символу и с тем же магическим числом, в тот момент, когда мы хотим отправить хедж. Это можно определить при помощи данной функции. 5. Получение количества существующих позиций //+------------------------------------------------------------------+ //| СУЩЕСТВУЮЩИЕ ПОЗИЦИИ (EXISTING POSITIONS) | //+------------------------------------------------------------------+ int ExistPositions(string symbol, int magic) { int NumPos = 0; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos++; } } return(NumPos); } //+------------------------------------------------------------------+ Эту функцию можно использовать следующим образом: ExistPositions("GBPJPY",318) Данная функция вернёт нам, "сколько существующих ордеров по GBPJPY с магическим номером 318 активны" в данный момент. Это ещё одна функция для определения типа выставленного ордера. 6. Определение типа ордера конкретной существующей позиции //+------------------------------------------------------------------+ //| СУЩЕСТВУЮЩАЯ ОТКРЫТАЯ ПОЗИЦИЯ | //+------------------------------------------------------------------+ int ExistOP(string symbol, int magic) { int NumPos = -1; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos = OrderType(); } } return(NumPos); } //+------------------------------------------------------------------+ Данная функция возвращает целое значение типа ордера для указанного символа и заданного магического числа, которые действуют в настоящий момент. Если установленный ордер по GBPJPY является OP_BUY, возвращаемое значение будет "0". Данная функция не только работает вместе с торговой функцией. Она также работает с функцией, показывающей текущий статус хеджирования. This function is called "OP2Str". 7. Показать состояние торговли //+------------------------------------------------------------------+ //| Преобразовать значение OP в строку | //+------------------------------------------------------------------+ string OP2Str(int op) { switch(op) { case OP_BUY : return("BUY"); case OP_SELL: return("SELL"); default : return("~~"); } } //+------------------------------------------------------------------+ Думаю, особых объяснений не требуется - в коде видно, как это работает. 8. Закрыть все ордера определённого типа Ещё одна функция для прямого закрытия отдельного ордера в случае ошибки при отправке или закрытии хеджа. //+------------------------------------------------------------------+ //| ЗАКРЫТЬ ВСЕ ОРДЕРА ОПРЕДЕЛЁННОГО ТИПА (CLOSE SCRAP) | //+------------------------------------------------------------------+ bool CloseScrap(string sym, int op, int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && amp; OrderMagicNumber() == magic && OrderSymbol() == sym && OrderType() == op) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) BResult = true; } } if(BResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("CloseScrap Error: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } то есть функция CloseScrap("GBPJPY",OP_BUY,318) закроет только установленные длинные позиции по "GBPJPY" с магическим числом 318. Всё просто. Осталось познакомиться с ещё одной функцией. 9. Показать желаемый логический (Boolean) статус //+------------------------------------------------------------------+ //| Преобразовать bool в string | //+------------------------------------------------------------------+ string bool2str( bool boolval) { if(boolval == true) return("Yes"); if(boolval == false) return("No"); } //+------------------------------------------------------------------+ Ничего особенного, эта функция просто показывает логический
статус некоторых параметров, например, значение BlockOpening. Если
установить её на true, эта функция вернёт "Yes". Соответственно,
будучи установленной на false, она вернёт "No". Вот и всё о функциях, которые нам понадобятся. А теперь отдадим должное написанию кода процесса хеджирования.
//+------------------------------------------------------------------+ //| функция start эксперта | //+------------------------------------------------------------------+ int start() { Потом зададим диапазон корреляции. if(Cor(BaseSymbol, H_Symbol) > Between || Cor(BaseSymbol, H_Symbol) < And) // Снятие блока, когда корреляция выходит за пределы // предполагаемого диапазона. BlockOpen = true; else BlockOpen = false; Затем определим направление хеджирования (это только пример). В данной статье я выбрала стиль торговли по значению свопа, а затем я буду торговать только путём накапливания свопов. // если они движутся в одном направлении, мы откроем длинную и короткую позиции if(MoveSameWay) { if(((BSwapL*BaseLotSize) + (HSwapS*H_LotSize)) > 0) { BOP = OP_BUY; HOP = OP_SELL; } else if(((BSwapS*BaseLotSize) + (HSwapL*H_LotSize)) > 0) { BOP = OP_SELL; HOP = OP_BUY; } } // конец MoveSameWay // если они движутся в разных направлениях, мы откроем две коротких или две длинных позиции else { if(((BSwapL*BaseLotSize) + (HSwapL*H_LotSize)) > 0) { BOP = OP_BUY; HOP = OP_BUY; } else if(((BSwapS*BaseLotSize) + (HSwapS*H_LotSize)) > 0) { BOP = OP_SELL; HOP = OP_SELL; } } Теперь установим хедж: // если они входят в диапазон корреляции и // вы их не блокируете if(!BlockOpen && !BlockOpening) { if(BOP == OP_BUY) // определим цену открытия BaseOpen = MarketInfo(BaseSymbol, MODE_ASK); else BaseOpen = MarketInfo(BaseSymbol, MODE_BID); if(HOP == OP_BUY) HOpen = MarketInfo(H_Symbol, MODE_ASK); else HOpen = MarketInfo(H_Symbol, MODE_BID); // В случае отсутствия свопа для накопления // из BOP и HOP будет -1. if(BOP >= 0 && HOP >= 0) { if(ExistPositions(BaseSymbol, MagicNo) == 0 && ExistPositions(H_Symbol, MagicNo) == 0) { SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, BSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); SendH(H_Symbol, HOP, H_LotsSize, HOpen, HSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); } else // в случае неудачного пинга или реквотирования { if(ExistPositions(BaseSymbol, MagicNo) == 1&& TotalCurProfit(MagicNo)>AcceptableLoss$) { CloseScrap(BaseSymbol, ExistOP(BaseSymbol, MagicNo), MagicNo); } else if(ExistPositions(H_Symbol, MagicNo) == 1&& TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(H_Symbol, ExistOP(H_Symbol, MagicNo), MagicNo); } } } else // если BOP или HOP меньше 0 { string swaptxt = "Отсутствует своп для накопления:" + "пожалуйста, измените один или несколько входных параметров."; } } Затем закроем их по достижении ожидаемой прибыли: if((TotalCurProfit(MagicNo) > ExpectProfit$) { CloseHedge(MagicNo); } Теперь рассмотрим нечто более интересное - ShowStatus. if(ShowStatus) { Comment("\nCorrel: " + DoubleToStr(Cor(BaseSymbol , H_Symbol), 2) , "\nBlockOpen : " + bool2str(BlockOpen || BlockOpening) , "\n" + swaptxt , "\n~~~~~~~" , "\nB/H [sp] : " + BaseSymbol + " [" + BSP + "]" + " / " + H_Symbol+" ["+HSP+"]" , "\nCurOp [Lots]: " + OP2Str(ExistOP(BaseSymbol, MagicNo)) + " [" + DoubleToStr(BaseLotSize, 2) + "]" + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) + " [" + DoubleToStr(H_LotsRatio*BaseLotSize, 2) + "]" , "\nCurPF [Expect]: $" + DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$"+DoubleToStr(ExpectProfit$, 2) + "]"); } else Comment(""); Завершим стандартным для каждого эксперта блоком: return(0); }
Шаг 6: Собираем весь код
Ниже вы можете видеть, как выглядит myHedge.mq4. //+------------------------------------------------------------------+ //| MyHedge.mq4 | //| myHedge | //| http://dailyh.blogspot.com/ | //+------------------------------------------------------------------+ #property copyright "myHedge" #property link "http://dailyh.blogspot.com/" //---- #include <stdlib.mqh> // это - для блокировки функции отправки ордера, но не для блокировки // функции закрытия. extern bool BlockOpening = false; extern string BaseSymbol = "EURJPY"; // первый символ extern string H_Symbol = "GBPJPY"; // второй символ extern bool MoveSameWay = true; // движутся они в одном направлении или нет extern int CorPeriod = 5; // желаемый период корреляции extern double BaseLotSize = 1.5; // размер лота первого символа extern double H_LotSize = 1.0; // размер лота второго символа extern double ExpectProfit$ = 137; // ожидаемая прибыль в долларах США // приемлемый проигрыш в долларах США на случай возникновения ошибки extern double AcceptableLoss$ = -77; extern string ExpectCor = "______"; // ожидаемая корреляция, для // хеджа это наибольший ожидаемый коэффициент корреляции, который должен быть // tбольше, чем "And" extern double Between = 1.05; extern double And = 0.9; // это - наименьший ожидаемый коэффициент корреляции extern string MISC = "______"; // кое-что ещё extern int MagicNo = 318; // желаемое магическое число extern bool ShowStatus = true; // показать существующее состояние хеджирования // проиграть звук, когда функции SendH и CloseH выполнены extern bool PlayAudio = false; //---- int BSP // спред базового символа ,HSP // спред хеджирующего символа ,gsp ,BOP = -1 // тип ордера базового символа ,HOP = -1 // тип ордера хеджирующего символа ,up = 0 ,Hcnt = 0 ,u = 0 ,d = 0 ,day = 0 ,sent = 0 ,firstopen ,expire; double Lot ,BaseOpen // цена открытия ордера базового символа ,HOpen // цена открытия ордера хеджирующего символа ,BPt // значение пункта базового символа ,HPt // значение пункта хеджирующего символа ,BSwapL // значение свопа длинной позиции по базовому символу ,BSwapS // значение свопа короткой позиции по базовому символу ,HSwapL // значение свопа длинной позиции по хеджирующему символу ,HSwapS; // значение свопа короткой позиции по хеджирующему символу bool SResult = false, BResult = false, H1.profitswap, H2.profitswap, H3.profitswap; bool SwapMode = true, allmeetcor = false, BlockOpen = false, buy, sell, cleared = false; string H1.string = "", H2.string = "", H3.string = "", OrdComment = "", candletxt,tdstxt = ""; //+------------------------------------------------------------------+ //| функция инициализации эксперта | //+------------------------------------------------------------------+ int init() { BSP = MarketInfo(BaseSymbol, MODE_SPREAD); HSP = MarketInfo(H_Symbol, MODE_SPREAD); //---- BPt = MarketInfo(BaseSymbol, MODE_POINT); HPt = MarketInfo(H_Symbol, MODE_POINT); //---- BSwapL = MarketInfo(BaseSymbol, MODE_SWAPLONG); BSwapS = MarketInfo(BaseSymbol, MODE_SWAPSHORT); //---- HSwapL = MarketInfo(H_Symbol, MODE_SWAPLONG); HSwapS = MarketInfo(H_Symbol, MODE_SWAPSHORT); //---- return(0); } //+------------------------------------------------------------------+ //| функция start эксперта | //+------------------------------------------------------------------+ int start() { if(Cor(BaseSymbol, H_Symbol) > Between || Cor(BaseSymbol, H_Symbol) < And) // Блокировать, если корреляция выходит за пределы ожидаемого диапазона. BlockOpen = true; else BlockOpen = false; //---- if(MoveSameWay) { if((BSwapL*BaseLotSize) + (HSwapS*H_LotSize) > 0) { BOP = OP_BUY; HOP = OP_SELL; } else if((BSwapS*BaseLotSize) + (HSwapL*H_LotSize) > 0) { BOP = OP_SELL; HOP = OP_BUY; } } else { if((BSwapL*BaseLotSize) + (HSwapL*H_LotSize) > 0) { BOP = OP_BUY; HOP = OP_BUY; } else if((BSwapS*BaseLotSize) + (HSwapS*H_LotSize) > 0) { BOP = OP_SELL; HOP = OP_SELL; } } if(!BlockOpen && !BlockOpening) { if(BOP == OP_BUY) BaseOpen = MarketInfo(BaseSymbol, MODE_ASK); else BaseOpen = MarketInfo(BaseSymbol, MODE_BID); if(HOP == OP_BUY) HOpen = MarketInfo(H_Symbol, MODE_ASK); else HOpen = MarketInfo(H_Symbol, MODE_BID); // В случае отсутствия свопа, который мы могли бы накапливать. if(BOP >= 0 && HOP >= 0) { if(ExistPositions(BaseSymbol, MagicNo) == 0 && ExistPositions(H_Symbol,MagicNo) == 0) { SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, BSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); SendH(H_Symbol, HOP, H_LotSize, HOpen, HSP, "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo); } else // в случае неудачного пинга или реквотирования { if(ExistPositions(BaseSymbol, MagicNo) == 1 && TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(BaseSymbol, ExistOP(BaseSymbol, MagicNo), MagicNo); } else if(ExistPositions(H_Symbol, MagicNo) == 1 && TotalCurProfit(MagicNo) > AcceptableLoss$) { CloseScrap(H_Symbol, ExistOP(H_Symbol, MagicNo), MagicNo); } } } else { string swaptxt = "Отсутствует своп для накопления: пожалуйста," + "измените один или несколько параметров."; } } if(TotalCurProfit(MagicNo) > ExpectProfit$) { CloseHedge(MagicNo); } if(ShowStatus) { Comment("\nКорреляция: "+DoubleToStr(Cor(BaseSymbol, H_Symbol), 2) , "\nBlockOpen : " + bool2str(BlockOpen || BlockOpening) , "\n" + swaptxt , "\n~~~~~~~" , "\nB/H [sp] : " + BaseSymbol + " [" + BSP + "]" + " / " + H_Symbol + " [" + HSP + "]" , "\nCurOp [лоты]: " + OP2Str(ExistOP(BaseSymbol, MagicNo)) + " [" + DoubleToStr(BaseLotSize, 2) + "]" + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) + " [" + DoubleToStr(H_LotSize, 2) + "]" , "\nCurPF [Расчётный]: $" + DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$" + DoubleToStr(ExpectProfit$, 2) + "]"); } else Comment(""); return(0); } //+------------------------------------------------------------------+ //| КОРРЕЛЯЦИЯ | //+------------------------------------------------------------------+ double symboldif(string symbol, int shift) { return(iClose(symbol, 1440, shift) - iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, PRICE_CLOSE, shift)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double powdif(double val) { return(MathPow(val, 2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double u(double val1, double val2) { return((val1*val2)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double Cor(string base, string hedge) { double u1 = 0, l1 = 0, s1 = 0; for(int i = CorPeriod - 1; i >= 0; i--) { u1 += u(symboldif(base, i), symboldif(hedge, i)); l1 += powdif(symboldif(base, i)); s1 += powdif(symboldif(hedge, i)); } if(l1*s1 > 0) return(u1 / MathSqrt(l1*s1)); } //+------------------------------------------------------------------+ //| УСТАНОВИТЬ ХЕДЖ | //+------------------------------------------------------------------+ bool SendH(string symbol, int op, double lots, double price, int sp, string comment, int magic) { if(OrderSend(symbol ,op ,lots ,price ,sp ,0 ,0 ,comment ,magic ,0 ,CLR_NONE) >0) { return(true); if(PlayAudio) PlaySound("expert.wav"); } else { Print(symbol, ": ", magic, " : " ,ErrorDescription(GetLastError())); return(false); } } //+------------------------------------------------------------------+ //| ЗАВЕРШИТЬ ХЕДЖ | //+------------------------------------------------------------------+ bool CloseHedge(int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) SResult = true; } } if(SResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("Ошибка CloseHedge: ", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+ //| ОБЩАЯ ПРИБЫЛЬ | //+------------------------------------------------------------------+ double TotalCurProfit(int magic) { double MyCurrentProfit = 0; for(int cnt = 0; cnt < OrdersTotal(); cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderMagicNumber() == magic) { MyCurrentProfit += (OrderProfit() + OrderSwap()); } } return(MyCurrentProfit); } //+------------------------------------------------------------------+ //| СУЩЕСТВУЮЩАЯ ПОЗИЦИЯ | //+------------------------------------------------------------------+ int ExistPositions(string symbol,int magic) { int NumPos = 0; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos++; } } return(NumPos); } //+------------------------------------------------------------------+ //| СУЩЕСТВУЮЩИЕ ОТКРЫТЫЕ ПОЗИЦИИ (OP) | //+------------------------------------------------------------------+ int ExistOP(string symbol,int magic) { int NumPos = -1; for(int i = 0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == symbol && OrderMagicNumber() == magic) { NumPos = OrderType(); } } return(NumPos); } //+------------------------------------------------------------------+ //| Преобразовать значение OP в строковые данные | //+------------------------------------------------------------------+ string OP2Str(int op) { switch(op) { case OP_BUY : return("BUY"); case OP_SELL: return("SELL"); default : return("~~"); } } //+------------------------------------------------------------------+ //| ЗАКРЫТЬ ВСЕ ОРДЕРА ОПРЕДЕЛЁННОГО ТИПА | //+------------------------------------------------------------------+ bool CloseScrap(string sym,int op,int magic) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderMagicNumber() == magic && OrderSymbol() == sym && OrderType() == op) { if(OrderClose(OrderTicket() , OrderLots() , OrderClosePrice() , MarketInfo(OrderSymbol(), MODE_SPREAD) , CLR_NONE)) BResult = true; } } if(SResult || BResult) { return(true); if(PlayAudio) { PlaySound("ok.wav"); } } else Print("Ошибка CloseScrap:", ErrorDescription(GetLastError())); RefreshRates(); // return(0); } //+------------------------------------------------------------------+ //| Преобразовать bool в string | //+------------------------------------------------------------------+ string bool2str(bool boolval) { if(boolval == true) return("Yes"); if(boolval == false) return("No"); } //+------------------------------------------------------------------+ ЗаключениеВ статье описан пример простого хеджирующего эксперта. Чтобы
он соответствовал вашему стилю торговли, вы можете модифицировать
его. Уверена, что каждый хеджирует по своему методу. И, пожалуйста,
обратите внимание на то, что советник такого типа нельзя протестировать в Тестере Стратегий,
поскольку у него есть собственные ограничения. Вам придётся
его тестировать только "вживую". Ниже приводится примерный
резхультат торговли при помощи хеджирующего советника.
А функция ShowStatus будет выглядеть следующим образом:
Надеюсь, вам понравилась моя статья и что она оказалась полезной
при создании вашего собственного хеджирующего эксперта. Перевод с английского языка выполнен MetaQuotes Software Corp. Текст оригинала: http://articles.mql4.com/ru/388
Предупреждение:
все права на данные материалы
принадлежат MetaQuotes Software Corp. Полная или частичная перепечатка запрещена.
Если кто знает, подскажите где взять исходник корреляционного
индикатора ?
С уважением - С.Д.
17.07.2007 18:05 Sart
else // in case ping failed or requote { if(ExistPositions(BaseSymbol, MagicNo) == 1&& TotalCurProfit(MagicNo)>AcceptableLoss$) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! { CloseScrap(BaseSymbol, ExistOP(BaseSymbol, MagicNo), MagicNo); } else if(ExistPositions(H_Symbol, MagicNo) == 1&& TotalCurProfit(MagicNo) > AcceptableLoss$) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! { CloseScrap(H_Symbol, ExistOP(H_Symbol, MagicNo), MagicNo); } } Orders would be opened and immediatly closed. Best Regards - S.D.
16.07.2007 13:45 Sart
Интересная ошибка в коде - сравниваются два отрицательных числа
- текущая прибыль и допустимый убыток и в случае, когда текущая
прибыль превышает допустимые убытки, позиция закрывается. Все
было бы правильно, если бы числа были положительные. Это место
в районе примечания - "в случае неудачного пинга или реквотирования"
С уважением - С.Д.
16.07.2007 11:54 Sart
Странное место в функции закрытия хэджа:
OrderClose( OrderTicket() , OrderLots() , OrderClosePrice() --- Вот здесь, т.е. , предполагается, что цена закрытия по умолчанию хранится в OrderClose() либо Bid либо Ask, какая нужна та и хранится ? , MarketInfo(OredrSymbol(), MODE_SREAD) , CLR_NONE) И еще по мелочам, например, встречается такое : { return; if (Audy) PlaySound(. ...); } С уважением - С.Д.
14.07.2007 14:36 Sart
6 комментариев
|