الگویی برای تریلینگ اِستاپ و خروج از بازار

تریلینگ اِستاپ

الگویی برای تریلینگ اِستاپ و خروج از بازار

مقدمه

توسعه‌دهندگانِ الگوریتم‌های اصلاح یا بستن معامله، همواره یک دغدغه‌ی تمام‌نشدنی دارند – چگونه نتایج بدست‌آمده از روش‌های مختلف را با یکدیگر مقایسه کنیم؟ مکانیزم این کار کاملا مشخص است – استراتژی تستر. اما چگونه اکسپرتی بسازیم که برای معاملات بازشونده/بسته‌شونده، به یک نسبت کار کند؟ این مقاله ابزاری را معرفی می‌کند که [این ابزار] شرایط را برای تکرارِ قویِ بازشدن‌های معامله، فرآهم می‌آورد، و این کار به ما اجازه می‌دهد که یک پلتفرم درست ریاضی را حفظ کرده و نتایج الگوریتم‌های مختلف برای تریلینگ اِستاپ‌ها و خروج از بازار را با یکدیگر مقایسه کنیم.

اگر حضرتعالی مشغول اِشکال‌زدایی از یک اکسپرت پیچیده هستید که قرار است مستقل بیاید و زمان ورود به بازار، تریلینگ اِستاپ‌ها، و خروج از بازار را محاسبه کند، پس باید بگوییم عملا داشتن الگویی تکرارپذیر برای مقایسه با دیگر الگوها، غیرممکن است. شرایطی را تصور کنید که در آن یک سیگنال نسبتاً بلند برای بازکردن یک معامله وجود داشته باشد. به‌طور ایده‌آل، معامله باز خواهد شد. سپس، اگر جهت انتخاب‌شده درست باشد و قیمت در جهت پیش‌بینی‌شده حرکت کند، تریلینگ اِستاپ آغاز به کار خواهد کرد. با توجه به نوسانات قیمت، اگر اِستاپ (StopLoss) خیلی نزدیک گذاشته شود، خیلی زود معامله بسته خواهد شد، و در غیراین‌صورت، سود “افزایش” خواهد داشت. اگر سیگنال بازشونده در آن زمان هنوز معتبر باشد، اکسپرت یک معامله‌ی جدید را می‌بندد. در نتیجه، ما باید نتایج یک معامله‌ی “صحیح” را با نتایج چند معامله‌ی دیگر، مقایسه کنیم—[آن‌هم معاملاتی] که بعد از بسته‌شدن‌های زودهنگام، باز شده‌اند. برای جلوگیری از بوجود آمدن چنین شرایطی، این توصیه‌ها را داریم:

بیان مسئله

  • الگوهای نقطه‌ی بازشدن/بسته‌شدن معامله، در نمودار علامت‌گذاری شده‌اند.
  • زمآن‌های بازشدن/بسته‌شدن و جهت ترید (buy/sell) در یک فایل ذخیره شده‌اند.
  • اکسپرتی که قرار است فایل آماده‌شده را بخواند و دستورات آن را مو به مو اجرا کند، ایجاد شده‌است.

نقاطِ باز شدن می‌بایستی روی بازگشت‌های بازار تنظیم شوند – بسیار خوب است که می‌شود آن‌ها را به‌وضوح در بخش تاریخچه دید. هرچند، انتخاب نقاط بسته‌شدن نباید وقتی باشد که قیمت به نقطه‌ی بازگشتی مخالف می‌رسد، بلکه باید بعد از آن باشد. فراموش نکنید که کار ما بهینه‌سازی تریلینگ و خروج از بازار است، بنابراین، باید به هر الگوریتمی اجازه‌ی ورود بدهیم، حتی الگوریتم‌های بی‌ربط، و تا آخرِ کارِ آن الگوریتم را باید ببینیم. اگر الگوریتم قادر به تثبیت سود نبود، ضررهایش را رصد می‌کنیم که خود می‌شود سیگنالی برای ما، تا در الگوریتم بازنگری کنیم.

تریلینگ اِستاپ

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

در معامله‌ی انجام‌شده “در امتداد خط آبی”، سه نقطه‌ی بالقوه برای خوردن اِستاپ‌ها بعد از تریلینگ‌ها، وجود دارد:

  1. تریلینگ پُرجنب‌وجوش در کمترین فاصله از قیمت کنونی.
  2. تریلینگ نُرمال و “صبور”.
  3. تریلینگ ایده‌آل که سودها را تا آخرین قطره از بین می‌برد.

