
عبور از محدودیتهای استراتژیتستر در تست اکسپرت هج
در این مقاله به ایدهی تست اکسپرت هج در استراتژیتستر میپردازیم. همانطور که میدانید استراتژیتستر محدودیتهای خاص خودش را دارد و برای یک نمادِ (symbol) دیگر، نمیتواند هیچ معاملهای باز کند. هر کاربری که بخواهد اکسپرت/اکسپرتهای هج خود را تست کند باید فقط در حالت واقعی (live) این کار را انجام دهد. اما آیا این موضوع تواناییهای ما را محدود میسازد؟ مطمئن هستم که هر تریدر هج، نیاز دارد که اکسپرت خود را قبل از رفتن به حالت واقعی، تست کند. بنابراین، میخواهم این ایده را بدهم که بیاییم یکنوع وضعیت مجازی جهت تست استراتژی (تستر-مانند) ایجاد کنیم، و امیدوارم این کار به ما کمک کند محدودیتهای استراتژیتستر متاتریدر ۴ را شکسته و بتوانیم بعداً استفادههای دیگری نیز داشته باشیم.
مفهوم تستر مجازی
وقتی داشتم در mq4 با تابع “Files” کار میکردم، ایدهی تستر مجازی به ذهنم خطور کرد. و در ادامه این فکر به ذهنم رسید که برخی از دادههای مهم را از یک فایل بگیرم تا بهنوعی طرح ترید مجازی را آماده کنم. “آیا این پاسخ سوال من دربارهی تست اکسپرت هج است؟” بیایید امتحان کنیم.
تستر مجازی من به هیچ برنامه یا نرمافزار خارجی نیاز ندارد. همهچیز را میتوان توسط پارامترهای mq4 انجام داد. مفهوم این تستر مجازی این است که اجازه دهیم پارامترهای مشخصشده برای باز کردن یا بستن معاملات هج به ما بگویند که دادههای مورد نیاز را جمعآوری کنیم؛ مثل قیمت بازشدن، زمان بازشدن، قیمت بستهشدن، زمان بستهشدن، و تمام دیگر دادههای مهم. بعد از اینکه دادههای مورد نیاز تعیین و جمعآوری شدند، از آنها برای مقایسه با مقدار آخرین تیکِ هر نوع دادهی همسان، مانند قیمت بازشدن و آخرین قیمت پیشنهادی برای فروش (Bid)، یا قیمت بازشدن و آخرین خرید (Ask)، استفاده میکنیم. چنین مقادیری ما را بهسمت روش محاسبهی سود هدایت میکنند و این کار ما را راهنمایی میکند گروه جدیدی از دادهها را بعد از برآورده شدن شرایط بستهشدن هج، جمعآوری کنیم.
گروههای داده، بهشکل یک فایل برای استفادههای بیشتر درمیآیند. بعد از اینکه تست گرفتن انجام شد و انواع دادهها در فایل یا فایلهایی ذخیره شدند، قادر خواهیم بود ببینیم “چگونه اکسپرت هج اجرا شدهاست”. دادهها را میدهیم تا آنها را بهشکل اندیکاتور منحنی عملکرد ترسیم کنند، و پس از آن تست مجازی اکسپرت هج خود را میتوانیم تمام کنیم.
با این مفهوم، فکر میکتنم بتوانیم نتایج تست را که مشابه با نتایج استراتژیتستر واقعی هستند، داشته باشیم. باید این را بگویم که این فقط یک ایده برای ایجاد یک تستر برای اکسپرتهای هج است و ضمانت نمیکنم که دقیقاً عین تستر واقعی به ما نتیجه دهد. اما امیدوارم حداقل مرجع خوبی برای بحثهای آینده باشد.
بیایید شروع کنیم.
معنای سادهی معاملهی هج
قبل از اینکه شروع کنیم، بیایید کمی دربارهی “HEDGE” صحبت کنیم. سادهترین راه برای تعریف هجینگ این است که دو معامله در جهت مخالف [یکدیگر] در دو جفتاَرز، همزمان باز کنیم. این کار برای کم کردن ریسک معامله انجام میشود، اگر یکی از معاملات بهسمت بالا برود، آن یکی قطعاً بهسمت پایین حرکت میکند، اما هیچ جای نگرانی نیست زیرا همزمان هم معاملهی Sell داریم، هم معاملهی Buy، و اگر یکی را از دست بدهیم، دیگری را بدست آوردهایم، و به همین دلیل است که این را “کم کردن ریسک” مینامند. در دنیای فارکس، انواع و اقسام سبکهای معامله در جهت مخالف، داریم.
- برای دو جفتاَرز که همیشه مثل هم حرکت میکنند، مانند EURUSD و GBPUSD، Buy برای EURUSD و Sell برای GBPUSD، بهصورت همزمان، میشود هجینگ.
- برای دو جفتاَرز که همیشه مخالف هم حرکت میکنند، مانند EURUSD و USDCHF، Buy برای EURUSD و Buy برای USDCHF میشود هج کردن آنها.
- و حتی Buy و Sell گرفتن همزمان برای EURUSD نیز هج کردن بهحساب میآید، اما بعضیوقتها به این کار “arbitrate” میگویند.
در معاملات هج، حقایقی هست که نمیتوان آنها را زیر سوال برد.
- همبستگی. یک ابزار آماری است برای ارتباط بین دو واحد پولی. ضریب همبستگی، محدودهای از ۱- تا ۱+ دارد. ۱+ یعنی دو جفتاَرز صد در صد مواقع در یک جهت حرکت میکنند. ۱- یعنی دو جفتاَرز صد در صد مواقع در جهت مخالف [یکدیگر] حرکت میکنند. و در صورتیکه ۰ باشد، بدان معناست که ارتباط بین دو جفتاَرز مدنظر، کاملاً تصادفی است (بیشتر بخوانید).
- نسبت لاتیج. برای کار کردن با دو جفتاَرزی که نه در جهت یکدیگرند و نه مخالف یکدیگر حرکت میکنند، “نسبت لاتیج” کاملاً مهم و ضروری است زیرا نوسانات و قابلیت حرکت این دو جفتاَرز، متفاوت و همانند لاکپشت و خرگوش است، و اگر یکی از اینها لاکپشت باشد، دیگری خرگوش است. نسبت لاتیج میتواند ریسک را کمتر کند، حرکتی که قویتر است، یا همان جفتاَرزی که خرگوش است، تاثیر خود را گذاشته و با درج لاتیج بالاتر برای جفتاَرز لاکپشت، ضررِ کمتر، هنگامیکه جفتاَرز خرگوش ما در جهت منفی حرکت میکند، تضمینشده است. آنگاه میتوانید از لاکپشتی که در جهت مثبت است، بیشتر سود بگیرد، و یا بهعبارت دیگر، لاکپشت سودده، ضرر خرگوش را جبران میکند. بنابراین، تکنیک هج این خاطرجمعی را به شما میدهد که بیشتر از باز کردن فقط یک معامله در سَمتِ منفی، ضرر نمیکنید.
راستی، آیا تابحال از خود پرسیدهاید که یک معاملهگر هجر چگونه با این سبک معامله کردن، سود بدست میآورد؟ نگران نباشید، همیشه بین دو جفتاَرز، نقاط مشترک و بهنوعی رویهماُفتادن (overlap) داریم، و همبستگی مطلق و دائمی نیست، مکرر تاخیر از سوی یک جفتاَرز را شاهد خواهیم بود، یکی شروع به حرکت میکند و دیگری بعد از آن شروع میکند؛ و دوباره و دوباره، درست مثل لاکپشت و خرگوش – خرگوش وسط راه استراحت میکند و منتظر لاکپشت است تا شکستش دهد و برنده شود. به همین دلیل است که معاملهگرهای هج سودهای خوبی میگیرند. و امروزه بسیاری از افراد از این روش برای کسب درآمد در فارکس استفاده میکنند و جای نگرانی هم نیست. هج کنید، صبر کنید و وقتی سود مثبت دیدید، معامله را ببندید، و همین!
مفهوم هج
قبل از اینکه کدنویسی تستر مجازی را آغاز کنیم، بیایید مفهوم هج را در یک ازمایش بفهمیم. بدون مفهوم هج هیچگاه نخواهیم دانست کدام نوع داده را باید خروجی بگیریم، ثبت و محاسبه کنیم. این دادهها به ما نشان میدهند چه نوع معاملهای را باید بهصورت مجازی ایجاد کرد. در این آزمایش قوانین هج را اینگونه تعریف میکنم.
- بهصورت روزانه و در آغاز روز، [معاملهی] هج باز کنید
- وقتی معامله به ۱۰۰ دلار رسید آن را ببندید (لاتیج، ۱ و ۲ لات باشد)
- دادههای تیک قیمت را ساعتی جمعآوری کنید***
- در آغاز روز جدید، حتی اگر به سود مورد نظر نرسیدید، دادهها را پاک کنید
- فقط، ۲ لات EURJPY بخرید، و ۱ لات GBPJPY بفروشید.
بر اساس این قوانین، معاملات مجازی نیاز به قیمتهای بازشدن روزانهی (هر دو جفتاَرز) دارند تا از آنها بهعنوان قیمت بازشدن معامله استفاده کنیم. برای محاسبهی سود در طول روز، قیمت هر روز و در هر ساعت، بهعنوان تیک قیمت، باید بهعنوان داده برای قیمت بستهشدن معامله ثبت شود (ask برای sell، و bid برای buy) و باید همراه با زمان آن تیک، ثبت شدن انجام شود (تا مطمئن شویم قیمت تیک از مقدارِ زمانی مشابه میآید). و با درنظر گرفتن مفهوم معاملات هج بهصورت روزانه، تمام دادههای مورد نیاز را در دو نوع فایل تقسیم میکنم، که بازشدن روزانه و مقدار تیک هر دو جفتاَرز هستند. هر دو نوع داده را در قالب فایلهای رشتهای، همراه با نامهای متفاوت، مانند GBPJPYD1.csv و GBPJPYTick.csv، خروجی میگیریم.
بهخاطر دادههای تیک، و از آنجاییکه میخواهیم تستر مجازی ما تا سرحد امکان شبیه به استراتژیتستر واقعی باشد، باید این دو مرحله را انجام دهیم.
- اسکریپتی بنویسید که قیمت بازشدن روزانه GBPJPY را در قالب یک فایل خروجی بگیرد.
- اسکریپتی بنویسید که قیمت تیک روزانه GBPJPY را در قالب یک فایل خروجی بگیرد.
و هر دو مرحله را باید برای EURJPY نیز انجام دهید.
اما فکر میکنم میتوانیم همهی اینها را در قالب یک اکسپرت ترکیب کنیم، و این اکسپرت باید هر دو نوع داده را در قالب دو فایل مجزا خروجی بدهد. و بعد از اینکه این اکسپرت فرآیند ثبت دادهها را تمام کرد، یک اکسپرت جدید برای ایجاد معاملهی مجازی، تمام دادههای GBPJPY و EURJPY را از فایلهای خروجیگرفتهشده میگیرد تا تست مجازی روی آنها انجام شود.
۳ گام برای شکستن محدودیت تست
با ایدهای که دادم، میتوانیم رویای شکستن محدودیت تست را فقط در ۳ گام به حقیقت تبدیل کنیم.
- دادههای قیمت را گرفته و آنها را در قالب فایلهایی با استفاده از اکسپرت، خروجی بگیرید.
- با یک اکسپرت دیگر شرایط تست مجازی را ایجاد کرده، بطوریکه این اکسپرت هم نتایج را بهشکل یک فایل خروجی دهد.
- در پنجرهای جداگانه نتایج را بهشکل یک اندیکاتور بازبینی کنید.
پس بیایید گام اول را برداریم.
گام ۱. خروجی گرفتن از دادههای قیمت
در پایین اکسپرتی را میبینید که برای خروجی گرفتن از قیمت بازشدن روزانهی اَرز مدنظر در قالب یک فایل با نام “GBPJPYD1.csv” برای GBPJPY و “EURJPYD1.csv” برای EURJPY طراحی شدهاست. و در عین حال، قیمت تیک را هم بهشکل یک فایل خروجی میدهد، و نام فایل چیزی مانند این است: “symbolT.csv” (درست مانند فایل D1). برای یادگیری نحوهی کارکرد اکسپرت، کامنتها را بخوانید.
توجه: تمام فایلهایی که این اکسپرت میسازد، در مسیر “MetaTrader 4/tester/files” هستند.
//+------------------------------------------------------------------+ //| symbol-D1.mq4 | //| A Sexy Trader | //| http://pipsmaker.wordpress.com/ | //+------------------------------------------------------------------+ #property copyright "A Sexy Trader" #property link "http://pipsmaker.wordpress.com/" #include <stdlib.mqh> extern string StartDate = "2007.03.17" //set the starting date to get the same time data ,StopDate = "2007.06.28"; //set the testing time limit to protect the over //data recording process extern bool For_OP_SELL = true;/*This is to guide for the right type of data to be collected ->if For_OP_SELL = true the daily Open will be collected as an order open price ->if For_OP_SELL = false , means for OP_BUY, the daily Open+SPREAD will be collected instate. */ string name,tname; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //-------------------------------------------------------------------+ //| Some Essential Parameters In This EA | //-------------------------------------------------------------------+ int day // a variable to mark that today Open has been collected ,ho // handle of the file recording the Open price ,ht // handle of the file recording the tick price ,x=1 /* the order of D1 file increasing every time D1 data is equal to 4086 characters and generate the new recording file*/ ,xt=1 // same as x but for tick data ,bartime // a variable to mark that current bar's Open has been collected ; double ot // latest Open Time ,op // latest Open price ,lt // latest tick time ,ltk // latest tick price ; string OStr // the string to collect the daily open ,TStr // the string to collect the tick value ; //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { /*---------------------Only collect the data in the specific time period.----------------------*/ if(TimeToStr(TimeCurrent(),TIME_DATE)>=StartDate && TimeToStr(TimeCurrent(),TIME_DATE)<=StopDate) { name=Symbol()+x+"D1.csv"; // setup the name of daily open price file tname=Symbol()+xt+"T.csv" // the name of tick price file ; //---- if(day!=TimeDay(Time[0])) // the new day has come { ot=Time[0]; // get the new bar time if(For_OP_SELL)op=Open[0]; // get the new order open price for SELL Symbol else op=Open[0]+MarketInfo(Symbol(),MODE_SPREAD)*Point; // else if collecting for the BUY Symbol OStr=OStr+TimeToStr(Time[0],TIME_DATE)+",";//collect the new time data separate each data with "," OStr=OStr+DoubleToStr(op,Digits)+","; //now the new open price //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~now it's time to export as a file ho=FileOpen(name ,FILE_CSV|FILE_WRITE); // open a file to record the daily open if(ho>0) // if the file Symbol()+x+"D1.csv" exist { FileWrite(ho,OStr); // write the collected data FileClose(ho); // close the file every time your file process done if(StringLen(OStr)==4086){x++;OStr="";} /* if the data contains 4086 characters set new x to*/ } /* create the new file and prepare the new string for the new file */ Print(TimeToStr(Time[0],TIME_DATE)); // print the collected day time int thex=FileOpen(Symbol()+"x.csv",FILE_CSV|FILE_WRITE); // create a file to record "how many x?" for D1 file for further usage if(thex>0) // if the file exist { string xs=DoubleToStr(x,0); // transform x into string FileWrite(thex,xs); // write the x value FileClose(thex); // close file (every time you finish) } day=TimeDay(Time[0]); // now mark today as collected } //--------------------------------FOR TICK VALUE /*Because of the decision of collecting the tick data hourly*/ if(bartime!=Time[0]) // the new hourly bar has come // and to make it more flexible when you decided // to collect data in another time frame { lt=TimeCurrent(); // get the tick time if(!For_OP_SELL) ltk=Bid; // the tick price for sell order else ltk=Ask; // in case for buy order TStr=TStr+TimeToStr(lt,TIME_DATE|TIME_MINUTES)+","; // insert the data into the collected string TStr=TStr+DoubleToStr(ltk,Digits)+","; // //~~~~~~~~ // now export the data ht=FileOpen(tname,FILE_CSV|FILE_WRITE); // open a file to record the tick value if(ht>0) // if the file Symbol+xt+"T.csv" exist { FileWrite(ht,TStr); // write the collected tick with time FileClose(ht); // finish. if(StringLen(TStr)==4080){xt++;TStr="";}// prepare for new file if this file reached 4080 character } int thext=FileOpen(Symbol()+"xt.csv",FILE_CSV|FILE_WRITE); // record the xt value .. same as D1 file if(thext>0) // if the file exist { string xts=DoubleToStr(xt,0); // transform into string FileWrite(thext,xts); // write xt FileClose(thext); // done } bartime=Time[0]; // mark as current hourly bar Open price has been collected } } else if(TimeToStr(TimeCurrent(),TIME_DATE)>StopDate) // if out of specified period Print("Done."); // let us know it all done. //---- return(0); } //+------------------------------------------------------------------+
گام ۲. ایجاد معاملهی مجازی
این یکی از جذابترین مراحل است. در اینجا میخواهیم اکسپرت هج را توسط استراتژیتستر، بهنوعی تستپذیر کنیم. اسکریپت پایین را نگاه کنید تا ببینید این کار چگونه انجام میشود. و خواندن کامنتها را نیز فراموش نکنید. و درست همانند اکسپرت اول، فایل نتایج در مسیر “MetaTrader 4/tester/files” ذخیره خواهد شد.
//| VirtualHedge.mq4 | //| A Sexy Trader | //| http://pipsmaker.wordpress.com/ | //+------------------------------------------------------------------+ #property copyright "A Sexy Trader" #property link "http://pipsmaker.wordpress.com/" #include <stdlib.mqh> extern string StartDate = "2007.03.17"; // specify the testing period the same as collected data extern string StopDate = "2007.06.27"; extern string BaseSymbol = "GBPJPY"; // the base symbol extern string HedgeSymbol = "EURJPY"; // the hedge symbol extern int Base_OP = OP_SELL; // by the rules always sell GBPJPY extern int Hedge_OP = OP_BUY; // and always buy EURJPY extern double BaseLotSize = 1.0; // take the lot size of 1 for GBPJPY extern double HedgeLotSize = 2.0; // and take 2 lots for EURJPY extern double ExpectProfit$ = 100; // always close when reach $100 extern bool PrintDetails = true; // print the order opening and closing detail ? int BSP // the spread of GBPJPY ,HSP // the spread of EURJPY ,BOP=-1 // OrderType of GBPJPY ,HOP=-1 // OrderType of EURJPY ,day=0 // for marking that today hedge was executed ,hr // handle of the file for exporting the hedge result ,p=1 ,BC // the base-symbol's contract size ,HC // the hedge-symbol's contract size ,floating=0 // for marking as there are some orders currently floating ,Pointer=0 // the Pointer of each string data ,AL // Account Leverage ,on // order number ; double BOpen // open price of base symbol ,HOpen // open price of hedge symbol ,BLots // base symbol lotsize ,HLots // base symbol lotsize ,lastTick // to mark the last tick for calculating the current profit ,BPF // base symbol order profit ,HPF // hedge symbol order profit ,TPF // the total profit ,CurBalance // the array to collect the hedge results ,CurB=0 // the current balance ,BTick // Base tick ,HTick // Hedge tick ,BD1Time // Base daily open time ,HD1Time // Hedge daily open time ,BTTime // Base tick time ,HTTime // Hedge tick time ; string CurTrade // a string to show the current performance as a comment ,BORD // a string to specify the type of arrows and text of base symbol ,HORD // same thing but for hedge symbol ,hobstr // the whole string of the base symbol open price data ,bstr // the string of all daily data of base Symbol ,hstr // the string of all daily data of hedge Symbol ,btstr // the string of tick data of base Symbol ,htstr // the string of tick data of hedge Symbol ,pstr // the string for exporting result data ; color SELLCL=DeepSkyBlue // the color of arrows to mark that sell order was executed ,BUYCL=HotPink // the color of arrows to mark that buy order was executed ,BCL // the color of base symbol, varies by the Base_OP parameter ,HCL // the color of hedge symbol, varies by the Hedge_OP parameter ; bool closed=true // for marking as all trades were closed ,trimb=true // get rid of taken data of base Symbol or not? ,trimh=true // get rid of taken data of hedge Symbol or not? ,trimbd1=true // get rid of taken daily data of base Symbol or not? ,trimhd1=true // get rid of taken daily data of hedge Symbol or not? ; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- CurBalance=AccountBalance(); //mark the initial deposit CurB=AccountBalance(); //mark the current balance pstr=pstr+DoubleToStr(CurBalance,2)+","; //collect the performance string AL=AccountLeverage(); //get the Account Leverage BSP=MarketInfo(BaseSymbol ,MODE_SPREAD); //get the spread HSP=MarketInfo(HedgeSymbol ,MODE_SPREAD); BC =MarketInfo(BaseSymbol ,MODE_LOTSIZE); //get the contract size for calculating profit HC =MarketInfo(HedgeSymbol ,MODE_LOTSIZE); BOP=Base_OP; //get the OrderType HOP=Hedge_OP; BLots=BaseLotSize; //get the lot size HLots=HedgeLotSize; string RName=BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv"; //name the performance file //this file is needed to copy to /* Program files/MetaTrader 4 /Experts/files */ hr =FileOpen(RName ,FILE_CSV|FILE_WRITE); //open the file to export the initial deposit if(hr>0) //if the file exist { FileWrite(hr,pstr); //export the initial deposit FileClose(hr); //close file } if(Base_OP==OP_SELL){BCL=SELLCL;BORD="sell";} //specify the parameter leading to create else {BCL=BUYCL; BORD="buy";} // the trading arrow and text if(Hedge_OP==OP_BUY){HCL=BUYCL; HORD="buy";} else {HCL=SELLCL;HORD="sell";} getdata(BaseSymbol); //get all data of BaseSymbol getdata(HedgeSymbol); //all data of HedgeSymbol //the function located at the bottom return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { string RName=BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv"; //name the performance file //--------------------------Only perform the show of specified period--------------------------// if(TimeToStr(TimeCurrent(),TIME_DATE)>=StartDate && TimeToStr(TimeCurrent(),TIME_DATE)<=StopDate) //mark as no any order now { if(day!=TimeDay(Time[0])) //the new day has come { { if(BOpen!=0 && HOpen!=0) //check if yesterday hedge still floating { if(Base_OP==OP_BUY) //the base-symbol's current profit { BPF=((BTick-BOpen)*BLots*BC)/BOpen; } else { BPF=((BOpen-BTick)*BLots*BC)/BOpen; } if(Hedge_OP==OP_BUY) //the hedge-symbol's current profit { HPF=((HTick-HOpen)*HLots*HC)/HOpen; } else { HPF=((HOpen-HTick)*HLots*HC)/HOpen; } TPF=BPF+HPF; //the total current profit CurB+=TPF; CurBalance=CurB; //get the latest AccountBalance pstr=pstr+DoubleToStr(CurBalance,2)+","; //insert into the performance string floating=0; //mark as no any order now BOpen=0; // block the profit calculation process HOpen=0; if(BOpen==0 && HOpen==0) //make sure there is no any order now { closed=true; //mark all orders were closed CreateObject("R : "+on,OBJ_TEXT,Time[0],Close[0],0,0,DarkViolet,"","Cleared With Profit Of : "+DoubleToStr(TPF,2)); //create the cleared all orders text if(PrintDetails)Print("Cleared Hedge With Profit : "+DoubleToStr(TPF,2)); //print latest action if PrintDetails allowed hr =FileOpen(RName ,FILE_CSV|FILE_WRITE); //open the result file to prepare for file writing if(hr>0) { FileWrite(hr,pstr); //export the data FileClose(hr); } if(StringLen(pstr)>4086){p++;pstr="";} //set the new file name if pstr is larger than 4086 characters int thep=FileOpen("p.csv",FILE_CSV|FILE_WRITE); //this file is needed to copy to /* Program files/MetaTrader 4 /Experts/files */ //too // record the p value as a file if(thep>0) // if the file exist { string ps=DoubleToStr(p,0); // transform into string FileWrite(thep,ps); // write p FileClose(thep); // done } } } if(floating==0) //now all yesterday hedge were cleared { trimb=true; trimh=true; //allow getting tick data for today to work //----------GETTING TODAY ORDER OPEN PRICE AND TIME----------// if(trimbd1) //getting the daily base price allowed { Pointer=StringFind(bstr,",",0); //find the nearest "," from the beginning of string BD1Time=StrToTime(StringSubstr(bstr,0,Pointer)); //get the time value located before the "," syntax bstr=StringSubstr(bstr,Pointer+1,0); //trim off the taken data Pointer=StringFind(bstr,",",0); //find the nearest "," from the trimmed data string BOpen=StrToDouble(StringSubstr(bstr,0,Pointer)); //get the PRICE value located before the "," syntax bstr=StringSubstr(bstr,Pointer+1,0); //trim off the taken data again to prepare for next time } if(trimhd1) //getting the daily hedge price allowed { Pointer=StringFind(hstr,",",0); //all processes are the same as bstr above HD1Time=StrToTime(StringSubstr(hstr,0,Pointer)); //... hstr=StringSubstr(hstr,Pointer+1,0); //... Pointer=StringFind(hstr,",",0); //... HOpen=StrToDouble(StringSubstr(hstr,0,Pointer)); //... hstr=StringSubstr(hstr,Pointer+1,0); //... } //--------GETTING TODAY ORDER OPEN PRICE AND TIME ENDED--------// if(BOpen!=0 && HOpen!=0 && CurBalance>(BLots+HLots)*BC/AL) //make sure the data taken is not zero and margin balance still available { floating=1; //mark as hedge sent closed=false; //mark as all orders opened on++; //new hedge orders have opened if(PrintDetails) //if PrintDetails allowed { Print(on+" Opened : "+BaseSymbol+" "+DoubleToStr(BLots,2)+" lots @ "+DoubleToStr(BOpen,Digits)+"."); Print(on+" Opened : "+HedgeSymbol+" "+DoubleToStr(HLots,2)+" lots @ "+DoubleToStr(HOpen,Digits)+"."); } } else //in case can not send hedge { Comment("Can Not Open The Trade : No Margin Available"); } //let us know if(closed==false) //hedge sent { //create the buy and sell arrow and text //this function is located at the bottom of the EA CreateObject("B : "+on,OBJ_ARROW,Time[0],Open[0]-20*Point,0,0,BCL,BORD,""); CreateObject("H : "+on,OBJ_ARROW,Time[0],Open[0]+30*Point,0,0,HCL,HORD,""); } } } day=TimeDay(Time[0]); //mark as proceeded } //-------------------------For Each Tick----------------------------// if(lastTick!=Hour()) //the new hour has come { if(trimb && StringFind(btstr,",",0)>0) //getting base tick allowed { Pointer=StringFind(btstr,",",0); //same process as getting daily data above BTTime=StrToTime(StringSubstr(btstr,0,Pointer)); btstr=StringSubstr(btstr,Pointer+1,0); Pointer=StringFind(btstr,",",0); BTick=StrToDouble(StringSubstr(btstr,0,Pointer)); btstr=StringSubstr(btstr,Pointer+1,0); } if(trimh && StringFind(htstr,",",0)>0) //if getting hedge tick allowed { Pointer=StringFind(htstr,",",0); HTTime=StrToTime(StringSubstr(htstr,0,Pointer)); htstr=StringSubstr(htstr,Pointer+1,0); Pointer=StringFind(htstr,",",0); HTick=StrToDouble(StringSubstr(htstr,0,Pointer)); htstr=StringSubstr(htstr,Pointer+1,0); } if(TimeDay(BD1Time)==TimeDay(BTTime) && TimeDay(HD1Time)==TimeDay(HTTime)) //only if the tick is form the same day { trimbd1=true; trimhd1=true; //allow to get the next day value if(TimeHour(BTTime)==TimeHour(HTTime)) //and same time hour { trimb=true; trimh=true; //allow to get the next tick value if(BOpen!=0 && HOpen!=0) //if the calculation process allowed { if(Base_OP==OP_BUY) { BPF=((BTick-BOpen)*BLots*BC)/BOpen; //the base-symbol's current profit } else { BPF=((BOpen-BTick)*BLots*BC)/BOpen; } if(Hedge_OP==OP_BUY) { HPF=((HTick-HOpen)*HLots*HC)/HOpen; //the hedge-symbol's current profit } else { HPF=((HOpen-HTick)*HLots*HC)/HOpen; } TPF=BPF+HPF; //the total current profit CurTrade=DoubleToStr(TPF,2); //show the current profit if(TPF > ExpectProfit$) //when they need to close { BOpen=0; //set the new value of order open price HOpen=0; //and block the profit calculation process CurTrade="No Any Hedge Order Now."; //Hedge was closed floating=0; //mark as hedge was closed CurB+=TPF; CurBalance=CurB; //get the last balance equity pstr=pstr+DoubleToStr(CurBalance,2)+","; //insert into performance string CreateObject("R : "+on,OBJ_TEXT,Time[0],Close[0],0,0,YellowGreen,"", "Close With Profit Of : "+DoubleToStr(TPF,2)); //create the closed text if(PrintDetails) //Print the last Close detail { Print(on+" Closed "+BaseSymbol+" @ "+DoubleToStr(BTick,Digits)); Print(on+" Closed "+HedgeSymbol+" @ "+DoubleToStr(HTick,Digits)); Print(on+" Closed Hedge With Profit : "+DoubleToStr(TPF,2)); } hr =FileOpen(RName ,FILE_CSV|FILE_WRITE); //open it again to prepair for file writing if(hr>0) { FileWrite(hr,pstr); //export the data FileClose(hr); } if(StringLen(pstr)>4086){p++;pstr="";} //set the new file name if pstr is larger than 4086 characters thep=FileOpen("p.csv",FILE_CSV|FILE_WRITE); // record the p value again if(thep>0) // if the file exist { ps=DoubleToStr(p,0); // transform into string FileWrite(thep,ps); // write p FileClose(thep); // done } } } } else //in case the data values are not from the same tick time { if(BTTime>HTTime){trimb=false;} //freeze the offside data to can not be trim off else {trimh=false;} } } else //in case tick data is offside from today { if(BTTime>BD1Time){trimb=false;} //freeze the offside data to can not be trim off else if(BTTime<BD1Time){trimbd1=false;} if(HTTime>HD1Time){trimh=false;} else if(HTTime<HD1Time){trimhd1=false;} } } lastTick=Hour(); //mark as latest tick proceeded } Comment("\nBOpen : "+DoubleToStr(BOpen,Digits) //show the current situation ,"\nHOpen : "+DoubleToStr(HOpen,Digits) ,"\nBOT : "+TimeToStr(BD1Time,TIME_DATE) ,"\nHOT : "+TimeToStr(HD1Time,TIME_DATE) ,"\nBTick : "+DoubleToStr(BTick,Digits) ,"\nHTick : "+DoubleToStr(HTick,Digits) ,"\nBTT : "+TimeToStr(BTTime,TIME_DATE|TIME_MINUTES) ,"\nHTT : "+TimeToStr(HTTime,TIME_DATE|TIME_MINUTES) ,"\nfloating : "+floating ,"\nclosed : "+closed ,"\ntrimb : "+trimb ,"\ntrimh : "+trimh ,"\n" ,"\nCurOrderNo. : "+on ,"\nCurProfit : "+CurTrade ,"\nCurBalance : "+DoubleToStr(CurBalance,2) ); //---- return(0); //ALL DONE. } //+------------------------------------------------------------------+ //| A Function To Make This Virtual Tester Looks Like The Real One | //+------------------------------------------------------------------+ void CreateObject(string name,int type, int time1, double price1, int time2, double price2, color cl,string ordtype,string txt) { if(type==OBJ_TREND) { ObjectCreate(name,type,0,time1,price1,time2,price2); ObjectSet(name,OBJPROP_COLOR,HotPink); } if(type==OBJ_ARROW) { ObjectCreate(name,type,0,time1,price1); ObjectSet(name,OBJPROP_COLOR,cl); if(ordtype=="sell")ObjectSet(name,OBJPROP_ARROWCODE,221); else ObjectSet(name,OBJPROP_ARROWCODE,222); } if(type==OBJ_TEXT) { ObjectCreate(name,type,0,time1,price1); ObjectSetText(name,txt,8,"Comic Sans MS",cl); } } //+------------------------------------------------------------------+ //| GETTING ALL DATA FROM FILES FUNCTION | //+------------------------------------------------------------------+ void getdata(string sym) { Comment("Collecting Data.","\n\nPlease Wait........"); //let us know that getting data still in process int x =FileOpen(sym+"x.csv",FILE_CSV|FILE_READ) //get how many files of D1 and tick ,xt=FileOpen(sym+"xt.csv",FILE_CSV|FILE_READ) ,pter=0,s=0,v=0 ,lastME=0,t=0 ; double ME,U; string str,str2; int xa=StrToInteger(FileReadString(x)) ,xta=StrToInteger(FileReadString(xt)) ,xtc=1 ; FileClose(x); FileClose(xt); if(xta>xa)xtc=xta; //make it run only in one for loop else xtc=xa; pter=0;s=0; for(int i=1;i<=xtc;i++) //the loop to get all string data { string name=sym+i+"T.csv" //set the data file name ,d1 =sym+i+"D1.csv" ; int h=FileOpen(name,FILE_CSV|FILE_READ) //open all files to read ,d=FileOpen(d1 ,FILE_CSV|FILE_READ); //------------------------------------------------------------ string source=FileReadString(h); //read the tick string FileClose(h); if(sym==BaseSymbol) //if get the data of base symbol { btstr=btstr+source; } else //if hedge symbol { htstr=htstr+source; } //------------------------------------------------------------ if(d>0) //read the daily data { string d1s =FileReadString(d);FileClose(d); if(sym==BaseSymbol) //if get base daily data { bstr=bstr+d1s; } else //if get hedge data { hstr=hstr+d1s; } } } } //------------------------------------ALL DONE---------------------------------------------//
گام ۳. بازبینی نتیجه
بعد از اینکه معاملات مجازی انجام و نتایج هج ثبت شدند، میتوانیم آن دادهها را برداشته تا مفهوم هجینگمان را نشان دهیم. برای انجام این کار، تصمیم گرفتم تمام دادههای ثبتشده را بهعنوان یک اندیکاتور برای ترسیم منحنی عملکرد در یک پنجرهی جدا، همانند بسیاری از اندیکاتورها مثل CCI، RSI، و ATR و غیره، خروجی بگیرم. تمام فایلهای اکسپرت دوم نیز باید در مسیر “MetaTrader 4/experts/files” کپی شوند.
برای اتمام این منحنی، اندیکاتور زیر نیاز است.
//+------------------------------------------------------------------+ //| performance.mq4 | //| A Sexy Trader | //| http://pipsmaker.wordpress.com/ | //+------------------------------------------------------------------+ #property copyright "A Sexy Trader" #property link "http://pipsmaker.wordpress.com/" #property indicator_separate_window #property indicator_buffers 1 #property indicator_color1 Goldenrod //---- input parameters extern string BaseSymbol="GBPJPY"; extern string HedgeSymbol="EURJPY"; //---- buffers double ExtMapBuffer1[] //this is the indicator buffer ,curve[8888888] //this array is for collecting the result from the performance file ; int handle; //maybe no need to explain anymore string data; int len=0 ,i=0 ,j=0 ,p ,pv ,pter=0 ; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,ExtMapBuffer1); IndicatorShortName(BaseSymbol+"~"+HedgeSymbol+" "); //---- p =FileOpen("p.csv",FILE_CSV|FILE_READ); //get how many result files were exported pv=StrToInteger(FileReadString(p)); FileClose(p); for(int i=1;i<=pv;i++) //the loop to get all exported result as a string { string name = BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv";//get the name of the performance file handle=FileOpen(name,FILE_CSV|FILE_READ); //search for the file to open to read if(handle>0) //if the file is exist { data=data+FileReadString(handle); //get the whole data FileClose(handle); //close it } } //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { int counted_bars=IndicatorCounted(),i=0,s=-1; //---- len=StringLen(data); //get the lenght of the data string pter=0; //set the pointer which use for searching the "," /*please be informed that the file csv was collected the result as a string like this ۱۰۰۰.۵۴,۱۱۰۰.۵۴,۱۲۰۰.۵۴,۱۳۰۰.۵۴,۱۴۰۰.۵۴ but the fact is we want only the real data is like this ۱۰۰۰.۵۴ ۱۱۰۰.۵۴ ۱۲۰۰.۵۴ ۱۳۰۰.۵۴ ۱۴۰۰.۵۴ so the "," is the key to get the data as above and it can be done by finding out the data befor "," and get rid off it from the whole data to shift the next data into the front and insert each taken off data into the curve array */ for(i=len;i>=0;i--) /*the loop to define how many room this array should build { to contain the performance data */ if(StringFind(data,",",0)>0) //if there is a nearest "," from the front { s++; //indicate the room number pter=StringFind(data,",",0); //get the point where the first "," exist curve[s]=StrToDouble(StringSubstr(data,0,pter));//insert the first data of the whole string data=StringSubstr(data,pter+1,0); //cut the inserted data off } else break; //no data to count anymore , break the loop ArrayResize(curve,s+1); //resize the curve array for furthur usage //---- for(i=0,j=s;i<=s;i++,j--) //the plotting process bigin { if(curve[j]>0)ExtMapBuffer1[i]=curve[j]; //plot the performance curve } //---- //all the things done. return(0); } //+------------------------------------------------------------------+
چگونه از آنها استفاده کنیم
قبل از اینکه یک کپی از کد من را دانلود کنید، بیایید کوتاه به “چگونگی استفاده از آنها” بپردازیم و به آن بهچشم یک مینیدستتورالعمل نگاه کنید.
برای اینکه انتظاراتمان را واقعاً برآورده کنیم، ۵ قدم ساده باید برداریم که نمیشود از آنها صرفنظر کرد.
- در تستر (نیازی به حالت ویژوال نیست)، در منوی “Expert Advisor:”، symbol-D1.mq4 را انتخاب کنید، و در “Symbol:”، اولین نماد هجِ جفتاَرز هج مورد علاقهی خود را انتخاب کنید، دورهی تاریخ و زمان را تعیین کنید و اگر این نماد جهت معاملهی Sell است، مقدار “For_OP_SELL” را true تعیین کنید، و اگر برای معاملهی Buy است، آن را false تعیین کنید، و برای منوی “Period:”، دورهی hourly (ساعتی) را انتخاب کرده و “Start” را بزنید تا فرآیند ثبت، شروع شود.
- برای نماد دوم هج، همان مراحل شمارهی ۱ را انجام دهید، ***فراموش نکنید که پارامتر “For_OP_SELL” را تغییر دهید*** تا متناسب با نوع معاملهی این نماد باشد.
- mq4 را انتخاب کنید، تمام متغیرها را تعیین کنید، و نماد مورد نظر برای تست را انتخاب کنید (هر نمادی که دوست دارید). اما این کار نیاز به حالت ویژوال دارد تا بتوان عملکرد هج را دید.
- تمام فایلهای مربوط به نشان دادن کارایی هج را از “program files/metatrader 4/tester/files” به “program files/metatrader 4/experts/files” کپی کنید (csv و p.csv. اگر بیش از یک فایل نتیجه داشتید، میبایستی همه را کپی کنید).
- mq4 را به هر نموداری که در حال حاضر فعال است، متصل کنید تا عملکرد هج را در حالت تقریباً واقعی ببینید.
و این منحنی عملکرد، حاصل قوانین تجربی من است.

