مدیریت ریسک و تعیین حجم معامله در رباتهای معاملاتی (با مثال طلا و MQL5)
فرمول تعیین حجم معامله بر اساس درصد ریسک و فاصله حد ضرر، حد ضرر پویا با ATR، توقف روزانه، محاسبه درست ارزش تیک در MetaTrader 5 و خطاهای رایج بکتست؛ با مثال عددی روی XAUUSD.
در ساختن رباتهای معاملاتی برای طلا، زود به این نتیجه رسیدم که بیشترین ضرر حسابها از سیگنال غلط نمیآید؛ از حجم نامتناسب، جابهجا کردن حد ضرر و ادامه دادن بعد از چند ضرر پشت سر هم میآید. هیچ استراتژیای همیشه درست نیست، پس چیزی که بقای حساب را تعیین میکند، قوانین ریسک است. این مقاله قوانینی است که در اکسپرتهای MQL5 خودم پیاده کردهام، با فرمول و مثال عددی. پیش از هر چیز: این مطلب درباره ساختن ابزار و کنترل ریسک است، نه توصیه سرمایهگذاری یا وعده سود.
قاعده اول: ریسک ثابت به درصد، نه حجم ثابت
ورود با حجم ثابت (مثلاً همیشه ۰٫۱ لات) یعنی ریسک هر معامله به فاصله حد ضرر بستگی دارد: معاملهای با حد ضرر نزدیک ریسک کمی دارد و معاملهای با حد ضرر دور، ریسک زیادی. این ریسک ناخواسته است و کنترل نمیشود.
روش درست برعکس است: اول تعیین میکنید حاضرید در هر معامله چه درصدی از حساب را از دست بدهید (معمولاً عددی کوچک)، بعد حجم را از روی فاصله حد ضرر حساب میکنید. فرمول:
حجم = (موجودی × درصد ریسک) ÷ (فاصله حد ضرر × ارزش هر واحد حرکت قیمت برای یک لات)
نتیجه این است که مستقل از فاصله حد ضرر، ضرر هر معامله در صورت خوردن حد ضرر تقریباً ثابت است.
مثال عددی روی طلا
فرض کنید موجودی حساب ۱۰٬۰۰۰ دلار است و ریسک هر معامله ۱ درصد، یعنی حداکثر ضرر ۱۰۰ دلار. در بیشتر بروکرها اندازه قرارداد یک لات طلا (XAUUSD) ۱۰۰ اونس است؛ یعنی هر یک دلار حرکت قیمت برای یک لات، ۱۰۰ دلار سود یا زیان دارد.
اگر حد ضرر ۵ دلار از قیمت ورود فاصله داشته باشد: حجم = ۱۰۰ ÷ (۵ × ۱۰۰) = ۰٫۲ لات. اگر حد ضرر ۱۰ دلار فاصله داشته باشد: حجم = ۱۰۰ ÷ (۱۰ × ۱۰۰) = ۰٫۱ لات. در هر دو حالت، اگر حد ضرر بخورد، ضرر حدود ۱۰۰ دلار است.
اندازه قرارداد را از بروکر خودتان بررسی کنید و در کد هم هرگز آن را ثابت ننویسید؛ از مشخصات نماد بخوانید، چون بین بروکرها و حسابها فرق میکند.
نکات کلیدی
- ریسک هر معامله به درصد موجودی، کوچک و ثابت.
- حجم نتیجه محاسبه است، نه ورودی.
- مشخصات نماد را از بروکر بخوانید، نه از حافظه.
پیادهسازی در MQL5: ارزش تیک و گام حجم
در MetaTrader 5، ارزش حرکت قیمت را باید از مشخصات نماد گرفت: SYMBOL_TRADE_TICK_SIZE (کوچکترین حرکت قیمت) و SYMBOL_TRADE_TICK_VALUE (ارزش آن حرکت برای یک لات به ارز حساب). حجم نهایی هم باید به گام مجاز حجم (SYMBOL_VOLUME_STEP) گرد شود (همیشه رو به پایین، تا ریسک از حد بیشتر نشود) و بین حداقل و حداکثر مجاز بماند.
خطای رایجی که در کدهای آماده دیدهام، گرد کردن رو به بالا یا نادیده گرفتن حداقل حجم است؛ در حساب کوچک ممکن است حجم محاسبهشده از حداقل کمتر شود. در این حالت درست این است که معامله انجام نشود، نه اینکه با حداقل حجم و ریسکی بیشتر از قاعده وارد شود.
// حجم بر اساس درصد ریسک و فاصله حد ضرر (به واحد قیمت)
double LotsForRisk(const string sym, const double riskPct, const double slDistance)
{
if(slDistance <= 0.0) return 0.0;
const double equity = AccountInfoDouble(ACCOUNT_EQUITY);
const double riskMoney = equity * riskPct / 100.0;
const double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
const double tickValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
if(tickSize <= 0.0 || tickValue <= 0.0) return 0.0;
const double lossPerLot = slDistance / tickSize * tickValue; // ضرر یک لات اگر SL بخورد
double lots = riskMoney / lossPerLot;
const double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
const double minL = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
const double maxL = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
lots = MathFloor(lots / step) * step; // همیشه رو به پایین
if(lots < minL) return 0.0; // معامله نکن
return MathMin(lots, maxL);
}قاعده دوم: حد ضرر بر اساس نوسان (ATR)
حد ضرر ثابت (مثلاً همیشه ۵ دلار) در روزهای آرام بازار زیادی دور است و در روزهای پرنوسان زیادی نزدیک و با نویز عادی قیمت میخورد. ATR (میانگین دامنه واقعی) نشان میدهد قیمت در دوره اخیر بهطور معمول چقدر حرکت میکند. حد ضرر را مضربی از ATR بگذارید (مثلاً ۱٫۵ یا ۲ برابر ATR چهارده دورهای) تا با شرایط بازار تنظیم شود.
ترکیب این قاعده با قاعده اول جالب است: وقتی بازار پرنوسان است، ATR و فاصله حد ضرر بزرگتر میشوند و در نتیجه حجم کوچکتر. یعنی ربات خودبهخود در شرایط پرنوسان محتاطتر میشود، بدون اینکه قاعده جداگانهای برایش بنویسید.
قاعده سوم: توقف روزانه و سقف ریسک همزمان
حتی با ریسک کوچک در هر معامله، یک روز بد با ده معامله ضررده میتواند آسیب جدی بزند. دو سقف دیگر هم لازم است:
توقف روزانه: اگر افت موجودی امروز از حد مشخصی گذشت (مثلاً چند برابر ریسک یک معامله)، ربات تا روز بعد معامله جدید باز نکند. این قاعده جلوی روزهایی را میگیرد که شرایط بازار با فرضهای استراتژی جور نیست.
سقف ریسک باز: مجموع ریسک همه معاملههای باز همزمان نباید از حد مشخصی بیشتر شود. پنج معامله همجهت روی طلا، عملاً یک معامله بزرگ است.
نکات کلیدی
- افت روزانه بیش از حد → توقف تا روز بعد.
- مجموع ریسک معاملههای باز سقف دارد.
- حد ضرر هر معامله در لحظه ورود ثبت میشود و فقط به سمت کاهش ریسک جابهجا میشود.
بکتست: خطاهایی که نتیجه را زیادی خوب نشان میدهند
هر استراتژی را قبل از اجرای زنده روی داده تاریخی آزمایش میکنم، اما بکتست بهراحتی گمراه میکند. سه خطای رایج:
۱. بیشبرازش (Overfitting): اگر پارامترها را آنقدر تنظیم کنید که روی داده گذشته بهترین نتیجه را بدهد، احتمالاً استراتژیای ساختهاید که فقط گذشته را حفظ کرده. بخشی از داده را کنار بگذارید و فقط در پایان، روی آن آزمایش کنید (یا از روش walk-forward استفاده کنید).
۲. هزینههای واقعی: اسپرد، کمیسیون و لغزش قیمت (slippage) در بکتست باید واقعبینانه باشند. روی طلا، بهخصوص هنگام خبرها، اسپرد میتواند چند برابر حالت عادی شود.
۳. نگاه به آینده (Look-ahead): استفاده از دادهای که در لحظه تصمیم هنوز وجود نداشته؛ مثلاً قیمت بسته شدن کندلی که هنوز تمام نشده. در MQL5 یعنی سیگنال را روی کندل بستهشده (شاخص ۱) حساب کنید، نه کندل جاری.
بعد از بکتست هم، اجرای چند هفتهای روی حساب آزمایشی (دمو) با همان بروکر، تفاوتهای اجرای واقعی را نشان میدهد.
جمعبندی
قوانین ریسک از سیگنال ورود مهمترند: ریسک ثابت به درصد موجودی، حجم محاسبهشده از فاصله حد ضرر با مشخصات واقعی نماد، حد ضرر بر پایه ATR، توقف روزانه و سقف ریسک همزمان. بکتست را با هزینههای واقعی و داده کنار گذاشته انجام دهید و به نتیجهای که زیادی خوب است مشکوک باشید. این قواعد در رباتهای معاملات الگوریتمی من پیاده شدهاند؛ هیچکدام سود را تضمین نمیکنند، اما جلوی ضررهایی را میگیرند که از بیانضباطی میآیند.