علاوه بر این‌ها، جایی نزدیک نقطه‌ی شماره ۴، ممکن است به اشتباه، تریلینگ بیش از حد “ناصبور”، اتفاق بیُفتد.

اکنون که می‌دانیم چگونه نواحی ایده‌آل را “علامت‌گذاری” کنیم، فقط یک چیز باقی می‌ماند و آن‌هم راحت‌تر کردن کار تا جای ممکن است.

ابزارهای علامت‌گذاری

برای راحت‌تر کردن علامت‌گذاری نمودار با خطوط موردنظر، بیایید دسته‌ای از اسکریپت‌ها را آماده کنیم. دو اسکریپتِ TL_Buy و TL_Sell خطوط علامت‌گذاری را برای Sell و Buy ایجاد می‌کنند. اسکریپتِ TL_Write تمام خطوط ایجادشده را بررسی کرده و ویژگی‌های آن‌ها را درون یک فایل برای اکسپرتِ TL_Trade جهت کار کردن با آن‌ها، ذخیره می‌کند. اسکریپت دیگر یعنی TL_Read قادر خواهد بود فایل ایجادشده را بخواند، و تمام خطوط را برمبنای آن [فایل] اصلاح کند. این کار احتمالاً برای اصلاح خطوط موجود یا برای اضافه کردن خطوط جدید، یا حتی حذف خطوط کنونی، مفید است.

برای اینکه اسکریپت‌های خواندن/نوشتن قادر باشند با خطوط‌شان کار کنند، تمام این خطوط را بر اساس قوانین خاصی نام‌گذاری خواهیم کرد:

  1. اسامی تمام خطوط ایده‌آل، با یک پیشوند آغاز می‌شوند (TL_). بعدها می‌توانید از این پیشوند برای انتخاب یا حذف خطوط استفاده کنید؛
  2. بعد از پیشوند یک حرف می‌آید که کد عملیات است، B برای Buy، و S برای Sell؛
  3. در اسم خط، بعد از کد عملیات، شماره‌ی خط می‌آید تا خطوط از یکدیگر مجزا باشند.

در نتیجه، برای مثال، در نمودار باید خطوطی با این اسامی داشته باشیم: TL_B1 TL_B2, TL_S3 …

اسکریپت ‌هایی که خطوط را می‌سازند به‌سادگی روی نمودار می‌آیند و خط مربوطه در نقطه‌ی موردنظر نمایش داده می‌شود. می‌توانید دو سر خط را طوری جابه‌جا کنید که “خط آبی” ایده‌آلِ موردنیازِ ترید، علامت‌گذاری شود. اسکریپت‌های خواندن/نوشتن، بعد از اجرا روی نمودار، از ما می‌خواهند اسمی برای فایل انتخاب کنیم تا با آن اسم، فایل ذخیره، و خوانده شود. این کار به ما اجازه می‌دهد به‌سادگی از دسته‌های مختلف خطوط—برای مثال برای جفت‌اَرزهای مختلف—استفاده کنیم.

کد این اسکریپت‌ها کاملا واضح گفته شده، و تمام توضیحات موردنیاز نیز ارائه شده‌‌اند، بنابراین این اجازه را به خود می‌دهم که دیگر الگوریتم‌های آن‌ها را توضیح ندهم، چراکه از خود کدها می‌توانید الگوریتم‌ها را متوجه شوید.