اوه! خیلی زشت است اما مطمئناً منحنی شما بهتر خواهد بود.
نتیجهگیری
بسیار خوشحالم که اکنون قدم به دنیای جدید تست اکسپرتهای هج گذاشتهایم. دیگر مشکل محدودیت نداریم. اما بهیاد داشته باشید که مفهوم هجینگ که در این مقاله مطرح شد، فقط مثال است و برای کوتاه کردن زمان تست گرفتن ایجاد شدهاست. اگر میخواهید تستر مجازی با استراتژی هج شما کار کند، میبایستی دادههای خاص خود، مانند بازشدن و بستهشدن هر روز، high، low، یا هر نوع دیگری را لیست کنید. و اگر میخواهید با همبستگی ترید کنید، تمام مقادیر همبستگی برای هر زمان خاصی باید خروجی گرفته شوند. با این لیست شما میدانید که چه دادهای باید ثبت شود، چه دادهای باید محاسبه شود، و چه دادهای را باید بهعنوان نتیجه، خروجی گرفت. و برای کوتاهتر شدن زمان پردازش دادههای خود، پیشنهاد میکنم دورهی تست خود را چند قسمت کنید – که بهتر از این است که همه را در یک زمان پردازش کنید. برای مثال اگر میخواهید اکسپرت خود را برای ۱ سال تست کنید، میتوانید ۴ بخش سه ماهه درنظر بگیرید. امیدوارم منحنی عملکرد شما شکلی دلفریب داشته باشد و امیدوارم این مقاله به شما معاملهگران هج کمک کند، یا حداقل بخشی از این مقاله برای شما مفید بوده باشد و یا از این مقاله الهام گرفته و نتایج عالی کسب کنید.
این مقاله دارای فایل پیوست است.
فایل پیوست را از اینجا میتوانید دانلود کنید .
یک مورد نظر
Thanks for sharing your thoughts on cialis professional. Regards