مــبـــانــی کـدنـویـســی اکسپرت هِــــج

مــبـــانــی کـدنـویـســی اکسپرت هِــــج

مقدمه

قصد دارم در این مقاله‌، اکسپرت هج را معرفی کنم که ایده‌‌ای بسیار ساده‌ای هم دارد. اما ابتدا یادداشتی مهم درباره‌ی مبانی اکسپرت هج را با هم بخوانیم:

  • هج (برگرفته از ویکی‌پدیا، دانشنامه‌ی آزاد)

برگرفته از مدخل  (Hedging)

در امور مالی، “هج”، یک نوع خاصی از سرمایه‌گذاری است که به‌طور ویژه برای کاهش یا از بین بردن ریسک، در یک سرمایه‌گذاری دیگر، استفاده می‌شود. هجینگ (hedging)، یک استراتژی برای به‌حداقل‌رساندنِ ضرر در کسب‌وکار است، و در همان حال اجازه می‌دهد، آن کسب‌وکار برای‌ ما سود هم داشته باشد. عموماً، کسی که این کار را انجام می‌دهد، یا به‌عبارتی، فرد هجر (hedger)، روی اوراقِ بهاداری سرمایه‌گذاری می‌کند که باور دارد نسبت به “اَرزش واقعی‌شان” زیر قیمت آمده‌اند

(برای مثال، وام مسکنی که او گرفته)، و وی این [موضوع] را با فروش موقت[۲] اوراق بهادار مرتبط، ترکیب می‌کند. بنابراین، در اینجا فرد اهمیتی نمی‌دهد که اَرزش مجموعه‌ی بازار بالا می‌رود یا پایین می‌آید. هولبروک ورکینگ (Holbrook Working)، که یکی از پیشگامان تئوری هجینگ است، این استراتژی را استراتژی “احتکار در پایه” (Speculation in the basis) می‌نامد – جاییکه این پایه، اختلافِ بین اَرزش تئوری هج، و اَرزش واقعی آن (یا بین قیمت‌های واقعی، و قیمت‌های آینده در زمان هولبروک ورکینگ) به‌حساب می‌آید.

در هر نوع فعالیت کاری، طبیعتاً ریسک‌هایی داریم. و برخی از این ریسک‌ها برای مشاغل یا فعالیت‌هایی خاص، “عادی” محسوب می‌شوند؛ مثلاً بالا رفتن یا پایین آمدن قیمت نفت در شرکت‌های استخراج و پخش فرآورده‌های نفتی، اَمری طبیعی حساب می‌شود. اما برخی دیگر از ریسک‌ها، طبیعی نیستند و اصلاً مشتاق آنها هم نیستیم، ولی بدون پوشش و حمایت، نمی‌توان از آنها جلوگیری کرد. کسی که فروشگاه دارد، می‌تواند از ریسک‌هایی مانند رقابت، محصولات ضعیف یا مشتری‌ناپسند، خود را محفوظ نگه دارد. اما در آتش سوختنِ اجناس، طبیعتاً ناخواسته است ولی می‌شود با بیمه‌ی آتش‌سوزی این ریسک را “پوشاند” [در اصلِ مقاله، برای لغت “پوشاند” معادل hedge آورده شده‌است، که در معنی کلی، یعنی پوشاندن و حفظ کردن با پوشش، تا به‌نوعی به بحث هجینگ در مقاله ربط پیدا کند].

