
ساخت ساده با اکسپرت ادوایزر (Expert Advisor یا EA) در پلتفرم متاتریدر ۴ (MetaTrader 4)
یکی از قدرتمندترین ابزارها برای خودکارسازی فرآیندهای معاملهگری است که به معاملهگران اجازه میدهد تا استراتژیهای خود را به کدهای قابل اجرا تبدیل کرده و اجرای آنها را به صورت الگوریتمی و بدون دخالت انسانی به پلتفرم بسپارند. اساساً، یک اکسپرت ادوایزر برنامهای است که بر روی نمودار یک ابزار مالی (مانند جفتارز، شاخص یا کالا) اجرا میشود و بر اساس قوانین از پیش تعریف شده، تصمیمات معاملاتی مانند باز کردن، مدیریت و بستن موقعیتها را به صورت خودکار اتخاذ میکند. این امر نه تنها زمان صرف شده برای نظارت مداوم بر بازار را کاهش میدهد، بلکه خطاهای ناشی از تصمیمگیریهای احساسی را نیز حذف میکند، که یکی از بزرگترین چالشها در معاملهگری دستی است. برای ایجاد این رباتهای معاملاتی، نیاز به تسلط بر زبان برنامهنویسی اختصاصی متاتریدر، یعنی امکیوال۴ (MQL4)، است. این زبان که بر اساس سینتکس زبان C++ بنا شده، به گونهای طراحی شده که دسترسی مستقیم و بهینه به تمام دادههای بازار، تاریخچه قیمتها و توابع مدیریت سفارشات پلتفرم متاتریدر ۴ را فراهم آورد. درک عمیق از عملکرد اکسپرت ادوایزر و نحوه تعامل آن با محیط متاتریدر ۴، اولین گام اساسی برای ورود به دنیای برنامهنویسی الگوریتمی در بازارهای مالی است.
معرفی زبان (MQL4) و جایگاه آن در برنامهنویسی الگوریتمی
امکیوال۴ (MQL4) مخفف MetaQuotes Language 4 است و زبان اصلی برنامهنویسی مورد استفاده در متاتریدر ۴ محسوب میشود. این زبان از لحاظ ساختاری شباهت زیادی به زبان C++ دارد، اما با افزودن توابع و ساختارهای دادهای خاص برای نیازهای معاملهگری و تحلیل تکنیکال توسعه یافته است. جایگاه MQL4 در برنامهنویسی الگوریتمی بسیار محوری است، زیرا مستقیماً با موتور داخلی ترمینال متاتریدر ۴ ارتباط برقرار میکند. این ارتباط مستقیم به اکسپرت ادوایزرها این امکان را میدهد که به دادههای لحظهای بازار (Ask، Bid)، قیمتهای تاریخی (OHLC)، شاخصهای فنی استاندارد (مانند میانگین متحرک یا RSI) و همچنین توابع مدیریت سفارشات مانند OrderSend دسترسی داشته باشند. برخلاف زبانهای برنامهنویسی عمومی که نیاز به کتابخانههای واسط برای اتصال به کارگزاریها دارند، کدهای MQL4 مستقیماً در محیط ترمینال کامپایل و اجرا میشوند، که این امر سرعت اجرای آنها را به شدت بالا میبرد و امکان اجرای بلادرنگ (Real-time execution) را فراهم میآورد. درک سینتکس، انواع دادهها، ساختارهای کنترلی (مانند حلقهها و شرطها) و مهمتر از همه، توابع اختصاصی MQL4 برای مدیریت زمان، قیمت و سفارشات، لازمه اصلی برای هر کسی است که قصد دارد یک اکسپرت ادوایزر کارآمد بسازد. این زبان ابزاری است که رؤیای یک استراتژی معاملاتی پیچیده را به کدی قابل اجرا تبدیل میکند.
تفاوت اسکریپت، اندیکاتور و (Expert) در MT4
پلتفرم متاتریدر ۴ میزبان سه نوع اصلی از برنامههای قابل اجرا است که هرکدام وظیفه و چرخه حیات مشخصی دارند: اسکریپتها (Scripts)، اندیکاتورها (Indicators) و اکسپرت ادوایزرها (Experts). درک تفاوتهای بنیادین این سه، برای انتخاب ابزار مناسب جهت پیادهسازی یک ایده معاملاتی ضروری است.
اسکریپتها (Scripts) سادهترین نوع برنامه در MQL4 هستند. آنها برای انجام یک عمل یکباره طراحی شدهاند و پس از اجرای یک دستور، بلافاصله کار خود را به پایان میرسانند و از نمودار حذف میشوند. برای مثال، یک اسکریپت میتواند برای بستن تمام موقعیتهای باز در یک نماد خاص یا اصلاح سریع تنظیمات یک اندیکاتور استفاده شود. چرخه حیات یک اسکریپت بسیار کوتاه است؛ تابع OnStart() تنها تابعی است که در یک اسکریپت اجرا میشود و پس از اتمام کار آن، برنامه متوقف میگردد.
اندیکاتورها (Indicators) ابزارهایی تحلیلی هستند که وظیفهشان ترسیم یا محاسبه اطلاعات بر اساس دادههای قیمتی تاریخی و فعلی است. این برنامهها صرفاً دادهها را نمایش میدهند و به خودی خود مجاز به ارسال دستورات معاملاتی نیستند (مگر با استفاده از ترفندهای خاص یا استفاده از متغیرهای Global که معمولاً توصیه نمیشود). اندیکاتورها بر روی نمودار باقی میمانند و هر بار که قیمت جدیدی دریافت شود، محاسبات خود را بهروز میکنند. تابع اصلی آنها OnCalculate() است که مسئول انجام محاسبات فنی و رسم خطوط یا اشکال بر روی نمودار است.
در نهایت، اکسپرت ادوایزرها (Experts) پیچیدهترین نوع برنامه هستند. آنها برنامههایی هستند که هم تحلیل میکنند (مانند اندیکاتورها) و هم اقدام میکنند (مانند اسکریپتها). اکسپرت ادوایزر پس از اتصال به یک نمودار، در تمام طول حیات خود، به صورت مداوم وضعیت بازار را تحت نظر دارد و بر اساس منطق معاملاتی از پیش تعریف شده، قادر است دستورات خرید و فروش را از طریق تابع OrderSend() به سرور کارگزاری ارسال نماید. چرخه حیات یک اکسپرت از طریق توابع OnInit() (هنگام شروع)، OnTick() (با دریافت هر تیک جدید قیمت) و OnDeinit() (هنگام حذف از نمودار) مدیریت میشود. بنابراین، اگر هدف خودکارسازی کامل تصمیمات و اجرای معاملات باشد، قطعاً باید از یک اکسپرت ادوایزر استفاده شود.
ساختار فایلهای اکسپرت در MQL4 و توضیح کامل پوشهها
هر اکسپرت ادوایزر در MQL4 به عنوان یک فایل اجرایی با پسوند .mq4 نوشته میشود که این فایلها در محیط متاتریدر ۴ توسط کامپایلر به فایلهای .ex4 تبدیل میگردند تا قابل اجرا باشند. ساختاردهی صحیح فایلها در پوشههای مربوطه در پوشه MQL4 نصب متاتریدر ۴ بسیار حیاتی است. پوشه اصلی MQL4 معمولاً در مسیر C:\Program Files\MetaTrader 4\MQL4 یا مشابه آن قرار دارد. در داخل این پوشه، چندین زیرپوشه کلیدی وجود دارد که هرکدام وظیفه مشخصی را بر عهده دارند.
پوشه Experts جایی است که تمام فایلهای سورس کد اکسپرت ادوایزر ما (فایلهای .mq4) و همچنین فایلهای کامپایل شده (فایلهای .ex4) باید قرار گیرند تا در لیست ناوبری (Navigator) متاتریدر ۴ ظاهر شوند. اگر یک اکسپرت جدید میسازیم، باید آن را در این پوشه ذخیره کنیم.
پوشه Indicators برای نگهداری کد اندیکاتورها استفاده میشود، و پوشه Scripts برای اسکریپتها. این تفکیک سیستمی کمک میکند تا مدیریت پروژهها آسانتر شود. علاوه بر این، پوشههای دیگری مانند Libraries برای نگهداری کتابخانههای سفارشی (فایلهای .ex4 که حاوی توابع قابل استفاده مجدد در چندین اکسپرت هستند) و Include برای نگهداری فایلهای هدر (فایلهای .mqh که شامل تعاریف متغیرها یا توابع کمکی هستند) وجود دارند. برای یک اکسپرت ادوایزر ساده، تمرکز ما روی پوشه Experts خواهد بود. تمامی کدهای ما باید شامل یک ساختار مشخص شامل تعاریف اولیه، تعریف متغیرهای ورودی، توابع اصلی و منطق معاملاتی باشند. عدم رعایت این ساختار استاندارد یا قرار دادن فایلها در مسیر اشتباه، منجر به عدم شناسایی یا اجرای نادرست اکسپرت خواهد شد.
معرفی کامل توابع اصلی OnInit، OnDeinit و OnTick با توضیح کاربرد عملی هرکدام
ساختار اصلی هر اکسپرت ادوایزر بر پایه سه تابع اختصاصی MQL4 استوار است که چرخه حیات برنامه را تعریف میکنند: OnInit(), OnDeinit(), و OnTick(). این توابع به صورت خودکار توسط موتور متاتریدر ۴ فراخوانی میشوند.
تابع OnInit() (Initialization): این تابع تنها یک بار و دقیقاً در لحظهای که اکسپرت ادوایزر برای اولین بار به یک نمودار متصل میشود یا پس از تغییر تنظیمات آن (تغییر پارامترهای ورودی)، فراخوانی میگردد. این تابع محل ایدهآلی برای کارهای آمادهسازی اولیه است. در این تابع باید بررسیهای اولیه انجام شود، مانند اطمینان از فعال بودن معاملات خودکار در تنظیمات ترمینال، بررسی اینکه آیا این اکسپرت قبلاً در این نماد و تایمفریم اجرا شده است یا خیر، و همچنین تخصیص حافظه یا فراخوانی توابع کمکی مورد نیاز. در پایان اجرای تابع، اگر کدی که برای مقدار بازگشتی (Return Value) تعریف شده، مقدار INIT_SUCCEEDED را برگرداند، اکسپرت آماده اجرای مراحل بعدی میشود؛ در غیر این صورت، اکسپرت با شکست مواجه شده و متوقف میگردد.
تابع OnDeinit() (De-initialization): این تابع نیز تنها یک بار، دقیقاً قبل از حذف اکسپرت ادوایزر از نمودار یا هنگام خاموش شدن ترمینال متاتریدر ۴ فراخوانی میشود. کاربرد اصلی آن، آزادسازی منابعی است که در OnInit() تخصیص داده شدهاند. برای مثال، اگر متغیرهای سراسری یا منابع حافظه خاصی را تخصیص دادهاید، باید در اینجا آنها را پاکسازی کنید. همچنین این محل مناسبی برای ارسال پیام پایانی به سیستم یا بستن موقت موقعیتهایی است که نیاز به نظارت پس از قطع اجرای ربات دارند (البته این کار باید با احتیاط انجام شود، زیرا در برخی سناریوها ممکن است بسته شدن ناخواسته رخ دهد).
تابع OnTick(): این تابع قلب تپنده هر اکسپرت ادوایزر است و مسئول اجرای منطق معاملاتی است. تابع OnTick() هر بار که یک قیمت جدید (تیک) از سرور کارگزاری دریافت میشود، فراخوانی میگردد. از آنجا که قیمتها ممکن است بسیار سریع تغییر کنند، این تابع ممکن است صدها یا هزاران بار در دقیقه فراخوانی شود. تمام منطق اصلی تصمیمگیری برای باز کردن یا بستن موقعیتها در این تابع پیادهسازی میشود. به دلیل فراخوانی مکرر، برنامهنویسی درون OnTick() باید بسیار کارآمد باشد و از اجرای دستورات غیرضروری جلوگیری شود تا از ارسال بیش از حد درخواستها به سرور جلوگیری شود.
//+------------------------------------------------------------------+
//| SimpleEA_Structure.mq4 |
//+------------------------------------------------------------------+
int OnInit()
{
// بررسی اولیه: اطمینان از فعال بودن معاملات خودکار
if(!IsExpertEnabled())
{
Print("هشدار: معاملات خودکار در تنظیمات ترمینال غیرفعال است!");
return(INIT_FAILED);
}
Print("اکسپرت ادوایزر با موفقیت مقداردهی اولیه شد.");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// انجام عملیات پاکسازی نهایی
Print("اکسپرت ادوایزر در حال خاموش شدن است. دلیل: ", reason);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
// منطق معاملاتی اصلی در اینجا اجرا می شود
if(PositionsTotal() == 0) // فقط زمانی که هیچ موقعیتی باز نیست
{
double currentMA = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE, 1);
double prevMA = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE, 2);
if(currentMA > prevMA)
{
// شرط خرید برقرار است
SendOrder(OP_BUY);
}
else if(currentMA < prevMA)
{
// شرط فروش برقرار است
SendOrder(OP_SELL);
}
}
}
بررسی (Trading Logic) در اکسپرت ساده
منطق معاملاتی هسته اصلی هر اکسپرت ادوایزر است و مجموعهای از قواعد قطعی است که تعیین میکند چه زمانی باید وارد بازار شد، چگونه موقعیت باز را مدیریت کرد و چه زمانی باید از بازار خارج شد. در برنامهنویسی الگوریتمی، این منطق باید کاملاً ریاضی، غیرقابل تفسیر و بدون جایگزینی برای احساسات انسانی باشد. یک منطق معاملاتی خوب باید شامل سه بخش اصلی باشد: شرایط ورود (Entry Conditions)، شرایط مدیریت موقعیت (Position Management) و شرایط خروج (Exit Conditions).
شرایط ورود معمولاً بر اساس سیگنالهای تولید شده توسط اندیکاتورهای تکنیکال یا تجزیه و تحلیل دادههای قیمتی تعیین میشوند. برای مثال، سادهترین منطق بر اساس تقاطع دو میانگین متحرک (Moving Average Crossover) است: ورود خرید زمانی که میانگین سریعتر از میانگین کندهتر عبور کند و ورود فروش زمانی که میانگین سریعتر از پایین به میانگین کندهتر عبور کند.
شرایط مدیریت موقعیت شامل تعیین سطوح حد سود (Take Profit – TP) و حد ضرر (Stop Loss – SL) و همچنین اجرای قواعدی برای تریلینگ استاپ (Trailing Stop) یا تغییر این سطوح در طول عمر معامله است. مهم است که اکسپرت توانایی بررسی وضعیت بازار (آیا موقعیتی باز است یا خیر) را داشته باشد تا از ارسال بیش از یک دستور خرید در یک زمان جلوگیری کند، که این امر توسط تابع PositionsTotal() بررسی میشود.
شرایط خروج میتواند بر اساس رسیدن به TP/SL، یا بر اساس سیگنال معکوس منطق معاملاتی ورود، یا صرفاً بر اساس زمانبندی (مثلاً خروج پس از ۲۴ ساعت) تعریف شود. هرچه منطق پیچیدهتر باشد، نیاز به توابع کمکی و ساختارهای دادهای بیشتری در MQL4 خواهد بود، اما برای شروع، باید منطق را تا حد امکان ساده نگه داشت تا اشکالزدایی (Debugging) آسانتر باشد.
طراحی یک استراتژی بسیار ساده (مثلاً بر اساس Moving Average)
برای ساخت اولین اکسپرت ادوایزر، از یک استراتژی کلاسیک و بسیار شناخته شده به نام تقاطع میانگین متحرک (Moving Average Crossover) استفاده میکنیم. این استراتژی ساده، پتانسیل خوبی برای یادگیری مفاهیم پایه دارد. فرض میکنیم که از دو میانگین متحرک نمایی (Exponential Moving Average – EMA) با دورههای متفاوت استفاده خواهیم کرد: EMA 10 به عنوان میانگین سریع و EMA 30 به عنوان میانگین کند.
قوانین استراتژی:
- شرط خرید (Long Entry): اگر EMA 10 از پایین به EMA 30 عبور کند (EMA 10 > EMA 30 در کندل فعلی و EMA 10 < EMA 30 در کندل قبلی) و هیچ موقعیت باز دیگری وجود نداشته باشد، یک دستور خرید ارسال میشود.
- شرط فروش (Short Entry): اگر EMA 10 از بالا به EMA 30 عبور کند (EMA 10 < EMA 30 در کندل فعلی و EMA 10 > EMA 30 در کندل قبلی) و هیچ موقعیت باز دیگری وجود نداشته باشد، یک دستور فروش ارسال میشود.
- شرط خروج: در این نسخه ساده، موقعیتها تنها در صورت رسیدن به حد ضرر یا حد سود از پیش تعیین شده بسته خواهند شد.
برای محاسبه مقادیر میانگین متحرک از تابع داخلی MQL4 به نام iMA() استفاده میکنیم. دقت داشته باشید که باید به شاخصهای (Indices) کندلها توجه کرد؛ شاخص 0 مربوط به کندل فعلی (در حال بسته شدن) و شاخص 1 مربوط به کندل بسته شده قبلی است.
// محاسبه میانگین متحرک ها
double fastMA = iMA(Symbol(), Period(), FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
double slowMA = iMA(Symbol(), Period(), SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
double prevFastMA = iMA(Symbol(), Period(), FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double prevSlowMA = iMA(Symbol(), Period(), SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
// شرط خرید
if(fastMA > slowMA && prevFastMA < prevSlowMA)
{
// سیگنال خرید
if(PositionsTotal() == 0)
{
SendOrder(OP_BUY, ...);
}
}
// شرط فروش
else if(fastMA < slowMA && prevFastMA > prevSlowMA)
{
// سیگنال فروش
if(PositionsTotal() == 0)
{
SendOrder(OP_SELL, ...);
}
}
این منطق اطمینان میدهد که ورود تنها در لحظه تقاطع اتفاق میافتد و از ورودهای مکرر در یک جهت جلوگیری میکند.
توضیح دقیق متغیرها، ورودیها () و مدیریت تنظیمات
یکی از بزرگترین مزایای اکسپرت ادوایزرها نسبت به اسکریپتها، قابلیت تنظیم پارامترهای آنها بدون نیاز به تغییر کد منبع و کامپایل مجدد است. این کار از طریق تعریف متغیرهای ورودی یا Input Parameters انجام میشود که با استفاده از کلمه کلیدی extern یا در نسخههای جدیدتر MQL4 با استفاده از input در تعریف متغیر، مشخص میگردند. این متغیرها در پنجره تنظیمات اکسپرت در متاتریدر ۴ قابل دستکاری هستند و امکان بهینهسازی (Optimization) پارامترها را فراهم میکنند.
برای استراتژی میانگین متحرک، پارامترهای ورودی شامل دورههای زمانی برای میانگین متحرکها، حجم معامله (Lot Size)، فاصله حد ضرر و حد سود خواهند بود.
//--- Input Parameters (پارامترهای ورودی)
input int FastMAPeriod = 10; // دوره میانگین متحرک سریع
input int SlowMAPeriod = 30; // دوره میانگین متحرک کند
input double LotSize = 0.1; // حجم معامله
input int StopLossPips = 500; // حد ضرر بر حسب پیپ (برای 5 رقمی: 50 پیپ)
input int TakeProfitPips = 1000; // حد سود بر حسب پیپ (برای 5 رقمی: 100 پیپ)
این متغیرها باید در ابتدای کد تعریف شوند. در تابع OnInit() میتوانیم از این متغیرها برای بررسیهای اولیه استفاده کنیم. نکته مهم در مدیریت تنظیمات، تبدیل مقادیر بر حسب پیپ به مقادیر قیمتی قابل استفاده توسط توابع معاملاتی است. برای مثال، اگر کارگزاری 5 رقمی است، یک فاصله 50 پیپی برابر با 500 واحد پوینت است. باید از تابع _Point برای محاسبه دقیق فاصله استفاده شود.
// در داخل OnInit یا قبل از OrderSend
double sl_price, tp_price;
double point_value = MarketInfo(Symbol(), MODE_POINT);
if(orderType == OP_BUY)
{
sl_price = Bid - StopLossPips * point_value;
tp_price = Bid + TakeProfitPips * point_value;
}
// ... (برای OP_SELL مشابه)
مدیریت صحیح Input Parameters باعث میشود اکسپرت ادوایزر انعطافپذیر باشد و بتوان آن را برای نمادهای مختلف یا شرایط بازار متفاوت بدون نیاز به کامپایل مجدد، تنظیم نمود.
بررسی نحوه ارسال دستور خرید و فروش با OrderSend
ارسال دستورات معاملاتی در MQL4 منحصراً از طریق تابع قدرتمند OrderSend() انجام میگیرد. این تابع مسئول برقراری ارتباط با سرور کارگزاری و ثبت سفارش است. ساختار این تابع بسیار مفصل است و شامل ۹ آرگومان اجباری است که باید با دقت پر شوند.
سینتکس کلی تابع:
int OrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration, color arrow_color)
- symbol: نماد مورد نظر (مثلاً “EURUSD”).
- cmd: نوع عملیات (مثلاً
OP_BUYبرای خرید یاOP_SELLبرای فروش). - volume: حجم معامله بر حسب لات (Lot).
- price: قیمت ورود مورد نظر. برای خرید از قیمت Ask و برای فروش از قیمت Bid استفاده میشود.
- slippage: میزان انحراف مجاز (Slippage) بر حسب پوینت.
- stoploss: قیمت حد ضرر. اگر قیمتی برای آن تعیین نشود، باید صفر (0.0) قرار داده شود.
- takeprofit: قیمت حد سود. اگر قیمتی برای آن تعیین نشود، باید صفر (0.0) قرار داده شود.
- comment: توضیحی که در تاریخچه معاملات نمایش داده میشود.
- magic: عدد جادویی (Magic Number) که برای شناسایی موقعیتهای باز شده توسط این اکسپرت ادوایزر خاص استفاده میشود. این پارامتر حیاتی است.
- expiration: زمان انقضای سفارش (برای سفارشات در انتظار یا Pending Orders). برای سفارشات بازار (Market Orders) صفر است.
- arrow_color: رنگی که برای نمایش فلش سیگنال بر روی نمودار استفاده میشود (برای سفارشات بازار معمولاً 0).
مثال ارسال دستور خرید:
// فرض کنید متغیرهای قیمت و پارامترها محاسبه شدهاند
double sl_buy = Bid - StopLossPips * _Point * 10; // برای 5 رقمی
double tp_buy = Bid + TakeProfitPips * _Point * 10; // برای 5 رقمی
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 5, sl_buy, tp_buy,
"Simple MA Buy", 12345, 0, clrBlue);
if(ticket > 0)
{
Print("سفارش خرید با موفقیت ارسال شد. Ticket: ", ticket);
}
else
{
Print("خطا در ارسال سفارش خرید! کد خطا: ", GetLastError());
}
در اینجا، عدد جادویی 12345 به اکسپرت کمک میکند تا در آینده فقط موقعیتهایی را که خود آن ایجاد کرده، مدیریت یا ببندد. بررسی مقدار بازگشتی ticket بسیار مهم است؛ اگر مثبت باشد، سفارش ارسال شده است و اگر صفر یا منفی باشد، خطایی رخ داده است که باید با استفاده از GetLastError() بررسی شود.
مدیریت خطاها و بررسی در MQL4
یکی از تفاوتهای اصلی بین یک کد ناشیانه و یک اکسپرت ادوایزر حرفهای، توانایی آن در مدیریت خطاها یا Error Handling است. در محیط معاملاتی زنده، ارسال یک سفارش ممکن است به دلایل متعددی با شکست مواجه شود: قیمت بازار تغییر کرده باشد (Requote)، اعتبار کافی نباشد (Not Enough Money)، یا تنظیمات حد ضرر/حد سود نامعتبر باشد (Invalid SL/TP). اگر اکسپرت پس از شکست در ارسال سفارش، فرآیند خود را ادامه دهد، ممکن است در تیک بعدی دوباره تلاش کند و باعث ارسال مجدد سفارش شود.
در MQL4، هرگاه یک تابع اصلی (مانند OrderSend، OrderModify یا OrderClose) با شکست مواجه شود، یک کد خطا به آخرین مقدار برگردانده میشود که با تابع GetLastError() قابل بازیابی است. این کد خطا باید بلافاصله پس از هر عملیات حساس بررسی شود.
برای مثال، پس از OrderSend:
int result = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 5, 0, 0, "Buy", 12345, 0, clrNONE);
if(result < 0)
{
int error_code = GetLastError();
Print("خطای ارسال سفارش در ", Symbol(), ": ", error_code);
// تحلیل کدهای رایج خطا
if(error_code == 130) // Invalid Stoploss/Takeprofit
{
Print("SL/TP خارج از محدوده مجاز بازار است.");
}
else if(error_code == 131) // री-कोट (Requote)
{
// ممکن است نیاز به دریافت قیمت جدید و تلاش مجدد باشد
RefreshRates();
Print("قیمت بازار تغییر کرد. تلاش مجدد در تیک بعدی.");
}
// از اجرای توابع مدیریت موقعیت برای این تیک صرف نظر می کنیم
return;
}
همچنین، برای مدیریت موقعیتهای باز، باید قبل از ارسال هرگونه دستور اصلاح یا بستن، از تابع OrderSelect() استفاده شود تا اطمینان حاصل شود که موقعیت صحیح انتخاب شده است و اینکه آیا آن موقعیت واقعاً توسط این اکسپرت (با استفاده از Magic Number) باز شده است یا خیر. این بررسیها از تداخل با معاملات دستی یا معاملات سایر اکسپرتها جلوگیری میکند و استحکام برنامه را به شدت افزایش میدهد.
تست اکسپرت در (Strategy Tester)
قبل از اجرای هر اکسپرت ادوایزر بر روی حساب واقعی، ضروری است که عملکرد آن در شرایط تاریخی بازار ارزیابی شود. این فرآیند از طریق ابزار استراتژی تستر (Strategy Tester) در متاتریدر ۴ انجام میشود. استراتژی تستر به ما اجازه میدهد تا اکسپرت را بر روی دادههای تاریخی قیمت (Historical Data) اجرا کنیم و کارایی آن را در طول زمان اندازهگیری نماییم.
برای شروع تست، ابتدا باید مطمئن شویم که دادههای تاریخی کافی و با کیفیت برای نماد مورد نظر دانلود شدهاند، که این امر از طریق پنجره Market Watch و انتخاب گزینه History Center قابل انجام است. سپس، استراتژی تستر (با کلید میانبر Ctrl+R) باز میشود. در این پنجره، موارد زیر باید تنظیم شوند:
- Expert Advisor: انتخاب اکسپرت ادوایزر ساخته شده.
- Symbol: انتخاب نماد معاملاتی.
- Model: حالت مدلسازی که کیفیت تست را تعیین میکند. برای دقیقترین نتایج، مدل Every tick (هر تیک) توصیه میشود، اگرچه کندترین است. مدل Control Points سریعتر است اما دقت کمتری دارد.
- Date Range: تعیین بازه زمانی تست.
- Input Parameters: تنظیم مقادیر Input Parameters که در مرحله قبل تعریف کردیم (مثلاً EMA 10 و EMA 30).
- Optimization: اگر هدف بهینهسازی باشد، این گزینه فعال میشود تا استراتژی تستر به صورت خودکار بهترین ترکیب پارامترها را بیابد.
پس از اجرای تست، گزارش مفصلی در تب Report ارائه میشود که شامل شاخصهای کلیدی عملکرد (KPIs) مانند خالص سود (Net Profit)، ضریب ریسک به ریوارد (Profit Factor)، حداکثر افت سرمایه (Maximal Drawdown) و تعداد کل معاملات است. این گزارش ابزاری ضروری برای اعتبارسنجی منطق معاملاتی است. اگر اکسپرت در تست تاریخی سودآور نبود، نشان میدهد که منطق نیازمند بازبینی یا بهینهسازی دقیقتر است.
نکات مهم برای جلوگیری از خطاهای رایج مبتدیان
ساخت اولین اکسپرت ادوایزر مملو از تلههایی است که برنامهنویسان تازهکار اغلب در آنها گرفتار میشوند. آگاهی از این خطاهای رایج میتواند فرآیند توسعه را روانتر کند.
یکی از شایعترین خطاها، مسئله تکرار معامله (Over-trading) در تابع OnTick() است. همانطور که ذکر شد، OnTick() با هر تیک قیمت فراخوانی میشود. اگر برنامه بررسی نکند که آیا موقعیتی باز است یا خیر، ممکن است صدها دستور خرید در یک ثانیه ارسال کند. برای جلوگیری از این امر، باید همواره بررسی شود: if(PositionsTotal() == 0) قبل از ارسال هر دستور ورود جدید.
خطای دیگر مربوط به مدیریت قیمتها و اعشار است. MQL4 باید بداند که آیا کارگزاری شما 4 رقمی است یا 5 رقمی. استفاده نادرست از _Point در محاسبات SL/TP میتواند باعث شود که حد ضرر یا حد سود در نقطهای بسیار دور یا بسیار نزدیک به قیمت فعلی تنظیم شود. همواره باید از تابع MarketInfo(Symbol(), MODE_POINT) برای تعیین مقدار پوینت استفاده کرد.
استفاده نامناسب از Magic Number نیز اشتباه بزرگی است. اگر دو اکسپرت یا یک اکسپرت و یک معامله دستی از یک Magic Number (مثلاً 0) استفاده کنند، توابع مدیریت سفارش ممکن است موقعیتهای ناخواسته را ببندند یا اصلاح کنند. استفاده از یک عدد جادویی منحصر به فرد برای هر اکسپرت ضروری است.
همچنین، نباید فراموش کرد که اکسپرت فقط در صورتی اجرا میشود که:
- اجازه اجرای معاملات خودکار در تنظیمات ترمینال داده شده باشد.
- آیکون “AutoTrading” در نوار ابزار سبز باشد.
- تابع
OnInit()با موفقیت اجرا شده وINIT_SUCCEEDEDرا برگردانده باشد.
نکته آخر، اجرای کدهای زمانبر در OnTick() است. توابعی که نیاز به جستجو در تاریخچه طولانی دارند یا محاسبات پیچیده انجام میدهند، باید به توابع کمکی خارج از OnTick() منتقل شوند و اجرای آنها به تیکهای خاص (مثلاً فقط در اولین تیک هر کندل جدید) محدود شود تا از کاهش سرعت عملکرد ترمینال جلوگیری گردد.
مسیر یادگیری حرفهایتر پس از ساخت اولین اکسپرت
ساخت یک اکسپرت ادوایزر مبتنی بر تقاطع میانگین متحرک یک نقطه شروع عالی است، اما برای تبدیل شدن به یک برنامهنویس الگوریتمی حرفهای، باید دانش خود را فراتر ببرید. مسیر بعدی شامل عمق بخشیدن به مفاهیم MQL4 و تکنیکهای پیشرفته معاملهگری الگوریتمی است.
ابتدا، باید بر روی ساختاردهی کد تمرکز کرد. یادگیری نحوه استفاده از فایلهای هدر (.mqh) برای سازماندهی توابع کمکی و متغیرهای سراسری، به حفظ نظم در پروژههای بزرگ کمک میکند. همچنین، پیادهسازی یک سیستم مدیریت ریسک قوی خارج از منطق ورود/خروج، مانند محاسبه حجم لات بر اساس درصد ریسک از سرمایه (Risk Percentage Sizing) به جای استفاده از حجم ثابت، حیاتی است.
سپس، باید بر مدیریت وضعیتهای پیشرفته تسلط یافت. این شامل یادگیری نحوه کار با انواع سفارشات در انتظار (Pending Orders) مانند OP_BUYLIMIT و OP_SELLSTOP است، که برای استراتژیهای شکست (Breakout) ضروری هستند. مدیریت تریلینگ استاپهای پیچیده که توسط اکسپرت مدیریت میشوند، یکی دیگر از مراحل پیشرفته است.
در مرحله بعدی، لازم است که به جای تکیه بر توابع داخلی MQL4، یاد بگیریم چگونه با استفاده از توابع پیچیدهتر iCustom() اندیکاتورهای سفارشی خود را مستقیماً از درون اکسپرت ادوایزر فراخوانی کنیم. این امر به شما اجازه میدهد تا رباتهایی بسازید که بر اساس شاخصهای توسعه داده شده توسط خودتان تصمیم بگیرند.
آموزش عمیقتر در زمینه استراتژی تستر و استفاده از توابع بهینهسازی پیشرفته برای یافتن پارامترهای مقاوم در برابر تغییرات بازار (Robustness testing) نیز بسیار مهم است. در نهایت، مهاجرت به MQL5 برای بهرهمندی از قابلیتهای چند نخی (Multithreading)، پشتیبانی بهتر از دادههای تاریخچه و اجرای تستهای پیشرفتهتر، گام نهایی برای تبدیل شدن به یک متخصص در برنامهنویسی الگوریتمی خواهد بود.
دیدگاهها (0)