/****************************************************************
 PATTERN TRADING: TL_Buy - creation of a new, pattern buying line
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
 
int start()
{
  int MaxNo=0,i,No; 
  
  if(WindowOnDropped()!=0) { MessageBox("Script should be dropped in the main window","ERROR", IDOK + MB_ICONERROR); return(1); }
 
  // find the maximum suffix number for all lines
  for(i=0;i<ObjectsTotal();i++) 
  {
    if(StringFind(ObjectName(i),_prefix_)==0) 
    {
      No=StrToInteger(StringSubstr(ObjectName(i),StringLen(_prefix_)+1)); // select the line number
      if(MaxNo<No) MaxNo=No; // store it, if it is larger
    }
  }
  
  datetime t0=WindowTimeOnDropped(); double p0=WindowPriceOnDropped(); // find the coordinates of the script dropping point
 
  int width = 5*Period()*60;                             // width of the created line in bars converted into time units
  double height = 20*MarketInfo(Symbol(),MODE_TICKSIZE); // height of the created line in ticks converted into price units
  
  string LineName = _prefix_+"B"+(MaxNo+1);  // create a name for a new line
  ObjectCreate(LineName,OBJ_TREND,0,t0-width,p0-height, t0+width,p0+height); // create a line
  ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray
  ObjectSet(LineName,OBJPROP_WIDTH,2);   // set its width
  ObjectSet(LineName,OBJPROP_COLOR,Blue); // set its color
 
}
/****************************************************************
 PATTERN TRADING: TL_Sell - creation of a new, pattern selling line
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
 
int start()
{
  int MaxNo=0,i,No; 
  
  if(WindowOnDropped()!=0) { MessageBox("Script should be dropped in the main window","ERROR", IDOK + MB_ICONERROR); return(1); }
 
  // find the maximum suffix number for all lines
  for(i=0;i<ObjectsTotal();i++) 
  {
    if(StringFind(ObjectName(i),_prefix_)==0) 
    {
      No=StrToInteger(StringSubstr(ObjectName(i),StringLen(_prefix_)+1)); // select the line number
      if(MaxNo<No) MaxNo=No; // store it, if it is larger
    }
  }
  
  datetime t0=WindowTimeOnDropped(); double p0=WindowPriceOnDropped(); // find the coordinates of the script dropping point
 
  int width = 5*Period()*60;                             // width of the created line in bars converted into time units
  double height = 20*MarketInfo(Symbol(),MODE_TICKSIZE); // height of the created line in ticks converted into price units
  
  string LineName = _prefix_+"S"+(MaxNo+1);  // create a name for a new line
  ObjectCreate(LineName,OBJ_TREND,0,t0-width,p0+height, t0+width,p0-height); // create a line
  ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray
  ObjectSet(LineName,OBJPROP_WIDTH,2);   // set its width
  ObjectSet(LineName,OBJPROP_COLOR,Red); // set its color
 
}
/****************************************************************
 PATTERN TRADING: TL_Write - saving the coordinates of pattern lines in a file
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
#property show_inputs
 
extern string FileNameForWrite = "TL_DATA.TXT";
 
int start()
{
  int LinesCNT=0,i; string Operation; double p; datetime t;
  
  int fh=FileOpen(FileNameForWrite,FILE_CSV|FILE_WRITE,';');
 
  // look through all lines created and save the opening commands for the EA from them
  for(i=0;i<ObjectsTotal();i++) 
  {
    if(StringFind(ObjectName(i),_prefix_)==0) // our line
    {
      string LineName = ObjectName(i);  
 
      datetime t1=ObjectGet(LineName,OBJPROP_TIME1);
      datetime t2=ObjectGet(LineName,OBJPROP_TIME2);
 
      double p1=ObjectGet(LineName,OBJPROP_PRICE1);
      double p2=ObjectGet(LineName,OBJPROP_PRICE2);
 
      LinesCNT++; // increase the counter for producing the final message
      
      Operation = StringSubstr(ObjectName(i),StringLen(_prefix_),1); 
      
      // prices are necessary only for restoring the line in the chart
      FileWrite(fh,Operation,TimeToStr(t1),DoubleToStr(p1,Digits),TimeToStr(t2),DoubleToStr(p2,Digits)); 
    }
  }
  
  FileClose(fh);
  
  MessageBox("Stored sections "+(LinesCNT)+" pcs.","Done", IDOK + MB_ICONINFORMATION);
}
/****************************************************************
 PATTERN TRADING: TL_Read - drawing pattern lines from the file
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
#property show_inputs
 
extern string FileNameForRead = "TL_DATA.TXT";
 
int start()
{
  int LinesCNT=0,i; 
  
  int fh=FileOpen(FileNameForRead,FILE_CSV|FILE_READ,';');
  if(fh<0) { MessageBox("Error opening file \"" + FileNameForRead + "\"","ERROR", IDOK + MB_ICONERROR); return(1); }
 
  // first of all, delete everything
  for(i=0;i<ObjectsTotal();i++) { if(StringFind(ObjectName(i),_prefix_)==0) { ObjectDelete(ObjectName(i)); i--; } }
 
  // look through all lines created and save the opening commands for the EA from them
  while(true)
  {
    string Operation=FileReadString(fh);
    
    if(FileIsEnding(fh)) break; // file ended? - exit
    
    // read the section's coordinates
    datetime t1=StrToTime(FileReadString(fh));
    double   p1=StrToDouble(FileReadString(fh));
    datetime t2=StrToTime(FileReadString(fh));
    double   p2=StrToDouble(FileReadString(fh));
 
    // draw a section
    LinesCNT++;
    string LineName = _prefix_+Operation+(LinesCNT);  // create a name for a new line
    ObjectCreate(LineName,OBJ_TREND,0,t1,p1, t2,p2);  // create a line
    ObjectSet(LineName,OBJPROP_RAY,False); // make it a section, not a ray
    ObjectSet(LineName,OBJPROP_WIDTH,2);   // set its width
    if(Operation=="B") ObjectSet(LineName,OBJPROP_COLOR,Blue); else  ObjectSet(LineName,OBJPROP_COLOR,Red);// set its color
 
  }
  FileClose(fh);
  
  MessageBox("Read sections "+(LinesCNT)+" pcs.","Done", IDOK + MB_ICONINFORMATION);
}
/****************************************************************
 PATTERN TRADING: TL_Clear - deletion of all pattern lines
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
 
int start()
{
  int LinesCNT=0,i;
  
  for(i=0;i<ObjectsTotal();i++) 
  {
    if(StringFind(ObjectName(i),_prefix_)==0) { ObjectDelete(ObjectName(i)); i--; LinesCNT++; }
  }
}

تثبیت موقعیت فایل

بحث موقعیت فایل‌ها، بسیار بحث مهمی است. در حالت استاندارد، اسکریپت‌های در حالِ کار، فقط می‌توانند فایل‌ها را در مسیر c:\Program Files\MetaTrader 4\experts\files ایجاد کنند. هرچند، هنگام تست اکسپرت‌ها، تستر، به پوشه‌ی دارای همان نام، واقع “در مسیر خودش”، یعنیc:\Program Files\MetaTrader 4\tester\files، دسترسی دارد.

به همین دلیل است که، بعد از ایجاد فایل‌ها، و قبل از استفاده از آن‌ها در اکسپرت آزمایشی، می‌بایستی به‌صورت جداگانه آن‌ها را از c:\Program Files\MetaTrader 4\experts\files  به c:\Program Files\MetaTrader 4\tester\files کپی کنید.

اگر فایل مجدد ایجاد شود و تغییراتی در خطوط آن اتفاق بیفتد، بایستی این کار را تکرار کرد.

اکسپرت آزمایشی

مشکلی با کد اکسپرت آزمایشی نخواهید داشت، و روی این سه قسمت نیز تاکید شده‌است:

  1. قسمتِ بستن معامله هنگامی که به انتهای بخش الگو می‌رسیم؛
  2. قسمت بازکردن معامله هنگامی که به ابتدای بخش الگو می‌رسیم؛
  3. قسمت آزمایش تریلینگ اِستاپ و خروج از بازار.

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

  1. از آنجایی که خطوط می‌توانند بدون هیچ نظم خاصی ایجاد شوند، تمام مجموعه‌ی خطوط در هر “تیک” تستر آزمایش خواهد شد، و هدف این کار پیدا کردن خطوطی است که روی آن‌ها بازشدن/بسته‌شدن ضروری است.
  2. زمان‌های بازشدن/بسته‌شدن، با همان فرمت داخلی ثبت زمان و تاریخ، در توضیحات معامله نوشته می‌شوند. این کار ضروری است؛ اول از همه، برای خودمان تا اگر تریلینگ یک معامله را بدون اِشکال، قبل از پایان یافتن خط الگویش، بست، آن را مجدد چندین بار، باز نکنیم. و دوم، هنگام بررسی معاملات باز و مشاهده‌ی زمان بسته‌شدن آن‌ها از قسمت توضیحات، معامله را دقیقاً زمانی که خط کنترل آن پایان یافته‌ است، می‌بندیم، زیرا زمان بسته‌شدن در معامله‌ی باز نوشته شده است.
  3. پارامترProcedTrailing  فرآیند تریلینگ را فعال/غیرفعال می‌کند. این کار به ما اجازه می‌دهد اکسپرت را بدون هیچ‌گونه تریلینگ جهت گرفتن خوشبینانه‌ترین نتیجه برای مقایسه‌ی آن با نتایج بهینه‌سازی بدست‌آمده، داشته باشیم.
/****************************************************************
 PATTERN TRADING: TL_Trader - trading on pattern lines
 Copyright © ۲۰۰۶-۲۰۰۸, Sergey Kravchuk. http://forextools.com.ua
*****************************************************************/
 