تمام هج‌ها [یعنی تمام پوشش دادن‌ها] اَبزارهای مالی نیستند: برای مثال، تولیدکننده‌ای که به کشور دیگری صادرات می‌کند، با پول کشور مقصد هزینه‌های خود را انجام می‌دهد و کالا می‌فروشد تا اینگونه از ریسک به‌وجودآمده به‌خاطر اختلاف پول دو کشور، جلوگیری کند و آن را پوشش دهد (=هج کند).
بیشتر در این مورد بخوانید.

  • تمام چیزهایی که از سِرور نیاز داریم را باید با تابع MarketInfo (string symbol, int type) فراخوانی کنیم. این تابع به ما اجازه می‌دهد هر داده‌ای را وَرای داده‌هایی که روی نمودارِ فعال، دیده می‌شوند، فراخوانی کنیم. و همچنین اجازه خواهیم داشت هر نوع معامله‌ای در هر اَرزی را، فراتر از نمودار اَرزی که جلوی ماست، انجام دهیم. و می‌توانیم دو اَرز را به‌سادگی هج کنیم. جا دارد از خداوند بزرگ به‌خاطر دانشی که به ما بخشیده، و تیم متاتریدر ۴ تشکر کنیم که کار را برای ما بسیار ساده کرده‌اند!
  • یک موضوع مهم در هجینگ، همبستگی‌ بین دو اَرزِ درحال رصد است که می‌توان توابع کوچکی را از آنها استخراج کرد و در ادامه آنها را نشان خواهیم داد.

همبستگی (Correlation)، در دنیای مالی، اندا‌زه‌گیری آماری در ارتباطِ بین دو سند بهادار، به‌حساب می‌آید. ضریب همبستگی بین ۱- و ۱+ متغییر است. همبستگی ۱+ یعنی دو جفت‌اَرز ۱۰۰ درصد در یک جهت، در یک زمان، حرکت خواهند کرد. و ۱- نیز می‌گوید دو جفت‌اَرز ۱۰۰ درصد در جهت مخالف خواهند رفت. این عدد اگر صفر باشد، رابطه‌ی بین این دو جفت‌اَرز کاملاً رَندوم خواهد بود. بیشتر بخوانید.

مطالب بالا چیزهای ساده‌ای هستند، و فارکس هجرهایی که از اکسپرت متاتریدر ۴ استفاده می‌کنند، باید این مطالب را بدانند. اکنون می‌توانیم ساختن یک اکسپرت هج را شروع کنیم.

قدم به قدم با کدنویسی اکسپرت هج

مرحله اول: پارامترهای ورودی

قبل از شروع نوشتن اکسپرت هج، نیاز داریم که ۲ اَرز دارای همبستگی را انتخاب کنیم؛ به‌عبارت دیگر:

  • GBPUSD  وEURUSD  که همیشه در یک جهت حرکت می‌کنند؛
  • EURUSD  و USDCHF که همیشه در جهت مخالف می‌کنند؛
  • و غیره.

در این مقاله، دو جفت‌اَرز هج مورد علاقه‌ی خودم را انتخاب می‌کنم کهEURJPY  و GBPJPY هستند. این دو همیشه در یک جهت حرکت می‌کنند و برای ثبت معامله‌ی هج، کار ساده‌تری خواهیم داشت. بیایید شروع کنیم. برای شروع کار بیایید با این متغیرهای ورودی آشنا شویم.

// this is to block the order sending function but 
// not to block the close function.
extern bool BlockOpening = false; 
 
extern string BaseSymbol = "EURJPY";//the 1st symbol 
 
extern string H_Symbol = "GBPJPY";//the 2nd symbol 
 
extern bool MoveSameWay = true;//they move the same way or not 
 
extern int CorPeriod = 5;//your favorite correlation period 
 
extern double BaseLotSize = 1.5;//1st symbol lotsize 
 
extern double H_LotsSize = 1.0;//2nd symbol lotsize 
 
extern double ExpectProfit$ = 137;//your expect profit in USD 
//your acceptable loss in USD in case any error occurred 
extern double AcceptableLoss$ = -77; 
 
extern string ExpectCor = "______";//your expect correlation to hedge 
//this is the upper expect cor value and has to be greater than "And" 
extern double Between = 1.05; 
 
extern double And = 0.9;//this is the lower expect cor level 
 
extern string MISC = "______";//some thing more 
 
extern int MagicNo = 318;//your favorite magic number 
 
extern bool ShowStatus = true;//to show the present hedging status 
//to play sound when SendH and CloseH function done 
extern bool PlayAudio = false;

مرحله‌ دوم: اعلام متغیر

