اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی
بازدید 140

اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

در دنیای پویا و متغیر بازارهای مالی، معامله‌گران و تحلیل‌گران همواره به دنبال راه‌های جدید و خلاقانه‌ای برای کسب برتری هستند. این مقاله به بررسی روشی نوین در معاملات خودکار می‌پردازد که توانایی پیش‌بینی یادگیری عمیق (Deep Learning) را با قدرت تحلیل تکنیکال سنتی ترکیب کرده است. هدف این روش، توسعه یک تکنیک معاملاتی پایدار و انعطاف‌پذیر است که قادر به مدیریت پیچیدگی‌های بازارهای معاصر باشد. ترکیب مدل پیچیده حافظه کوتاه‌مدت شرطی (Conditional LSTM) با یک اندیکاتور تکنیکال به نام مومنتوم تنظیم‌شده بر اساس نوسان (Volatility Adjusted Momentum – VAM)، به ما این امکان را می‌دهد تا به این هدف دست یابیم. 📊✨

استفاده از اندیکاتورهای تکنیکال و یادگیری عمیق

اندیکاتورهای تکنیکال مدت‌هاست که در صنعت مالی برای شناسایی روندها و فرصت‌های معاملاتی استفاده می‌شوند. اما در مواقع نوسانات شدید یا تغییرات ناگهانی، این اندیکاتورها ممکن است به‌خوبی از پس پیچیدگی‌های دینامیک بازار برنیایند. در همین راستا، معماری‌های یادگیری عمیق مانند LSTM نشان داده‌اند که در پیش‌بینی الگوهای پیچیده و داده‌های وابسته به زمان عملکرد بسیار خوبی دارند، اما معمولاً از نظر قابلیت تفسیر و شناخت مسائل خاص بازار به‌اندازه تحلیل تکنیکال مؤثر نیستند.

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

شبکه عصبی حافظه کوتاه‌مدت شرطی (Conditional LSTM)

برای بهبود عملکرد اندیکاتور VAM، از مدل LSTM شرطی استفاده می‌کنیم که نوعی شبکه عصبی بازگشتی (Recurrent Neural Network – RNN) است و برای پردازش داده‌های دنباله‌دار با اطلاعات زمینه‌ای طراحی شده است. این مدل که با استفاده از داده‌های تاریخی قیمت و اندیکاتورهای تکنیکال آموزش داده شده، قادر به شناسایی ارتباطات پیچیده و غیرخطی در بازار است که روش‌های تحلیل سنتی ممکن است از شناسایی آن‌ها ناتوان باشند.

برای مشاوره و  طراحی اکسپرت، اندیکاتور یا ربات های معامله گر می توانید با کارشناسان ما تماس بگیرید ، ما همواره پاسخگو شما خواهیم بود.شماره تماس پشتیبانی سایت هوش فعال : 09364549266

🧠 ویژگی “شرطی” در LSTM این امکان را می‌دهد که مدل بتواند متغیرهای بیشتری را در بازار در نظر بگیرد، که منجر به پیش‌بینی‌های دقیق‌تر و آگاهانه‌تر می‌شود.

مشاور خبره (Expert Advisor – EA)

مشاور خبره (EA) که در این استراتژی به کار رفته است، یک سیستم معاملاتی خودکار است که اندیکاتور VAM را با پیش‌بینی‌های مدل LSTM ترکیب می‌کند. این EA در پلتفرم محبوب MetaTrader 5 ادغام شده است و با استفاده از سیگنال‌های هر دو بخش، به معامله‌گران در تصمیم‌گیری‌های هوشمند کمک می‌کند. همچنین، این EA دارای قابلیت‌های مدیریت ریسک پویا است که با توجه به تغییرات بازار، سطوح توقف ضرر (Stop Loss) و حد سود (Take Profit) را تنظیم می‌کند. 📈💼

مراحل پیاده‌سازی

در این مقاله، به بررسی پایه‌های نظری مدل‌های LSTM شرطی و اندیکاتور VAM می‌پردازیم و نشان می‌دهیم که چگونه این دو به بهترین شکل با هم همکاری می‌کنند. در هر مرحله از ساخت و پیاده‌سازی EA، از جمله تنظیم داده‌ها، آموزش مدل و ادغام آن در محیط MetaTrader 5، توضیحاتی ارائه خواهد شد.