#include <WinUser32.mqh>
 
#define _prefix_ "TL_"
 
extern string FileNameForRead = "TL_DATA.TXT";
extern double Lots = 0.1;
extern double StopLoss = 0;
extern double TrailingStop = 30;
extern bool   ProcedTrailing=true; // process the trailing block
 
double SL; // to calculate the SL values for opening an order
 
int start()
{
  int LinesCNT=0,i,ticket,pos; double p; datetime t; string s;
 
  int fh=FileOpen(FileNameForRead,FILE_CSV|FILE_READ,';'); // to test the file, it is necessary to pout it into tester\files\TL_DATA.txt
 
  if(fh<0) { MessageBox("Error opening file \"" + FileNameForRead + "\"","ERROR", IDOK + MB_ICONERROR); return(1); }
 
  // check all entries: if the opening time has already passed and no order with such a comment is found in history or in open orders
  // then it has not been opened yet - open it as it's said there
 
  while(true)
  {
    string Operation=FileReadString(fh);
    
    if(FileIsEnding(fh)) break; // file ended? - exit
    
    // count the section coordinates
    string st1=FileReadString(fh);
    string sp1=FileReadString(fh);
    string st2=FileReadString(fh);
    string sp2=FileReadString(fh);
    datetime t1=StrToTime(st1);
    double   p1=StrToDouble(sp1);
    datetime t2=StrToTime(st2);
    double   p2=StrToDouble(sp2);
    
  
    // what if sections' ends are mixed?
    if(t1>t2) { p=p1; p1=p2; p2=p; t=t1; t1=t2; t2=t;  s=st1; st1=st2; st2=s; s=sp1; sp1=sp2; sp2=s; } 
 
    string MarkComent = t1+"="+t2;
    
    //**********************************************************************************
    // ۱) block closing the orders as soon as the end of the pattern section is reached.
    //**********************************************************************************
    for(i=0;i<OrdersTotal();i++)
    {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue;
      if(OrderComment()==MarkComent && TimeCurrent()>=t2) // order must be closed
      {
        if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
        else OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
      }
    }
 
    //**********************************************************************************
    // ۲) block opening orders as soon as the beginning of the pattern section is passed.
    //**********************************************************************************
    bool OrderNotPresent=true; // a sign showing that we haven't opened such an order yet
    if(t1<=TimeCurrent() && TimeCurrent()<t2) // time to open - make sure that this order is not opened or closed
    {
      for(i=0;i<OrdersTotal();i++)
      {
        if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue;
        if(OrderComment()==MarkComent) { OrderNotPresent=false; break; } // order already exists
      }
      for(i=0;i<OrdersHistoryTotal() && OrderNotPresent;i++)
      {
        if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) continue;
        // order in history is added to the end, something like "[sl]" - it must be cut off!!
        pos = StringFind(OrderComment(),"[");
        string CurOrderComment = StringSubstr(OrderComment(),0,pos);
        if(CurOrderComment==MarkComent) { OrderNotPresent=false; break; } // order already exists
      }
      if(OrderNotPresent) // no such order - open it
      {
        // open an order
        if(Operation=="B") // Buy
        { 
          if(StopLoss<=0) SL=0; else SL=Ask-StopLoss*Point;
          ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,SL,0,MarkComent,1235,0,Blue);
          OrderSelect(ticket,SELECT_BY_TICKET);
        }
        else // Sell
        {
          if(StopLoss<=0) SL=0; else SL=Bid+StopLoss*Point;
          ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,SL,0,MarkComent,1235,0,Red);
          OrderSelect(ticket,SELECT_BY_TICKET);
        }
      }
    }
  }
  
  FileClose(fh);
 
  
  //******************************************************
  // ۳) block testing trailing stop and exit the market
  //******************************************************
  if(ProcedTrailing)
  {
    for(i=0;i<OrdersTotal();i++)
    {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) continue;
      if(OrderType()==OP_BUY)
      {
        if(Bid-OrderOpenPrice()>Point*TrailingStop)
        {
         if(OrderStopLoss()<Bid-Point*TrailingStop)
           {
            OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
            return(0);
           }
        }
      }
      if(OrderType()==OP_SELL)
      {
       if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
         {
          if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
            {
             OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
             return(0);
            }
         }
      }
    }
  }
  
  return(0);
}