در زیر، متغیرهایی را می‌بینید که در این اکسپرت استفاده شده، و من فقط متغیری را توضیح می‌دهم که برای درک عملکرد اکسپرت ضروری است.

int BSP       // the spread of base symbol 
 
    , HSP      // the spread of hedge symbol 
 
    , gsp 
 
    , BOP = -1 // base symbol order type 
 
    , HOP = -1 // hedge symbol order type 
 
    , up = 0 
 
    , Hcnt = 0 
 
    , u = 0 
 
    , d = 0 
 
    , day = 0 
 
    , sent=0 
 
    , firstopen 
 
    , expire; 
 
double Lot 
 
       , BaseOpen // base symbol order open price 
 
       , HOpen    // hedge symbol order open price 
 
       , BPt      // base symbol Point value 
 
       , HPt      // hedge symbol Point value 
 
       , BSwapL   // base symbol swap long value 
 
       , BSwapS   // base symbol swap short value 
 
       , HSwapL   // hedge symbol swap long value 
 
       , HSwapS;  // hedge symbol swap short value 
 
 
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 = "";

 

مرحله‌ سوم: دریافت تمام پارامترهای آماری مورد نیاز

اکنون بیایید بعضی از مقادیر (values) آماری‌ که در قسمت init() ثبت می‌شوند را مشخص کنیم.

//+------------------------------------------------------------------+ 
//| expert initialization function                                   | 
//+------------------------------------------------------------------+ 
 
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()”، را اِستارت بزنیم، بیایید با توابعی شروع کنیم که در این اکسپرت از آنها استفاده شده‌است. اما لطفاً توجه داشته باشید که تمامی این توابع خارج از تابع start() خواهند بود.

  1. تابع همبستگی

ابتدا نیاز داریم با توابعِ محاسباتیِ همبستگی آغاز کنیم. توابع زیر برای فردی است که ابتدا از آنها استفاده کرده و سپس اندیکاتور همبستگی  (igorad2004@list.ru)را رایگان در اختیار عموم گذاشته و من نیز آنها را برای استفاده در این اکسپرت، ساده‌سازی کرده‌ام، و اینگونه دیگر نیازی به فراخوانی مقدار همبستگی از اندیکاتور خارجی نداریم. ایده‌ی خوبیست، نه؟

//+------------------------------------------------------------------+ 
//|  CORRELATION                                                     |
//+------------------------------------------------------------------+ 
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)); 
  }
//+------------------------------------------------------------------+
//|  The real correlation function to call is here.                  |
//+------------------------------------------------------------------+
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). کار ساده‌ایست…

  1. تابع ارسال هج (Send Hedge Function)

به‌نظرم ساده‌تر این است که چگونگی ارسال معاملات هج را با ساختن تابعSendH ، مدیریت کنیم.