💡 همچنین، نتایج بهینه‌سازی و آزمون‌های پشتیبان (Backtesting) را ارائه می‌دهیم و عملکرد استراتژی VAM به تنهایی را با استراتژی ترکیبی VAM و LSTM مقایسه خواهیم کرد.

نتایج و چالش‌ها

در این مقاله، چالش‌ها و نکات مرتبط با ترکیب روش‌های پیشرفته یادگیری ماشین (Machine Learning) با تحلیل تکنیکال سنتی مورد بحث قرار می‌گیرد. هدف ما ارائه یک دید جامع از جنبه‌های عملیاتی پیاده‌سازی این سیستم است، از کیفیت داده‌ها و تفسیر مدل گرفته تا الزامات محاسباتی برای اجرای مدل‌های پیچیده در شرایط واقعی معاملات.

🔚 در پایان این مقاله، خوانندگان درک جامعی از نحوه استفاده از تکنیک‌های پیشرفته یادگیری ماشین برای بهبود تحلیل تکنیکال و نتایج معاملاتی به دست خواهند آورد. این بررسی از VAM و LSTM در معاملات خودکار، اطلاعات ارزشمندی درباره آینده معاملات الگوریتمی ارائه می‌دهد، خواه شما یک معامله‌گر، دانشمند داده یا محقق حوزه مالی باشید.

مومنتوم تنظیم‌شده بر اساس نوسان (Volatility Adjusted Momentum – VAM)

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

مدل یادگیری عمیق (Deep Learning Model)

در این مقاله، از مدل LSTM شرطی استفاده شده است که نوعی RNN مناسب برای داده‌های سری زمانی مالی است. این مدل با استفاده از داده‌های تاریخی قیمت و اندیکاتورهای تکنیکال (مانند MACD) به عنوان ورودی، حرکات قیمت آینده را پیش‌بینی می‌کند. مزیت LSTM شرطی در توانایی آن برای شناسایی روابط پیچیده میان عوامل مختلف بازار است.

مشاور خبره (EA)

در این مقاله به ساخت یک EA که پیش‌بینی‌های مدل یادگیری عمیق را با VAM ترکیب می‌کند، پرداخته شده است. ویژگی‌های اصلی EA به‌صورت خلاصه در زیر آمده است:

  • راه‌اندازی: EA پارامترهای ورودی و خروجی مدل یادگیری عمیق ONNX از پیش آموزش‌دیده را بارگذاری و پیکربندی می‌کند.
  • جمع‌آوری و نرمال‌سازی داده‌ها: EA مقادیر MACD و داده‌های قیمت قبلی را جمع‌آوری کرده و آن‌ها را قبل از ورود به مدل یادگیری عمیق نرمال‌سازی می‌کند.
  • محاسبه VAM: EA با استفاده از داده‌های قیمت فعلی و تاریخی، اندیکاتور VAM را محاسبه می‌کند.
  • منطق معاملاتی و پیش‌بینی: EA پیش‌بینی قیمت را از مدل یادگیری عمیق دریافت می‌کند و آن را با مقدار VAM ترکیب می‌کند:
    • اگر VAM بالا باشد و پیش‌بینی نشان‌دهنده افزایش قیمت باشد، EA یک معامله خرید باز می‌کند. 🟢💹
    • اگر VAM پایین باشد و پیش‌بینی نشان‌دهنده کاهش قیمت باشد، EA یک معامله فروش باز می‌کند. 🔴📉
  • مدیریت ریسک: EA با تعیین پویا سطوح توقف ضرر و حد سود بر اساس میانگین محدوده واقعی (ATR)، ریسک را مدیریت می‌کند.

ایجاد یک اندیکاتور جدید (VAM)

اگر بخواهیم یک اندیکاتور جدید ایجاد کنیم، به‌عنوان مثال این اندیکاتور:

// Calcular Momentum
   double momentum = close_price - iClose(NULL, 0, momentum_period);

// Calcular Volatilidad
   double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE);

// Calcular VAM
   double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000;

 

ما از مومنتوم (Momentum) و نوسان (Volatility) برای ایجاد یک اندیکاتور جدید به نام VAM استفاده خواهیم کرد.