چگونه این سیستم هنگامی که “کاملا یکپارچه” است کار می‌کند

جهت تست این سیستم، از یک دسته‌ی کوچک ۱۴ خطی استفاده کرده‌ایم. در اینجا محتوای فایل الگو با نام TL_DATA.txt را می‌بینید:

B;2007.12.28 05:00;1.4605;2008.01.09 22:00;1.4658
B;2008.01.29 05:00;1.4767;2008.02.05 05:00;1.4811
B;2008.02.15 16:00;1.4687;2008.02.21 09:00;1.4735
B;2008.02.21 14:00;1.4738;2008.02.26 07:00;1.4812
B;2008.02.28 14:00;1.5129;2008.03.05 12:00;1.5186
B;2008.03.05 22:00;1.5261;2008.03.11 20:00;1.5316
B;2008.03.13 01:00;1.5539;2008.03.18 22:00;1.5620
B;2008.03.26 14:00;1.5724;2008.03.28 10:00;1.5758
S;2007.11.30 13:00;1.4761;2007.12.10 22:00;1.4711
S;2007.12.14 04:00;1.4626;2007.12.28 00:00;1.4610
S;2008.01.17 17:00;1.4688;2008.01.24 13:00;1.4671
S;2008.02.07 12:00;1.4633;2008.02.14 11:00;1.4617
S;2008.03.19 23:00;1.5641;2008.03.25 23:00;1.5629
S;2008.03.31 19:00;1.5811;2008.04.08 04:00;1.5796