//+------------------------------------------------------------------+
//| SEND HEDGE                                                       |
//+------------------------------------------------------------------+
bool SendH(string symbol, int op, double lots,
           double price, int sp, string comment, int magic) 
  { 
    if(OrderSend(symbol 
                 , op 
                 , lots 
                 , price 
                 , sp 
                 , ۰ 
                 , ۰ 
                 , comment 
                 , magic 
                 , ۰ 
                 , 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() را، همانطور که در بالا نشان داده شد، فرا بخوانید.

  1. تابع بستن هج

فراتر از ارسال معاملات، نیاز به تابعی داریم که تمام معاملات هج را وقتی به سود مورد نظر ما رسیدند، ببندد.

و در اینجا آن را مشاهده می‌کنید:

//+------------------------------------------------------------------+
//|  CLOSE HEDGE                                                     |
//+------------------------------------------------------------------+
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); 
  } 
//+------------------------------------------------------------------+

 

این تابع فقط معاملاتی را می‌بندد که عدد جادویی مشابه دارند؛ به این معنی که در کار معاملات هجی که دیگر اعداد جادویی را دارند، دخالت نمی‌کند. چیزی نیست که نگران آن باشید. قبل از استفاده از این تابع [برای] بستن معاملات، باید تعریف کنیم که “اکنون چقدر داریم”، آن‌هم با تابع زیر.

  1. تابع یافتن سود کلی
//+------------------------------------------------------------------+
//|  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);

تمام مقادیر سود به دلار آمریکا محاسبه شده‌اند. از خط بالا درمی‌یابیم که وقتی سود کلی معاملاتی که عدد جادویی آنها ۳۱۸ است، بیش از ۱۰۰ دلار باشد، آن معاملات بسته خواهند شد. همین. برای باز کردن معاملات هج باید بدانیم که هیچ معامله‌ی دیگری در همان اَرز و با همان عدد جادویی، در حال حاضر باز، وجود ندارد. این کار را می‌توان با این تابع انجام داد.

  1. دریافت حجم پوزیشن‌های موجود
//+------------------------------------------------------------------+
//| 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 با عدد جادویی ۳۱۸ وجود دارد”. یک تابع دیگر هم داریم برای تعریف نوع معاملات باز.

  1. پیدا کردن نوع معامله در پوزیشن مشخص‌شده‌ی موجود
//+------------------------------------------------------------------+  
//| EXISTING OP POSITION                                             |
//+------------------------------------------------------------------+
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 باشد، مقدار برگشتی صفر خواهد بود. این تابع فقط با تابع ترید کار نمی‌کند، بلکه با تابعی که وضعیت هجینگ کنونی را نشان می‌دهد هم کار می‌کند. این تابع را “OP2Str” می‌نامند.

  1. نشان دادن وضعیت ترید
//+------------------------------------------------------------------+
//| Transform OP Value To string                                     |
//+------------------------------------------------------------------+ 
string OP2Str(int op) 
  { 
    switch(op) 
      { 
        case OP_BUY : return("BUY"); 
        case OP_SELL: return("SELL"); 
        default : return("~~"); 
      } 
  }
//+------------------------------------------------------------------+

 

چیز خاصی برای گفتن نداریم. خود تابع گویای نحوه‌‌ی عملکرد خود است.

  1. بستن تمام انواع معاملات مشخص‌شده

این هم یک تابع دیگر است برای بستن مستقیم فقط یک معامله (فرقی نمی‌کند چه نوع معامله‌ای باشد)، درصورتیکه هنگام ارسال یا بستن هج، خطایی رخ دهد.

//+------------------------------------------------------------------+
//| 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 با عدد جادویی ۳۱۸ را می‌بندد. ساده است… یک تابع دیگر هم برای آشنایی با آن داریم.

  1. نشان دادن هر وضعیت منطقی‌ای[۳] که شما می‌خواهید
//+------------------------------------------------------------------+
//| Translate bool to string                                         |
//+------------------------------------------------------------------+
string bool2str( bool boolval) 
  { 
    if(boolval == true) 
        return("Yes"); 
    if(boolval == false)
        return("No"); 
  }
//+------------------------------------------------------------------+

چیز پیچیده‌ای نیست. این تابع وضعیت منطقی بعضی از پارامترها، مانند مقدار BlockOpening را نشان می‌دهد. وقتی آن را true تعیین می‌کنید، این تابع روی صفحه‌ی نمایش Yes را به شما نشان می‌دهد. و وقتی آن را false تعیین ‌می‌کنید، روی صفحه‌ی نمایش No نشان داده می‌شود. تمام مطلب همین است. پس بیایید از فرآیند کدنویسی هج لذت ببریم.

مرحله پنجم: هسته‌ی اکسپرت

ابتدا با این شروع کنید:

//+------------------------------------------------------------------+ 
//| expert start function                                            | 
//+------------------------------------------------------------------+ 
int start() 
  {

سپس دامنه‌ی همبستگی را مشخص کنید.

if(Cor(BaseSymbol, H_Symbol) > Between || 
   Cor(BaseSymbol, H_Symbol) < And) 
// Block opening when the correlation is out of 
// expected range. 
    BlockOpen = true; 
else 
    BlockOpen = false;

 

پس از آن مسیر هج را مشخص کنید (این فقط یک مثال است)، در این مقاله من سبک ترید خود را با مقدار سوآپ انتخاب می‌کنم، سپس فقط به روشی که بتوانم از سوآپ هر روز درآمد داشته باشم، ترید خواهم کرد.

// if they move the same way we will open long & short 
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; 
          } 
  } // end MoveSameWay