مومنتوم بر حاصل‌ضرب ریشه مربع دوره مومنتوم و نوسان تقسیم می‌شود.

برای اهداف مقیاس‌بندی، نتیجه سپس در ۱۰٬۰۰۰ ضرب می‌شود.

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

یک مقدار مثبت VAM نشان‌دهنده مومنتوم صعودی است، در حالی که مقدار منفی نشان‌دهنده مومنتوم نزولی است. اندازه VAM قدرت مومنتوم را با توجه به نوسان اخیر بازار نشان می‌دهد.

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

با استفاده از این اندیکاتور به تنهایی، می‌توانیم یک مشاور خبره (EA) ایجاد کرده و بررسی کنیم که آیا این استراتژی سودآور است یا خیر.

استراتژی پیشنهادی 📈🔍

در ادامه، استراتژی استفاده از این اندیکاتور را شرح خواهیم داد:

void OnTick()
  {
   int bars = iBars(NULL, 0);
   if(bars < MathMax(momentum_period, MathMax(volatility_period, (vam_period))))//, MathMax(ma_long_period, rsi_period)))))
      return;

   double close_price = iClose(NULL, 0, 0);

// Calcular Momentum
   double momentum = close_price - iClose(NULL, 0, momentum_period);

// Calcular Volatilidad
   double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE);

// Calcular VAM
   double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000;


   double atr = iATR(_Symbol,PERIOD_CURRENT,14)*_Point;
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double slPriceBuy = NormalizeDouble(Bid - slmul*atr,_Digits);
   double tpPriceBuy = NormalizeDouble(Ask + tpmul*atr,_Digits);
   double slPriceSell = NormalizeDouble(Ask + slmul*atr,_Digits);
   double tpPriceSell = NormalizeDouble(Bid - tpmul*atr,_Digits);

// Señales
   if(vam > VAMTHRESH)// && ma_short > ma_long)// && rsi < 70 && ma_short > ma_long )
     {
      // Comprar
      trade.Buy(lot_size,_Symbol,   Ask, slPriceBuy, tpPriceBuy, " BUY EA ");
     }
   else
      if(vam < -VAMTHRESH)// && ma_short < ma_long)// rsi > 30 && ma_short < ma_long )
        {
         // Vender
         trade.Sell(lot_size,_Symbol,   Bid, slPriceSell, tpPriceSell, " SELL EA ");
        }
  }

 

تابع iBars(NULL, 0) تعداد کل میله‌های (bars) موجود برای نماد و تایم‌فریم مشخص را برمی‌گرداند.

int bars: مقدار بازگشتی، که نشان‌دهنده تعداد کل میله‌ها است، در متغیر bars ذخیره می‌شود.

MathMax: این تابع، بیشترین مقدار از بین اعداد ارائه‌شده را برمی‌گرداند. در این مورد، به‌صورت تو در تو برای تعیین بیشینه در دوره‌های زمانی مختلف استفاده می‌شود.

متغیرهای momentum_period، volatility_period،

 vam_period، ma_long_period، و rsi_period که قبلاً تعریف شده‌اند، نشان‌دهنده دوره‌های زمانی مختلف برای اندیکاتورها یا محاسبات مختلف هستند.

If: این شرط بررسی می‌کند که آیا تعداد کل میله‌ها کمتر از مجموع دوره‌های زمانی تعیین‌شده است یا خیر.

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

نتایج VAM 📊

نتایج به این صورت بودند (پس از بهینه‌سازی سریع که هنوز کامل نشده است):

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

این استراتژی و اندیکاتور ساده به نظر مناسب می‌آیند. 🌟

بیایید ببینیم اگر از یک مدل یادگیری عمیق (Deep Learning) برای این کار استفاده کنیم چه نتیجه‌ای می‌توانیم بگیریم. اما امروز قرار است کاری متفاوت انجام دهیم: قصد داریم یک مدل یادگیری عمیق با چند اندیکاتور ایجاد کنیم تا ببینیم کدام بهتر عمل می‌کند.

مدل‌های یادگیری عمیق 🤖✨

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

برای انجام همه این کارها، از Google Colab استفاده می‌کنیم (تا منابع رایانه شخصی خود را مصرف نکنیم) با اسکریپت پایتونی که به آن ضمیمه شده است.

از آنجا که این وب‌سایت مربوط به MQL5 است، توضیح کد پایتون را نخواهم داد.

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

نتایج گرافیکی از اولین اسکریپت 📈

 

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی  اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی  اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی  اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی  اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 

زمانی که تصمیم گرفتیم از MACD استفاده کنیم، اسکریپت را آماده کرده و تاریخ‌ها را برای اول ژانویه ۲۰۲۴ تنظیم کردیم (تا بتوانیم از اول ژانویه ۲۰۲۴ به بعد، نتایج را در MQL5 بک‌تست کنیم).

نتایج از اسکریپت دوم 📊

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

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

مدل Conditional LSTM (همان‌طور که در اسکریپت پایتون اجرا شده) به صورت زیر است:

Conditional LSTM چیست؟

نسخه پیشرفته‌ای از شبکه عصبی Long Short-Term Memory است که بهبودهایی با افزودن داده‌های زمینه‌ای یا شرایط بیشتر به فرآیند پیش‌بینی LSTM ارائه می‌دهد. این مدل به دلیل توانایی ترکیب چندین متغیر و داده‌های پیچیده بازار برای پیش‌بینی در بازارهای مالی، مخصوصاً بازارهای سهام و فارکس، بسیار جذاب است.

Conditional LSTM می‌تواند ترکیبی از داده‌های قیمت گذشته و متغیرهای خارجی و اندیکاتورهای مختلف بازار مانند RSI یا Moving Averages را در نظر بگیرد تا تصویری جامع‌تر از دینامیک بازار ارائه دهد. این ویژگی، آگاهی از زمینه (Contextual Awareness) را به مدل اضافه می‌کند که در بازارهای مالی که عوامل متعددی بر تغییرات قیمت تأثیرگذار هستند، بسیار مفید است.

مزایا و چالش‌ها

یکی از مزایای اصلی استفاده از Conditional LSTM توانایی آن در کشف روابط پیچیده بین چندین دینامیک بازار است. این مدل می‌تواند وابستگی‌های طولانی‌مدت را در داده‌های سری زمانی ثبت کند که در بازارهای مالی که الگوهای بلندمدت ممکن است ظاهر شوند، اهمیت دارد.

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

از طرف دیگر، کیفیت و ارتباط داده‌ها در Conditional LSTM بسیار حائز اهمیت است؛ این مدل نیاز به داده‌های با کیفیت و شاخص‌های دقیق دارد. همچنین یکی دیگر از مشکلات، تفسیرپذیری این مدل است؛ حتی اگر پیش‌بینی‌های دقیقی داشته باشد، درک دلیل آن‌ها ممکن است دشوار باشد. این ویژگی ‘جعبه سیاه’ می‌تواند در کاربردهای مالی که شفافیت اهمیت دارد، مشکل‌ساز شود.

کاربرد در پیش‌بینی بازارهای مالی

به‌رغم این چالش‌ها، Conditional LSTM پتانسیل جذابی برای پیش‌بینی مبتنی بر اندیکاتور در بازارهای مالی دارد. با استفاده از داده‌های چندوجهی پیچیده، این مدل می‌تواند پیش‌بینی‌های دقیق‌تر و نوانس‌دارتر داشته باشد. اما به دلیل چالش‌های پیچیدگی، نیازهای داده، و طبیعت غیرقابل پیش‌بینی بازارهای مالی، بهتر است Conditional LSTM به عنوان بخشی از یک رویکرد تحلیلی جامع‌تر استفاده شود.

این مدل نیاز به آزمون‌های فراوان و بررسی محدودیت‌های آن در شرایط عملی دارد تا بتوان از آن در معاملات مالی با ریسک بالا استفاده کرد.

📊 نمودار ساختار مدل Conditional LSTM

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

📥 ورودی‌ها و 📤 خروجی‌های مدل Conditional LSTM

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

این مشاور متخصص (EA) هدف اصلی‌اش خودکارسازی تصمیمات تجاری بر اساس ترکیبی از شاخص‌های فنی و پیش‌بینی‌های یک مدل یادگیری عمیق (ONNX) است. این EA از شاخص «مومنتوم تعدیل‌شده با نوسان» (VAM) و MACD (همگرایی و واگرایی میانگین متحرک) استفاده می‌کند و به همراه پیش‌بینی‌های قیمتی که توسط یک مدل یادگیری ماشین ارائه می‌شود، معاملات را انجام می‌دهد.

این EA با تعریف چندین ویژگی و کتابخانه آغاز می‌شود. کلاس CTrade برای اجرای معاملات گنجانده شده است و دیگر هدرها برای توابع آماری و مدیریت آرایه‌ها وجود دارد. پارامترهای ورودی برای محاسبات VAM و اجرای معاملات، مانند momentum_period، volatility_period و vam_period تعریف شده‌اند که برای کنترل منطق محاسبه مومنتوم و نوسان استفاده می‌شوند. پارامترهای معاملاتی مانند lot_size و ضریب‌های توقف ضرر (slmul) و برداشت سود (tpmul) نیز در اینجا تعریف شده‌اند که انعطاف‌پذیری بیشتری به رفتار EA می‌دهد. علاوه بر این، ثابت‌هایی که پارامترهای مدل ONNX را تعریف می‌کنند، مانند BATCH_SIZE، SEQUENCE_LENGTH و سایر موارد، برای مدیریت چگونگی ارسال داده‌ها به مدل یادگیری عمیق گنجانده شده‌اند.

//+------------------------------------------------------------------+
//|                                                      VAM + DL(MACD) EA |
//|                                      Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera |
//|                                       https://www.mql5.com/en/users/jsgaston/news |
//+------------------------------------------------------------------+
#property copyright "Javier Santiago Gaston de Iriarte Cabrera"
#property link      "https://www.mql5.com/en/users/jsgaston/news"
#property version   "1.01"


#include <Trade\Trade.mqh>
#include <Math\Stat\Math.mqh>
#include <Arrays\ArrayFloat.mqh>

CTrade trade;

// Inputs
input int momentum_period = 13;
input int volatility_period = 7;
input int vam_period = 9;
input double lot_size = 0.01;
input int slippage = 3;
input double VAMTHRESH = 9.0;
input int slmul = 2;
input int tpmul = 4;

// ONNX model parameters
#define BATCH_SIZE 1
#define SEQUENCE_LENGTH 30
#define INPUT_FEATURES 3
#define CONDITION_FEATURES 2
#define HIDDEN_DIM 128
#define NUM_LAYERS 2

float input_x[][SEQUENCE_LENGTH][INPUT_FEATURES];
float input_condition[][CONDITION_FEATURES];
float h0[][BATCH_SIZE][HIDDEN_DIM];
float c0[][BATCH_SIZE][HIDDEN_DIM];

#define PRICE_UP   0
#define PRICE_SAME 1
#define PRICE_DOWN 2

long ExtHandle = INVALID_HANDLE;
int ExtPredictedClass = -1;
datetime ExtNextBar = 0;
datetime ExtNextDay = 0;
float ExtMin = 0.0;
float ExtMax = 1.0;  // Initialize to 1.0 to prevent division by zero
float predicted_last;

#resource "/Files/stock_prediction_model_MACD.onnx" as uchar ExtModel[]

 

تابع اولیه‌سازی OnInit() اهمیت زیادی دارد زیرا مدل ONNX را از یک منبع باینری (stock_prediction_model_MACD.onnx) بارگذاری می‌کند و شکل‌های ورودی و خروجی مدل را تنظیم می‌کند. ورودی مدل ONNX شامل داده‌های قیمتی تاریخی، مقادیر MACD و وضعیت‌های پنهان و سلولی اولیه (h0 و c0) برای لایه‌های تکراری مدل است. اگر مدل با موفقیت بارگذاری شود، این تابع همچنین حداقل و حداکثر مقادیر قیمتی (ExtMin و ExtMax) را که برای نرمال‌سازی داده‌های ورودی به مدل ONNX استفاده می‌شوند، راه‌اندازی می‌کند. در صورت بروز هرگونه خطا در هنگام بارگذاری مدل، این تابع مقدار INIT_FAILED را برمی‌گرداند که به طور مؤثر فعالیت EA را متوقف می‌کند.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   Print("BATCH_SIZE: ", BATCH_SIZE, ", CONDITION_FEATURES: ", CONDITION_FEATURES);
   ExtHandle = OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(ExtHandle == INVALID_HANDLE)
     {
      Print("OnnxCreateFromBuffer error ", GetLastError());
      return(INIT_FAILED);
     }

// Set input shapes
   long input_shape[] = {BATCH_SIZE, SEQUENCE_LENGTH, INPUT_FEATURES};
   if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape))
     {
      Print("OnnxSetInputShape for input_x error ", GetLastError());
      return(INIT_FAILED);
     }

   long condition_shape[] = {BATCH_SIZE,CONDITION_FEATURES};
   if(!OnnxSetInputShape(ExtHandle, 1, condition_shape))
     {
      Print("OnnxSetInputShape for input_condition error ", GetLastError());
      return(INIT_FAILED);
     }

   long h0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM};
   if(!OnnxSetInputShape(ExtHandle, 2, h0_shape))
     {
      Print("OnnxSetInputShape for h0 error ", GetLastError());
      return(INIT_FAILED);
     }

   long c0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM};
   if(!OnnxSetInputShape(ExtHandle, 3, c0_shape))
     {
      Print("OnnxSetInputShape for c0 error ", GetLastError());
      return(INIT_FAILED);
     }



   const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }

// Initialize ExtMin and ExtMax
   GetMinMax();

   Print("Initializing EA with VAM and ONNX integration");
   return(INIT_SUCCEEDED);
  }

 

تابع OnTick() منطق اصلی است که در هر تغییر قیمت اجرا می‌شود. این تابع ابتدا بررسی می‌کند که آیا روز جدیدی آغاز شده و قیمت‌های حداقل و حداکثر را با استفاده از تابع GetMinMax() به‌روزرسانی می‌کند. بخش بعدی تضمین می‌کند که تابع تنها در صورت موجود بودن یک میله قیمتی جدید ادامه یابد. سپس EA متغیرهای ExtMin و ExtMax را به آخرین مقادیر قیمتی به‌روز می‌کند. قلب این تابع ترکیب محاسبه VAM و پیش‌بینی ONNX است. VAM با گرفتن تفاوت قیمت (حرکت) و تقسیم آن بر حاصل‌ضرب نوسانات و جذر momentum_period محاسبه می‌شود و در نهایت به ۱۰,۰۰۰ مقیاس می‌شود. اگر VAM از یک آستانه خاص (VAMTHRESH) عبور کند، این نشان‌دهنده یک روند قوی در بازار است و سیگنالی برای معامله بالقوه فراهم می‌آورد.

سپس EA نتایج پیش‌بینی و VAM را ترکیب می‌کند. اگر VAM بالا باشد (بیشتر از VAMTHRESH) و مدل ONNX پیش‌بینی افزایش قیمت کند، EA یک معامله خرید با توقف ضرر و سود هدف محاسبه‌شده بر اساس محدوده واقعی متوسط (ATR) باز می‌کند. به‌طور مشابه، اگر VAM پایین باشد (زیر منفی VAMTHRESH) و مدل ONNX پیش‌بینی کاهش قیمت کند، EA یک معامله فروش باز می‌کند. این معاملات با استفاده از کلاس CTrade که با توابع معاملاتی پلتفرم MetaTrader 5 تعامل دارد، اجرا می‌شوند.

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

void OnTick()
  {
// Check for new day and update ExtMin and ExtMax
   if(TimeCurrent() >= ExtNextDay)
     {
      GetMinMax();
      ExtNextDay = TimeCurrent() - TimeCurrent() % PeriodSeconds(PERIOD_D1) + PeriodSeconds(PERIOD_D1);
     }

// Check for new bar
   if(TimeCurrent() < ExtNextBar)
      return;
   ExtNextBar = TimeCurrent() - TimeCurrent() % PeriodSeconds() + PeriodSeconds();

// Update ExtMin and ExtMax
   double close = iClose(_Symbol, _Period, 0);
   if(ExtMin > close)
      ExtMin = (float)close;
   if(ExtMax < close)
      ExtMax = (float)close;

   int bars = iBars(_Symbol, PERIOD_CURRENT);
   if(bars < MathMax(momentum_period, MathMax(volatility_period, MathMax(vam_period, SEQUENCE_LENGTH))))
      return;

// Calculate VAM
   double momentum = close - iClose(_Symbol, PERIOD_CURRENT, momentum_period);
   double volatility = iStdDev(_Symbol, PERIOD_CURRENT, volatility_period, 0, MODE_SMA, PRICE_CLOSE);
   double vam = (momentum / (volatility * MathSqrt(momentum_period))) * 10000;
   Print("VAM ", vam);

// Get ONNX prediction
   int result=GetPrediction();

// Trading logic combining VAM and ONNX prediction
   double atr = iATR(_Symbol, PERIOD_CURRENT, 14)*_Point;
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double slPriceBuy = NormalizeDouble(Bid - slmul * atr, _Digits);
   double tpPriceBuy = NormalizeDouble(Ask + tpmul * atr, _Digits);
   double slPriceSell = NormalizeDouble(Ask + slmul * atr, _Digits);
   double tpPriceSell = NormalizeDouble(Bid - tpmul * atr, _Digits);
   
   //Print(result);

   if(vam > VAMTHRESH && result == 0)
     {
      trade.Buy(lot_size, _Symbol, Ask, slPriceBuy, tpPriceBuy, "BUY VAM+ONNX");
     }
   else
      if(vam < -VAMTHRESH && result == 2)
        {
         trade.Sell(lot_size, _Symbol, Bid, slPriceSell, tpPriceSell, "SELL VAM+ONNX");
        }
  }

 

پیش‌بینی مدل ONNX با فراخوانی تابع GetPrediction() به‌دست می‌آید. ورودی مدل با استفاده از تابع PrepareInputs() آماده می‌شود که قیمت‌های بسته تاریخی و داده‌های MACD را جمع‌آوری کرده، آن‌ها را با استفاده از دامنه قیمت (ExtMin و ExtMax) نرمالیزه کرده و آرایه‌های ورودی مورد انتظار مدل را پر می‌کند. این تابع داده‌ها را برای توالی قیمت ورودی (input_x) و شرایط مبتنی بر MACD (input_condition) تنظیم می‌کند و در عین حال حالت‌های پنهان (h0c0) را بازنشانی می‌کند.

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

void PrepareInputs()
  {
   ArrayResize(input_x, BATCH_SIZE);
   ArrayResize(input_condition, BATCH_SIZE);
   ArrayResize(h0, NUM_LAYERS);
   ArrayResize(c0, NUM_LAYERS);

   for(int i = 0; i < SEQUENCE_LENGTH; i++)
     {
      input_x[0][i][0] = (float)((iClose(_Symbol, PERIOD_CURRENT, i) - ExtMin) / (ExtMax - ExtMin));

      double macd_main[], macd_signal[];
      int macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
      CopyBuffer(macd_handle, 0, i, 1, macd_main);
      CopyBuffer(macd_handle, 1, i, 1, macd_signal);
      input_x[0][i][1] = (float)((macd_main[0] - ExtMin) / (ExtMax - ExtMin));
      input_x[0][i][2] = (float)((macd_signal[0] - ExtMin) / (ExtMax - ExtMin));
     }

   double macd_main2[], macd_signal2[];
   int macd_handle2 = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
   CopyBuffer(macd_handle2, 0, 0, 1, macd_main2);
   CopyBuffer(macd_handle2, 1, 0, 1, macd_signal2);
   input_condition[0][0] = (float)macd_main2[0];
   input_condition[0][1] = (float)macd_signal2[0];

   ArrayInitialize(h0, 0.0f);
   ArrayInitialize(c0, 0.0f);
  }
//+------------------------------------------------------------------+
//| Get prediction from ONNX model                                   |
//+------------------------------------------------------------------+
int GetPrediction()
  {
   PrepareInputs();
   

   float output_data[];
   ArrayResize(output_data, 1);

// Run the ONNX model
   if(!OnnxRun(ExtHandle,
               ONNX_NO_CONVERSION,
               input_x,
               input_condition,
               h0,
               c0,
               output_data))
     {
      Print("OnnxRun error: ", GetLastError());
      return ExtPredictedClass = -1;
     }

   float predicted=output_data[0]*(ExtMax-ExtMin)+ExtMin;
   Print("Predicted last ", predicted_last);
   Print("Predicted ",predicted);
   float last_close = (float)iClose(_Symbol, PERIOD_CURRENT, 0);
   Print("last close ",last_close);
   float delta = predicted_last - predicted;
   predicted_last=predicted;
   Print("Delta ",delta);

   if(MathAbs(delta) <= 0.00001)
      ExtPredictedClass = PRICE_SAME;
   else
      if(delta < 0)
         ExtPredictedClass = PRICE_UP;
      else
         ExtPredictedClass = PRICE_DOWN;
   Print(ExtPredictedClass);

   return ExtPredictedClass;
   
  }

 

تابع GetMinMax() مسئول تعیین مقادیر حداقل (ExtMin) و حداکثر (ExtMax) قیمت‌ها در روز گذشته است. این مقادیر برای نرمال‌سازی ورودی‌ها قبل از ارسال به مدل ONNX استفاده می‌شوند تا اطمینان حاصل شود که مدل ورودی‌ها را در یک دامنه ثابت دریافت می‌کند. اگر EA نتواند داده‌های قیمت لازم را به‌دست آورد، به یک دامنه ایمن پیش‌فرض برمی‌گردد تا از تقسیم بر صفر جلوگیری کند.

void GetMinMax()
  {
   double close[];
   int copied = CopyClose(_Symbol, PERIOD_D1, 0, SEQUENCE_LENGTH, close);

   if(copied > 0)
     {
      ExtMin = (float)MathMin(close);
      ExtMax = (float)MathMax(close);
     }
   else
     {
      Print("Failed to copy price data. Error: ", GetLastError());
      ExtMin = 0;
      ExtMax = 1;  // Prevent division by zero
     }
  }

 

در نهایت، EA شامل تابع غیرفعال‌سازی OnDeinit() است که در زمان حذف EA، دسته مدل ONNX را آزاد می‌کند. این کار اطمینان حاصل می‌کند که حافظه به‌درستی مدیریت می‌شود و از نشت منابع جلوگیری می‌شود.

void OnDeinit(const int reason)
  {
   if(ExtHandle != INVALID_HANDLE)
     {
      OnnxRelease(ExtHandle);
      ExtHandle = INVALID_HANDLE;
     }
  }

 

به طور خلاصه، این EA تجزیه و تحلیل فنی (از طریق VAM و MACD) را با پیش‌بینی‌های یادگیری ماشین از یک مدل ONNX ترکیب می‌کند تا تصمیمات تجاری خودکار و مبتنی بر اطلاعات اتخاذ کند. تجزیه و تحلیل فنی به شناسایی روندها کمک می‌کند، در حالی که مدل یادگیری ماشین حرکت قیمت را پیش‌بینی می‌کند و در نتیجه یک استراتژی ترکیبی به وجود می‌آورد.

نتایج

پس از بهینه‌سازی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

 اندیکاتور Conditional LSTM شبکه عصبی حافظه کوتاه‌مدت شرطی

نتیجه‌گیری

این مقاله به بررسی ادغام یادگیری عمیق، به‌ویژه مدل‌های Conditional LSTM، با شاخص Volatility Adjusted Momentum (VAM) برای بهبود سیستم‌های تجارت خودکار می‌پردازد. با ترکیب قابلیت‌های پیش‌بینی LSTM و تحلیل مومنتوم حساس به نوسانات VAM، این استراتژی به دنبال ضبط دینامیک‌های پیچیده بازار است. این سیستم که بر روی MetaTrader 5 پیاده‌سازی شده است، سیگنال‌های معاملاتی تولید کرده و مدیریت ریسک را به‌صورت پویا تنظیم می‌کند.

نتایج تست مجدد (Backtesting) نشان‌دهنده بهبود نتایج زمانی است که LSTM با VAM ترکیب می‌شود. با وجود چالش‌هایی مانند بیش‌برازش و نیازهای محاسباتی، این مطالعه نشان می‌دهد که ادغام یادگیری عمیق با تحلیل تکنیکال می‌تواند به‌طور قابل توجهی استراتژی‌های معاملاتی الگوریتمی را بهبود بخشد.

فایل های دانلود این پروژه

Example of new Indicator and Conditional LSTM

نظرات کاربران

دیدگاهتان را بنویسید

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