این فایل روی نمودار اینگونه خواهد بود:

تریلینگ اِستاپ

بهترین ترید نبود، اما بستر خوبی برای تست تریلینگ بود. 🙂

اگر تستر را با تریلینگ اِستاپ‌های غیرفعال (ProcedTrailing=false) اجرا کنیم، چنین نتیجه‌ی ضعیفی خواهیم داشت:

تریلینگ اِستاپ

یک بهینه‌سازی ساده‌ی تریلینگ‌اِستاپ‌گونه، مقدار بهینه‌ی ۹۵ پوینت را به ما می‌دهد.

تریلینگ اِستاپ

این مقدارِ بهینه که بیشترین سود را به ما داده، انطباق خوبی با آمار اندازه‌ی کندل‌های دوره‌ی تحتِ آزمایش، دارد: ۹۵ پوینت، یعنی ۹۸ درصد تمام کندل‌های این دوره، که به‌وضوح می‌توان در نمودارِ اندیکاتور ft.BarStat این را دید.

تریلینگ اِستاپ

همانطور که می‌بینید، نتایج بهینه‌سازی‌شده، بسیار جذاب‌تر به‌نظر می‌رسند:

تریلینگ اِستاپ

حتی می‌توان در نمودار، واضح‌تر این مسئله را دید. لطفاً توجه داشته باشید که تمامی معاملات دقیقاً در آغاز خطوط الگو باز شده‌اند!

تریلینگ اِستاپ

به اولین بخش نگاه کنید (March, 5). یک میله‌ی به سمت پایین بخشی از سود را با خود کَنده و بُرده، اما روند کلی Buy پابرجا مانده است. اگر تریلینگ را با یک اکسپرت معمولی تست می‌کردیم، کاملاً محتمل بود که یک پوزیشن Buy باز کند که تا انتهای خط دوم (بعد از March 17) باقی می‌ماند. در این صورت، نتایج غیرقابل‌مقایسه‌ای بدست می‌آوریم. سودی که در مورد دوم بدست آمد، حاصلِ با موفقیت باز شدنِ تکراری یک معامله‌ی جدید است، نه مکانیزم تریلینگ اِستاپ. هرچند، موضوع، بدست آوردن بیشترین حد سود نیست، بلکه، تا جای ممکن، داشتنِ مکانیزم تریلینگ اِستاپ کارآمد است. به همین دلیل، برای ما بسیار اهمیت دارد که تمامی معاملات همزمان باز شده‌، و برای مدتی طولانی نگه داشته نشده‌اند. هرچند، در این مورد، افزایشِ سودِ حاصل از بهینه‌سازی، کارایی الگوریتم تریلینگ را منعکس خواهدکرد!