// if the move the opposite way we will open short & short or long & long
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 they meet the correlation range and 
// you're not blocking them
if(!BlockOpen && !BlockOpening)  
  { 
    if(BOP == OP_BUY) 
    // define the opening price    
        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); 
    // In case there is no any swap condition to gain 
    // from BOP & HOP will be -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 // 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); 
                  } 
          } 
 
      }
    else // if one of BOP and HOP is less than 0
      {
        string swaptxt = "No Swap Condition To Gain From :" + 
                   "pls modify one or more input parameter(s).";
      }
  }

 

سپس آنها را وقتی که به سود مورد نظر می‌رسند، ببندید.

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);
}

مرحله ششم: سَرِهم‌کردن همه‌چیز

در اینجا می‌بینید که myHedge.mq4 من این شکلی خواهد بود:

//+------------------------------------------------------------------+
//|                                                      MyHedge.mq4 |
//|                                                          myHedge |
//|                                      http://dailyh.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "myHedge"
#property link "http://dailyh.blogspot.com/"
//----
#include <stdlib.mqh>
// this is to block the order sending function but not to block the 
// close function.
extern bool BlockOpening = false;
extern string BaseSymbol = "EURJPY"; // the 1st symbol
extern string H_Symbol = "GBPJPY";   // the 2nd symbol
extern bool MoveSameWay = true; // they move the same way or not
extern int CorPeriod = 5; // your favorite correlation period
extern double BaseLotSize = 1.5; // 1st symbol lotsize
extern double H_LotSize = 1.0; // 2nd symbol lotsize
extern double ExpectProfit$ = 137; // your expect profit in USD
// your acceptable loss in USD in case any error occurred
extern double AcceptableLoss$ = -77; 
extern string ExpectCor = "______"; // your expect correlation to 
// hedge this is the upper expect cor value and has to be greater 
// than "And"
extern double Between = 1.05;
extern double And = 0.9; // this is the lower expect cor level
extern string MISC = "______"; // some thing more
extern int MagicNo = 318; // your favorite magic number
extern bool ShowStatus = true; // to show the present hedging status
// to play sound when SendH and CloseH function done
extern bool PlayAudio = false; 
//----
int BSP  // the spread of base symbol
    ,HSP // the spread of hedge symbol
    ,gsp
    ,BOP = -1 // base symbol order type
    ,HOP = -1 // hedge symbol order type
    ,up = 0
    ,Hcnt = 0
    ,u = 0
    ,d = 0
    ,day = 0
    ,sent = 0
    ,firstopen
    ,expire;
double Lot
       ,BaseOpen // base symbol order open price
       ,HOpen // hedge symbol order open price
       ,BPt // base symbol Point value
       ,HPt // hedge symbol Point value
       ,BSwapL // base symbol swap long value
       ,BSwapS // base symbol swap short value
       ,HSwapL // hedge symbol swap long value
       ,HSwapS; // hedge symbol swap short value
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 = "";
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   if(Cor(BaseSymbol, H_Symbol) > Between || 
      Cor(BaseSymbol, H_Symbol) < And)
   // Block opening when the correlation is out of expected range.
       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);
       // In case there is no any swap condition that we can gain from.
       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), 
                     ۲), MagicNo);
               SendH(H_Symbol, HOP, H_LotSize, HOpen, HSP, "COR : " + 
                     DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo);
             }     
           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);
                     }
             }
         }
       else
         {
           string swaptxt = "No Swap Condition To Gain From : pls " + 
                            "modify one or more input parameter(s).";
         }
     }
   if(TotalCurProfit(MagicNo) > ExpectProfit$)
     {
       CloseHedge(MagicNo);
     }
   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_LotSize, 2) + "]"
               , "\nCurPF [Expect]: $" + 
                 DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$" + 
                 DoubleToStr(ExpectProfit$, 2) + "]");
     }
   else 
       Comment("");
   return(0);
  }
