
چگونه کد یک اکسپرت را کات کنیم تا زندگی آسودهتر و خطاهای کمتری داشته باشیم
سیستمهای ترید زیادی بر اساس تحلیل تکنیکال وجود دارند که یا اندیکاتور هستند یا طرحهای گرافیکی، که یک ویژگی مهم دارند. منظورم تقارن و همانند بودن چنین سیستمهایی در جهتِ معامله است. با توجه به این ویژگی، سیگنالهای ترید و مکانیزم درج معاملات در چنین سیستمهایی را بهطور کلی میتوان بهنسبتِ جهتِ آنها بیان کرد.
رویکرد سادهای که در ادامه آورده شدهاست، به ما اجازه میدهد از این ویژگی بهشکل موثر استفاده کنیم تا بهطرز چشمگیری طولِ کد اکسپرتها را، برمبنای چنین سیستمهای متقارنی، کاهش دهیم. اکسپرتهایی که از این رویکرد استفاده میکنند، از همین کد برای شناسایی سیگنالهای ترید و تولید معامله، هم برای پوزیشنهای بلندمدت و هم برای کوتاهمدتها، بهره میبرند.
در بحث توسعهی اکسپرتها بر اساس سیستمهای متقارن ، رایج است که فرد ابتدا، تولید و پردازش کدهای مربوط به سیگنالهای ترید در یک جهت را انجام داده، و سپس همان کد را کپی کرده و برای جهت دیگر، آن را اصلاح کند. در این شرایط اما خطا کردن چه آسان و شناسایی و رفع خطا چه مشکل خواهد بود… پس، کاهش خطاهای ممکن در منطق اکسپرت، دیگر خصوصیت خوبِ رویکرد مدنظر ما است.
- تعبیههای ثابت اکسپرت با توجه به جهت معامله
مفهومی که مدنظر ماست، بر اساس جهت معامله است. این جهت ممکن است بلندمدت باشد (سیگنالهای خرید و معاملات)، یا کوتاهمدت باشد (سیگنالهای فروش و معاملات). هدف ما، نوشتن اکسپرتها، به سبکی است که کد آنها با توجه به جهت معاملهی کنونی، نامتغیر است. برای جلوگیری از ارائهی توضیحات اضافه در متن، این کد را نامتغیر میخوانیم، با درنظر گرفتن اینکه این کد فقط نسبت به جهت معامله، نامتغیر است.
برای این کار، یک تابع یا یک متغیر وارد میکنیم، که مقدار آن همیشه جهت معاملهی کنونی را، با یک یا دو مقدار مقدور، نشان میدهد.
ارائهی این متغیر در این کد جنبهی بسیار مهمی دارد. هرچند بهنظر میرسد نوع منطقی [متغیرها] مناسب این مدل اهداف هستند، اما کمی تفاوت داشتن در نحوهی ارائه، یعنی [ارائه با متغیر از نوع] عددصحیح، تاثیرگذارتر است. جهت خودِ معامله را اینگونه کددهی میکنیم:
- جهتِ معاملاتِ بلندمدت: ۱+
- جهتِ معاملاتِ کوتاهمدت: ۱-
در مقایسه با نوع منطقی، مزیت این مدل ارائه این است که میتوان از آن بهشکل بسیار خوب و تاثیرگذاری برای انجام محاسبات مختلف، و نیز انجام بررسیهای مختلف در کد اکسپرت، بدون داشتن شاخههای شرطی مورد استفاده در رویکردهای متعارف، استفاده کرد.
- چگونه از رویکردهای متعارف در کدنویسی به رویکرد نامتغیر، تغییر وضعیت دهیم – ارائه مثال
بیایید این موضوع را با چند مثال، واضحتر کنیم. هرچند، بیایید با درنظر گرفتن چند تابع کمکی شروع کنیم، که بعدها هم مرتباً استفاده خواهند شد:
int sign( double v ) { if( v < 0 ) return( -1 ); return( 1 ); } double iif( bool condition, double ifTrue, double ifFalse ) { if( condition ) return( ifTrue ); return( ifFalse ); } string iifStr( bool condition, string ifTrue, string ifFalse ) { if( condition ) return( ifTrue ); return( ifFalse ); } int orderDirection() { return( 1 - 2 * ( OrderType() % 2 ) ); }
هدفِ تابع ()sign کاملاً مشخص است: ۱ را برای مقادیر غیرمنفی استدلال، و ۱- را برای مقادیر منفی، برمیگرداند.
تابع ()iif، معادلی برای عملگر زبان C یعنی “condition ? ifTrue : ifFalse” است و اجازه میدهد سادهسازی قابلتوجهی برای اکسپرتهای نامتغیر داشته باشیم، که اکسپرت را فشردهتر و ارائه آن را، بهتر میسازد. این تابع استدلالهای دوگانه را میگیرد، بنابراین، میتوان از آن با مقادیر هم این نوع، و هم نوعِ int (عددصحیح)، و datetime، استفاده کرد. برای اینکه همین کار را با رشتهها انجام دهیم، به تابعِ کاملاً مشابهِ ()iifStr نیاز خواهیم داشت تا مقادیر نوع رشتهای را بگیرد.
تابع ()orderDirection، جهتِ معاملهی ترید کنونی را، با توجه به توافقات ما دربارهی چگونگی ارائهی جهتهای معامله، برمیگرداند (بهعبارت دیگر، همان معاملهای که توسط تابع ()OrderSelect انتخاب شدهاست).
اکنون بیایید با مثالهای خاص ببینیم که چگونه رویکرد نامتغیر با این شکل کدنویسی برای جهتهای معامله، به ما اجازه میدهد کدهای اکسپرت را سادهسازی کنیم:
۲-۱. مثال ۱. تبدیلِ تحقق تریلینگ اِستاپ
یک کد معمولی:
if( OrderType() == OP_BUY ) { bool modified = OrderModify( OrderTicket(), OrderOpenPrice(), Bid - Point * TrailingStop, OrderTakeProfit(), OrderExpiration() ); int error = GetLastError(); if( !modified && error != ERR_NO_RESULT ) { Print( "Failed to modify order " + OrderTicket() + ", error code: " + error ); } } else { modified = OrderModify( OrderTicket(), OrderOpenPrice(), Ask + Point * TrailingStop, OrderTakeProfit(), OrderExpiration() ); error = GetLastError(); if( !modified && error != ERR_NO_RESULT ) { Print( "Failed to modify order " + OrderTicket() + ", error code: " + error ); } }
کد نامتغیر:
double closePrice = iif( orderDirection() > 0, Bid, Ask ); bool modified = OrderModify( OrderTicket(), OrderOpenPrice(), closePrice - orderDirection() * Point * TrailingStop, OrderTakeProfit(), OrderExpiration() ); int error = GetLastError(); if( !modified && error != ERR_NO_RESULT ) { Print( "Failed to modify order " + OrderTicket() + ", error code: " + error ); }
خلاصه:
- توانستیم از وارد شدن به شاخههای شرطی سنگین اجتناب کنیم؛
- فقط از یک رشته برای فراخوانی تابع ()OrderModify بهجای دو رشتهی اولیه، استفاده کردیم؛ و،
- بهعنوان نتیجهی مورد (۲)، کد را برای پردازش [جهت یافتن] خطاها، کوتاه کردیم.
بهیاد داشته باشید که توانستیم فقط از یک فراخوان برای تابع ()OrderModify استفاده کنیم و بهخاطر همین موضوع، بلافاصله جهتِ معاملهی ترید را، در عبارت محاسباتی، برای محاسبهی خطوط استاپ (stop levels)، بهکار گرفتیم. اگر از یک ارائهی منطقی برای جهت معامله استفاده میکردیم، این کار غیرممکن میشد.
اساساً، یک اکسپرتنویس باتجربه، میتواند [حتی] با استفاده از همان رویکردهای متعارف [و بعضاً سنتی]، فقط از یک فراخوان برای ()OrderModify استفاده کند؛ با این حال، در کار ما (در رویکرد ما)، این اَمر (یعنی استفاده از فقط یک فراخوان)، کاملاً بهصورت طبیعی اتفاق میاُفتد و نیاز به هیچگونه مرحلهی اضافی نداریم.
۲-۲. مثال ۲. تبدیلِ شناسایی سیگنال ترید
بهعنوان مثال، بیایید شناسایی سیگنالهای ترید را در یک سیستم با دو مووینگ اَورج، درنظر بگیریم:
double slowMA = iMA( Symbol(), Period(), SlowMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0 ); double fastMA = iMA( Symbol(), Period(), FastMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0 ); if( fastMA > slowMA + Threshold * Point ) { // open a long position int ticket = OrderSend( Symbol(), OP_BUY, Lots, Ask, Slippage, 0, 0 ); if( ticket == -1 ) { Print( "Failed to open BUY order, error code: " + GetLastError() ); } } else if( fastMA < slowMA - Threshold * Point ) { // open a short position ticket = OrderSend( Symbol(), OP_SELL, Lots, Bid, Slippage, 0, 0 ); if( ticket == -1 ) { Print( "Failed to open SELL order, error code: " + GetLastError() ); } }
اکنون بیایید کد نامتغیر را با توجه به جهت ترید، ایجاد کنیم:
double slowMA = iMA( Symbol(), Period(), SlowMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0 ); double fastMA = iMA( Symbol(), Period(), FastMovingPeriod, 0, MODE_SMA, PRICE_CLOSE, 0 ); if( MathAbs( fastMA - slowMA ) > Threshold * Point ) { // open a position int tradeDirection = sign( fastMA - slowMA ); int ticket = OrderSend( Symbol(), iif( tradeDirection > 0, OP_BUY, OP_SELL ), Lots, iif( tradeDirection > 0, Ask, Bid ), Slippage, 0, 0 ); if( ticket == -1 ) { Print( "Failed to open " + iifStr( tradeDirection > 0, "BUY", "SELL" ) + " order, error code: " + GetLastError() ); } }
فکر میکنم کاملاً واضح است که کد بسیار فشردهتر شدهاست. و طبیعتاً، دو بار بررسی خطاها، به یک بار، تبدیل شدهاست.
علیرغم این حقیقت که مثالهای بالا بسیار ساده هستند، ویژگیهای اصلی و مثبتِ رویکرد ما بسیار واضح دیده میشوند. در بعضی از مواردِ پیچیدهتر، تفاوت بین رویکرد سنتی و رویکرد ما، حتی از الان نیز بیشتر مشهود خواهد بود. بیایید از این بابت با یک مثال از یک اکسپرت استاندارد، یعنی MACD Sample، مطمئن شویم.
- چگونه MACD Sample را سادهسازی کنیم
برای اینکه مقاله خیلی طولانی نشود، کد کامل این اکسپرت را در اینجا لحاظ نمیکنیم. به آن بخشهایی از کد میرویم که با آنها کار داریم و تغییر میکنند.
کد کامل اکسپرت را میتوانید در نرمافزار متاتریدر ۴ یا در فایلهای پیوستشده به همین مقاله، بیابید. نسخهی سادهشده را نیز، جهت راحتی کار شما، گذاشتهایم (MACD Sample-2.mq4).
بیایید با بلوکی شروع کنیم که برای شناسایی سیگنالهای ترید نوشته شدهاست. کد اولیهی آن را در اینجا مشاهده میکنید:
// check for long position (BUY) possibility if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) { ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "macd sample",16384,0,Green); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice()); } else Print("Error opening BUY order : ",GetLastError()); return(0); } // check for short position (SELL) possibility if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) { ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point, "macd sample",16384,0,Red); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice()); } else Print("Error opening SELL order : ",GetLastError()); return(0); }
اکنون، با استفاده از روشهای بالا، بیایید همین کد را بهشکلی بازنویسی کنیم که برای سیگنالهای Buy و Sell یکسان باشد:
int tradeDirection = -sign( MacdCurrent ); // check if we can enter the market if( MacdCurrent * tradeDirection < 0 && ( MacdCurrent - SignalCurrent ) * tradeDirection > 0 && ( MacdPrevious - SignalPrevious ) * tradeDirection < 0 && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && ( MaCurrent - MaPrevious ) * tradeDirection > 0 ) { int orderType = iif( tradeDirection > 0, OP_BUY, OP_SELL ); string orderTypeName = iifStr( tradeDirection > 0, "BUY", "SELL" ); double openPrice = iif( tradeDirection > 0, Ask, Bid ); color c = iif( tradeDirection > 0, Green, Red ); ticket = OrderSend( Symbol(), orderType, Lots, openPrice, 3 , 0, openPrice + tradeDirection * TakeProfit * Point, "macd sample", 16384, 0, c ); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print( orderTypeName + " order opened : ", OrderOpenPrice() ); } else Print("Error opening " + orderTypeName + " order : ",GetLastError()); return(0); }
اکنون بیایید به بلوکی برویم که مسئول بستن پوزیشنهای باز و پردازش تریلینگ اِستاپها است. همانند قبل، بیایید نسخهی اولیه را ابتدا ببینیم:
if(OrderType()==OP_BUY) // long position is opened { // should it be closed? if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position return(0); // exit } // check for trailing stop if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss()<Bid-Point*TrailingStop) { OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop, OrderTakeProfit(),0,Green); return(0); } } } } else // go to short position { // should it be closed? if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) { OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position return(0); // exit } // check for trailing stop if(TrailingStop>0) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0)) { OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop, OrderTakeProfit(),0,Red); return(0); } } } }
بیایید با توجه به جهت ترید، این کد را به یک کد نامتغیر تبدیل کنیم:
tradeDirection = orderDirection(); double closePrice = iif( tradeDirection > 0, Bid, Ask ); c = iif( tradeDirection > 0, Green, Red ); // should it be closed? if( MacdCurrent * tradeDirection > 0 && ( MacdCurrent - SignalCurrent ) * tradeDirection < 0 && ( MacdPrevious - SignalPrevious ) * tradeDirection > 0 && MathAbs( MacdCurrent ) > ( MACDCloseLevel * Point ) ) { OrderClose(OrderTicket(),OrderLots(), closePrice, 3,Violet); // close position return(0); // exit } // check for trailing stop if(TrailingStop>0) { if( ( closePrice - OrderOpenPrice() ) * tradeDirection > Point * TrailingStop ) { if( OrderStopLoss() == 0 || ( OrderStopLoss() - ( closePrice - tradeDirection * Point * TrailingStop ) ) * tradeDirection < 0 ) { OrderModify( OrderTicket(), OrderOpenPrice(), closePrice - tradeDirection * Point * TrailingStop, OrderTakeProfit(), 0, c ); return(0); } } }
لطفاً بهیاد داشته باشید که نسخهی اولیهی این اکسپرت، در پردازش تریلینگ اِستاپ، شرط OrderStopLoss() == 0 را فقط برای پوزیشنهای کوتاه، بررسی میکند. این کار برای پردازش شرایطی که در آن فرد، تعیینِ stop level اولیه را انجام نداده، ضروری است (برای مثال، بهخاطر اینکه خیلی نزدیک به قیمت بازار بوده است).
این واقعیت که این شرط برای پوزیشنهای بلندمدت بررسی نمیشود را میتوان بهعنوان خطایی بسیار عادی در نوشتن چنین اکسپرتهای متقارنی، با استفاده از روش کپی-پِیست، درنظر گرفت.
توجه داشته باشید که این خطا بهصورت اتوماتیک، برای هر دو جهتِ ترید، در کد توسعهدادهشده، برطرف شدهاست. ذکر این نکته لازم است که اگر این خطا حین نوشتن کد نامتغیر رخ میداد، هم در پردازش پوزیشنهای بلند و هم در پردازش پوزیشنهای کوتاه، این خطا را داشتیم و نیازی به گفتن نیست که این کار احتمال شناسایی آن حین تست را افزایش میداد.
بسیار خب، اگر اکسپرتها را با تنظیمات مشابه روی دادههای مشابه تست کنید، خواهید دید که کاملاً یکسان هستند. هرچند، نسخهی سادهشده بسیار فشردهتر و قابلنگهداری است.
- توصیههایی برای نوشتن اکسپرتهای متقارن “از ابتدا”
تا الان، حالتهای مختلف تغییر از رویکرد قدیمی در کدها به رویکرد نامتغیر را دیدهایم. با این حال، توسعهی یک ربات ترید از ابتدا، با استفاده از اصول مطرحشده، کار بهتر و تاثیرگذارتری هست.
در نگاه اول، شاید ساده بهنظر نرسد، زیرا برای انجام این کار نیاز به مهارت و تجربههای خاص در ایجاد شرایط و بیان مسئله، با توجه به جهت معامله، داریم. هرچند، با کمی تمرین، کدنویسی به این سبک روی روال خواهد افتاد و اصلاً سخت نیست.
چند توصیه دارم که به شما کمک میکند از رویکرد تاثیرگذارتری استفاده کنید:
- هنگامی که دارید بخشی از کد را توسعه میدهید، اول از همه، جهتِ معاملات بلندمدت را پردازش کنید – در بسیاری از مواقع، راه سادهتر این است که کد نامتغیر را ترکیب کینم، زیرا جهت این معامله، با مقدار ۱+ ارائه شدهاست و هنگام نوشتن و تحلیل روابط نامتغیر، کار زیادی نمیبَرَد.
- اگر کار روی جهت بلندمدت را آغاز کردید، اول، شرطی بدون متغیر/تابع بنویسید که جهت معامله را منعکس میکند. مطمئن شوید که بیان [مسئله] صحیح بوده و جهت معامله را درون آن اضافه کنید. بعد از کسب کمی تجربه، میتوانید بدون تقسیم مراحل کار کنید.
- به جهت بلندمدت، مانند کَنه “نچسبید” – بعضیوقتها بهتر این است که شرط را برای جهت کوتاهمدت تعریف کنید.
- جاهایی که امکان کار با محاسبات وجود دارد، سعی کنید از شاخههای شرطی و استفاده از تابع iif() اجتناب کنید.
بهعنوان جملهی آخر در اینجا میخواهم بگویم، ممکن است شرایطی پیش بیاید که نتوانید بدون شاخههای شرطی کار را جلو ببرید. هرچند، بهتر این است که تلاش خود را بکنید و شرایط را یککاسه کنید و شرایط را در توابع کمکیِ جهت معامله، بهصورت جداگانه طوری پخش کنید که وابسته به یک اکسپرت خاص نباشید. این توابع، همانند توابع بالا، ()sign()، iif، و ()orderDirection، ممکن است مناسب یک کتابخانهی خاص باشند که اکسپرتهای شما بعداً بتوانند از آن استفاده کنند.
برای دوباره شفافسازی همهچیز، بیایید فرض کنیم مشکل زیر را داریم:
در یک معامله، برای یک پوزیشن طولانی، stop level باید در پایینترین سطح کندل قبلی، و برای پوزیشن کوتاه، باید در بالاترین سطح کندل قبلی باشد.
میتوانیم در کد این موضوع را اینگونه ارائه دهیم:
double stopLevel = iif( tradeDirection > 0, Low[ 1 ], High[ 1 ] );
بهنظر ساده و شفاف میآید، هرچند، حتی این ساختارهای ساده ممکن است و باید، به توابع ساده و کوچکتر تقسیم شوند، تا بتوان از آنها بارها و بارها استفاده کرد.
بیایید از عملگر شرطی، با جایگزینی آن در تابع کمکی، و به قصد اهداف کلیتر، اجتناب کنیم:
double barPeakPrice( int barIndex, int peakDirection ) { return( iif( peakDirection > 0, High[ barIndex ], Low[ barIndex ] ) ); }
اکنون میتوانیم محاسبهی stop levelها را، به این شکل، بیان کنیم:
double stopLevel = barPeakPrice( 1, -tradeDirection );
اگر در نگاه اول دیدید که تفاوت بسیار ناچیز است، لطفاً تحت تاثیر قرار نگیرید. این حالت، مزیتهای بسیار خوبی دارد:
- هدفش را کاملاً شفاف و بهشکل نامتغیر بیان میکند؛
- ترغیب به نوشتن کد اکسپرت، با سبکی بسیار مناسب میکند؛
- خواندن آن راحت است و توسعههای بعدی را راحتتر میسازد.
این فقط یک مثال بود. در واقع، بسیاری از اِلمانهای استاندارد کد اکسپرتها را میتوان به همین شکل بیان کرد. خودتان نیز میتوانید بهراحتی این کار را انجام دهید. بنابراین پیشنهاد میکنم کد خودتان را بررسی کرده و در آن به این شیوه بازنگری کنید.
- اصلاً چرا این همه کار؟
بهنظر من، مفهومی که توضیح داده شد، مزیتهای بسیار مهم زیر را دارد:
- کاهش سورس کد بدون کم شدن کارایی آن، و در نتیجه، صرف زمان کمتر حین توسعه و اصلاح سیستمهای ترید؛
- کاهش تعداد خطاهای بالقوه؛
- افزایش احتمال شناسایی خطاهای موجود؛
- سادهتر شدن اصلاح اکسپرت در آینده (تغییرات بهصورت خودکار هم برای سیگنالها و هم برای پوزیشنهای بلند و کوتاهمدت، اِعمال میشوند).
فقط متوجه یک عیب شدم: این کار ممکن است دشواریهای کوچکی در فهم و مطالعه در مراحل ابتدایی، بوجود بیاورد. هرچند، این موضوع در برابر مزیتهایی که در بالا ذکر شدهاند، تقریباً هیچ است. علاوه بر اینها، فقط بحث زمان است و تجربه – اکسپرتنویسهایی که به این سبک کار میکنند پس از مدتی کار برایشان بسیار راحت و طبیعی میشود.
نتیجهگیری
رویکردی که برای کدنویسی اکسپرتها در MQL4 ذکر شد، برمبنای استفاده و ارائهی مفهومِ جهت معامله، آنهم بهشکلی موثر، است. در عمل، به شما اجازه میدهد از تکرار مجدد برخی از بخشهای کد، که کاملاً یکسان هستند، جلوگیری کنید. تکرار مجدد، در رویکرد سنتی و در کد اکسپرتها، موضوعی طبیعی بهحساب میآید. بهرهگیری از روشی که توضیح داده شد، منجر به کاهش حجم سورس کد، و به دنبال آن، سایر مزیتها، میشود که بسیار ضروری بهنظر میرسد.
مثالهایی که در این مقاله ارائه شد، برای تازهکارها و باتجربهها منبع خوبی بود تا کدها و کدنویسی خودشان را آپدیت کنند – البته اگر بخواهند! مثالهایی که درنظر گرفته شدند، ساده بودند تا اهداف مورد نظر، یعنی خواندن و فهم سادهی موضوع، اجابت شوند. با این حال، از این رویکرد در تحقق سیستمهای بسیار پیچیده هم استفاده شدهاست؛ سیستمهایی که ابزارهای تحلیل تکنیکال، مانند کانالها، خطوط روند، چنگال آندرو، امواج الیوت، و دیگر روشهای متوسط یا پیشرفتهی تحلیل بازار را، در خود دارند.
این مقاله دارای فایل پیوست است.
فایل پیوست مقاله را میتوانید از اینجا دانلود کنید .
۴۰ مورد نظر
Hey There. I found your blog the use of msn.
This is a really neatly written article. I’ll be sure to bookmark it and
return to learn more of your useful information. Thanks for the post.
I’ll certainly comeback.
prescription drugs canada buy online
overnight pharmacy cialis purchasing cialis in the usa does medicare cover cialis for bph
prednisone over the counter uk buy prednisone can you buy prednisone
vacuum pump for ed buy canadian drugs sexual dysfunction in men
insurance that covers cialis best price for daily cialis cialis generic purchase
cheap pills online ed clinics erectile dysfunction
cialis prescription online cheapest cialis usa cialis buy without
j r enterprises ivermectin what is ivermectin for ivermectin 0.5 lotion
cialis omline cialis usa cialis samples online
guinea pig ivermectin ivermectin new zealand how much ivermectin to give a goat
prescription meds without the prescriptions how can i order prescription drugs without a doctor п»їed drugs online from canada
stromectol coronavirus worming rabbits with ivermectin is ivermectin for animals the same as for humans
cheap propecia online propecia hair propecia 5 mg
ed meds medication for ed new ed pills
ed pills gnc best male ed pills ed treatment drugs
carprofen without vet prescription how to get prescription drugs without doctor best ed pills non prescription
generic drugs without doctor’s prescription india pharmacy buy prescriptions from india pharmacy
pharmacy without dr prescriptions recommended canadian pharmacies prescription drugs without doctor approval
buy prescriptions from india pharmacy india pharmacy mail order india pharmacy
what is the best ed pill cheapest ed pills cures for ed
order provigil 100mg for sale
purchase provigil
buy medication online from india overseas pharmacies online buy prescriptions from india pharmacy
prescribing stromectol stromectol for sale stromectol for humans for sale
modafinil 200mg ca modafinil cheap
tadalafil without a doctor’s prescription cialis 20mg tadalafil tablets 20 mg india
order provigil 100mg for sale order provigil sale
stromectol without a doctor prescription stromectol 12 mg tablets prescribing stromectol
provigil 200mg over the counter provigil generic
buy clomid 50mg online where to buy cheap clomid online clomid
order provigil 100mg online cheap modafinil 200mg cost
purchase provigil for sale modafinil 100mg ca provigil 100mg generic
order provigil order provigil generic buy modafinil online cheap
ivermectin without a doctor prescription stromectol for sale stromectol pills for humans
https://erythromycinn.com/# erythromycin eye ointment side effects
sildenafil 20 mg sildenafil 100 mg sildenafil 100 mg
modafinil brand modafinil online order provigil 200mg pills
stromectol 12 mg tablets stromectol for humans for sale stromectol 12 mg tablets
stromectol for sale buy ivermectin cream stromectol for sale