نتیجه‌گیری

بسیار امیدوار هستم که بحث در مورد این مقاله تبدیل نشود به صحبت درباره‌ی چیز ناجوری که هیچ‌گاه من انجامش نداده‌ام! – خواننده‌ی مشتاق قطعاً کاربردی برای الگوریتم تحقیقاتی پیشنهاد‌شده پیدا خواهد کرد، حتی اگر به همین شکلی که اینجا آورده شده‌است، باشد. این مقاله ابزاری را توصیف می‌کند که من به آن دست یافته‌ام و ایده‌ی آن مدت‌ها ساکن ذهن من بوده و در نهایت، نظم به آن دادم و به شکل کد MQL4 آن را درآوردم. وقت برای اداره و هدایت تحقیقاتی که این ابزار برای آن ایجاد شده است را نداشتم. و به همین دلیل این مقاله هیچ‌گونه مقایسه‌ی تطبیقی بین الگوریتم‌های تریلینگ مختلف، ندارد. در آینده‌ای نزدیک به این موضوع خواهم پرداخت، و قسمت دوم مقاله به‌زودی برای انتشار آماده خواهد شد. با این حال، این مقاله به‌نظر به همین شکلی که هست، برای کسانی که MQL4 کار می‌کنند، مفید است.

دلیل دیگری که تصمیم گرفتم این ابزار “خام” را ارائه دهم این است که من یک برنامه‌نویس حرفه‌ای ولی یک تریدر تازه‌کار هستم. و این یعنی اینکه می‌توانم به‌طور مستقل کد MQL4 خود را تا ساده‌ترین یا پیچیده‌ترین حد ممکن توسعه دهم، اما برای تاکتیک‌های ترید و الگوریتم‌های تریلینگ، باید در کنار تریدرهایی حضور داشته باشم که در ترید به‌اندازه‌ی من در برنامه‌نویسی، حرفه‌ای هستند، تا بتوانیم کار را توسعه دهیم. به همین دلیل است که به ارتباط با همکارانم (انجمن دوستان فارکسی) برای خلق و توسعه بسیار علاقه‌مندم و دوست دارم با آن‌ها کار کنم تا ابزارهای خود را تبدیل به ابزارهایی کنم که در ترید واقعی بشود از آن‌ها استفاده کرد. اگر شما نیز علاقه‌مند به همکاری با من هستید، از طریق پروفایل من با من در ارتباط باشید.

توسعه‌ی دیگری که در آینده مدنظر داریم این است که می‌توانیم چند الگوریتم تریدینگ را روی یک نمودار، همزمان تست کنیم. در ابتدای بخش الگو، چند معامله باز می‌کنیم (به‌اندازه‌ی الگوریتم‌های تحت آزمایش)، که هرکدام دنباله‌رو الگوریتم خودش است. از نظر مفهومی، باید تصویری کلی بدست آوریم که نشان می‌دهد چندین تصویر روی هم قرار گرفته‌اند. آنگاه قادر خواهیم بود نتایج را هم از لحاظ کمّی (سود‌های خالص) و هم از لحاظ کیفی، مقایسه کنیم – قادر خواهیم بود ببینیم کدام الگوریتم وظیفه‌ی خود را دقیق‌تر انجام می‌دهد. هرچند این کار نیازمند این است که به اکسپرت خود بگوییم معاملات را با جایگزین تریلینگ‌ خود، از یکدیگر تفکیک کند، اما برای این موضوع جای نگرانی نیست.

راستی، از این روش‌ها می‌توان برای مقایسه‌ی هم تاکتیک‌های ورود و هم تاکتیک‌های خروج استفاده کرد! برای این کار فقط کافیست دسته‌ای از خطوط را با کمی تفاوت آماده کنید و اطمینان حاصل کنید نقاط بازشدن معامله‌تان، با توجه به روش‌هایی که مدنظر دارید، تا حد امکان نزدیک به بازشدن‌های الگو در نمودار است. این موضوع خود تحقیقی جدا می‌طلبد و عنوان مقاله‌ی دیگریست!

مقالات پیشنهادی :

M23admin

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

رویـداد‌هـا در مـتـاتـریـدر ۴

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

ترسیم سطح‌های افقی عبوری با استفاده از فراکتال‌ها

نوشتن نظر شما

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