//+------------------------------------------------------------------+
//| CORRELATION                                                      |
//+------------------------------------------------------------------+
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));
  }
//+------------------------------------------------------------------+
//| SEND HEDGE                                                       |
//+------------------------------------------------------------------+
bool SendH(string symbol, int op, double lots, double price, int sp, 
           string comment, int magic)
  {
   if(OrderSend(symbol
                ,op
                ,lots
                ,price
                ,sp
                ,۰
                ,۰
                ,comment
                ,magic
                ,۰
                ,CLR_NONE)
                >0)
     {
       return(true);
       if(PlayAudio)
           PlaySound("expert.wav");
     }
   else 
     {
       Print(symbol, ": ", magic, " : "
             ,ErrorDescription(GetLastError()));
       return(false);      
     }      
  }
//+------------------------------------------------------------------+
//| CLOSE HEDGE                                                      |
//+------------------------------------------------------------------+
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);
  }  
//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+
//| EXISTING POSITION                                                |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| EXISTING OP POSITION                                             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Transform OP Value To string                                     |
//+------------------------------------------------------------------+
string OP2Str(int op)
  {
   switch(op)
     {
       case OP_BUY : return("BUY");
       case OP_SELL: return("SELL");
       default     : return("~~");
     }
  }
//+------------------------------------------------------------------+
//| 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) 
          && 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 Error: ", ErrorDescription(GetLastError()));
   RefreshRates();
//  return(0);
  }  
//+------------------------------------------------------------------+
//| Translate bool to string                                         |
//+------------------------------------------------------------------+
string bool2str(bool boolval)
  {
   if(boolval == true) 
       return("Yes");
   if(boolval == false)
       return("No");
  }
//+------------------------------------------------------------------+

نتیجه‌گیری

این فقط یک مثال ساده از اکسپرت هج بود. قطعاً باید آن را منطبق با نیازها و سبک خود، تغییر دهید. مطمئناً سبک‌ها (استراتژی‌های) بسیاری وجود دارند که به شما کمک می‌کنند. توجه داشته باشید که این نوع اکسپرت را به‌خاطر محدودیت‌هایش نمی‌توانید با استراتژی‌تستر، تست کنید. فقط باید آن را در شرایط واقعی امتحان کرد. مثالی از نتیجه‌ی تست یک اکسپرت هج را مشاهده می‌کنید:

مــبـــانــی کـدنـویـســی اکسپرت هِــــج

و تابع ShowStatus هم چنین چیزی را به شما خواهد داد:

مــبـــانــی کـدنـویـســی اکسپرت هِــــج

امیدوارم از این مقاله لذت برده باشید و بتوانید اکسپرت هج خود را، عالی بسازید.

این مقاله دارای فایل پیوست است.

[۱]) هج “hedge” یعنی هم‌پوشانی. اگر روی یک اَرز، با حجم یکسان و در همان تایم‌فریم، دو معامله، یکی buy و یکی  sellهمزمان باز کنیم، آنگاه اصطلاحاً معامله‌ی hedge یا معامله‌ی هم‌پوشانی باز کرده‌ایم.

[۲]) فروش موقت یعنی فروختن چیزی موقتاً، با این قصد که بعداً دوباره آن را با قیمت پایین‌تر بخریم.

[۳]) Boolean (bool) داده‌های بولی یا همان داده‌های منطقی

M23admin

→ خواندن مطلب قبلی

کاربرد عملی سِرور خصوصی مجازی (VPS) برای ترید خودکار

خواندن مطلب بعدی ←

زبان MQL4 برای تازه‌کارها، سوالات سخت با جملات ساده

۲۳ مورد نظر

نوشتن نظر شما

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *