
Alım Satım Raporları ve SMS Bildirimi Oluşturma ve Yayınlama
Giriş
Bu makalede, alım satım sonuçları raporunun (Expert Advisor, Gösterge veya Script Dosyası kullanılarak) HTML dosyası olarak nasıl oluşturulacağı ve FTP yoluyla WWW-sunucusuna nasıl yükleneceği açıklanmaktadır. Ayrıca alım satım etkinliklerine ilişkin bildirimlerin cep telefonuna SMS olarak gönderilmesini de değerlendireceğiz.
Bu makalede açıklanan materyali daha rahat kullanabilmek için okuyucunun HTML (Köprü Metni Biçimlendirme Dili) hakkında bilgi sahibi olması önerilir.
Yükleme raporlarını uygulamak için FTP yoluyla veri alınabilen bir WWW-sunucusuna (herhangi bir bilgisayar olabilir) ihtiyacımız var. Alım satım etkinlikleriyle ilgili bildirimleri SMS olarak alma olasılığını uygulamak için bir E-POSTA-SMS ağ geçidine ihtiyacımız var (bu hizmet birçok cep telefonu operatörü ve üçüncü taraf kuruluş tarafından sağlanmaktadır).
1. Rapor Oluşturma ve FTP aracılığıyla Gönderme
Bir alım satım raporu oluşturan ve FTP-protokolü aracılığıyla gönderen bir MQL5-programı oluşturalım. İlk olarak, bunu Script dosyası olarak yapıyoruz. Gelecekte bunu, Expert Advisor'lara ve Göstergelere eklenebilecek bitmiş bir blok olarak kullanabiliriz. Örneğin, Expert Adviser'larda bu bloğu, alım satım talebinden sonra bu bloğu çalıştırmak veya ChartEvent olayı için bazı işlemleri ayarlamak için Alım Satım veya Zamanlayıcı olay işleyicisi olarak kullanabilirsiniz. Göstergelerde, bu bloğu Zamanlayıcı veya ChartEvent olay işleyicilerine dahil edebilirsiniz.
Program tarafından oluşturulan rapor örneği Şekil 1, 2 ve 3'te gösterilmiştir. Veya bu raporu makalenin sonunda bulunan bağlantıdan indirebilirsiniz.
Şekil 1. Rapor Örneği - Yatırımlar ve Pozisyonlar Tablosu.
Şekil 2. Rapor Örneği - Denge Grafiği.
Şekil 3. Rapor Örneği - Mevcut Enstrüman Fiyat Grafiği.
Yatırımlar ve pozisyonlar tablosunda (Şekil 1) kolaylık sağlamak için tüm yatırımlar pozisyonlara ayrılmıştır. Tablonun sol tarafında, piyasaya giriş hacmi, zamanı ve fiyatı (açılış pozisyonları ve eklemeler) gösterilmiştir. Tablonun sağ tarafında, piyasadan çıkmak için aynı parametreler gösterilmiştir (pozisyonun kısmen veya tamamen kapanması). Giriş/çıkışta yatırım iki kısma ayrılmıştır; bir pozisyonun kapanması ve bir sonraki pozisyonun açılması.
Yatırımlar ve pozisyonlar tablosunun altında denge tablosu (yatay eksen - zaman) ve altta mevcut enstrümanın fiyat grafiği gösterilmiştir.
Program, MetaTarder5_istall_dir\MQL5\Files klasöründe "report.html", "picture1.gif" ve "picture2.gif" dosyalarını (raporun html-dosyası, denge grafiği ve fiyat grafiğinin resim dosyaları) oluşturur. Ve FTP yayınlama özelliği, terminal ayarlarında etkinleştirilir - Bu üç dosyayı belirtilen sunucuya gönderir. Ayrıca, iki dosyaya daha ihtiyacımız olacak - oklarla açık pozisyonu gösteren resimler - Al veya Sat ("buy.gif" ve "sell.gif"). Bu resimleri (makalenin sonundaki indirme bağlantısı) alabilir veya herhangi bir grafik düzenleyicisinde kendiniz çizebilirsiniz. Bu iki dosya, "report.html" dosyası ile WWW-sunucusunun aynı klasörüne yerleştirilmelidir.
Giriş parametreleri olarak program, raporun oluşturulduğu dönemin başlangıç ve bitiş zamanını kabul eder. Örneğimizde, rapor döneminin sonu geçerli saattir ve kullanıcı rapor döneminin varyantını seçer: Tüm dönem, son gün, geçen hafta, geçen ay veya geçen yıl.
Raporun nasıl oluşturulduğu hakkında birkaç şey söyleyeceğim. Mevcut tüm yatırım geçmişi için alım satım sunucusu istenir. Elde edilen yatırımlar art arda işlenir. Deal_status[] dizisi, yatırımın işlenip işlenmediği hakkında bilgi depolar. Bu dizinin öğe indeksleri, yatırımların alım satım sunucusu listesinden alınan yatırım numaralarıdır. Ve öğe değerleri şu şekilde yorumlanır: 0 - yatırım henüz işlenmedi, 1 - yatırım zaten kısmen işlendi (giriş/çıkış), 127 - yatırım zaten işlendi (diğer değerler kullanılmadı ve ileride kullanılmak üzere ayrıldı).
Symb_list[] dizisi, alım satım işleminin gerçekleştirildiği finansal enstrüman adlarının listesini ve lot_list[] dizisi yatırımın işlenmesi sırasında her bir enstrüman için açık pozisyonların hacimlerini içerir. Pozitif hacim değerleri uzun pozisyonlara, negatif hacim değerleri kısa pozisyonlara karşılık gelir. Hacim sıfıra eşitse, bu, aracın açık pozisyonu olmadığı anlamına gelir. Yatırımlar sırasında listede olmayan (symb_list[] dizisinde) bir finansal enstrümanın işlenmesiyle karşılaşılırsa, oraya eklenir ve finansal enstrümanların sayısı (symb_total değişkeni) 1 değer artırılır.
Her yatırımda, sonraki her yatırımın işlenmesi, pozisyon kapanana veya giriş/çıkışa kadar aynı finansal enstrüman tarafından analiz edilir. Yalnızca deal_status[] dizisinin değeri 127'den küçük olan yatırımlar analiz edilir. Yatırım işlendikten sonra, deal_status[] dizisinin karşılık gelen öğesine 127 değeri atanır ve yatırım pozisyonun içinde/dışındaysa 1 değeri atanır. Pozisyonun açıldığı zaman, rapor dönemiyle eşleşirse (StartTime ve EndTime değişkenleri tarafından tanımlanır) - bu pozisyon raporlanmak üzere günlüğe kaydedilir (tüm girişler ve çıkışlar).
Yatırımlar tablosuna ek olarak, mevcut finansal enstrüman için yeni bir grafik açılır. Bu grafik için gerekli tüm özellikler sağlanır ve ChartScreenShot() işlevi kullanılarak bir ekran görüntüsü alınır; böylece mevcut enstrüman için fiyat grafiğini içeren bir resim dosyası elde ederiz. Daha sonra bu grafikte fiyat grafiği maskelenir ve bakiye değişim grafiği çizilir ve ardından başka bir ekran görüntüsü oluşturulur.
Grafikler içeren iki resim dosyası ve rapor içeren bir HTML dosyası oluşturulduğunda, FTP üzerinden dosya gönderme özelliği kontrol edilir. İzin verilmesi halinde, "report.html", "picture1.gif" ve "picture2.gif" dosyaları MetaTrader 5'te belirtilen ayarlara göre SendFTP() işlevi kullanılarak gönderilir.
MetaQuotes Dil Düzenleyicisini başlatın ve bir script dosyası oluşturmaya başlayın. Sabitleri tanımlayın; grafik yenileme zaman aşımı (saniye cinsinden), fiyat grafiğinin genişliği ve yüksekliği ve denge grafiğinin maksimum genişliği. Bakiye değişim eğrisini gösterecek olan grafiğin dönemi, rapor döneminin süresine ve grafiğin maksimum genişliğine göre seçilir. Grafiğin genişliği, denge grafiği için gerekli olan boyuta göre ayarlanır.
Grafiğin yüksekliği otomatik olarak genişliğin yarısı olarak hesaplanır. Ayrıca, dikey eksenin genişliğini sabit olarak belirleyeceğiz; bu, dikey eksen nedeniyle grafik alanının resmin genişliğine kıyasla azaldığı piksel sayısıdır.
#define timeout 10 // chart refresh timeout #define Picture1_width 800 // max width of chart in report #define Picture2_width 800 // width of price chart in report #define Picture2_height 600 // height of price chart in report #define Axis_Width 59 // width of vertical axis (in pixels)
Giriş parametrelerinin kullanıcıdan talep edileceğini belirtin.
// request input parameters #property script_show_inputs
Rapor dönemlerinin numaralandırmasını oluşturun.
// enumeration of report periods enum report_periods { All_periods, Last_day, Last_week, Last_month, Last_year };
Kullanıcıdan rapor dönemini isteyin (bu, varsayılan olarak tüm süredir).
// ask for report period input report_periods ReportPeriod=0;
OnStart() işlevinin gövdesini yazın.
void OnStart() {
Rapor döneminin başlangıcını ve sonunu belirleyin.
datetime StartTime=0; // beginning of report period datetime EndTime=TimeCurrent(); // end of report period // calculating the beginning of report period switch(ReportPeriod) { case 1: StartTime=EndTime-86400; // day break; case 2: StartTime=EndTime-604800; // week break; case 3: StartTime=EndTime-2592000; // month break; case 4: StartTime=EndTime-31536000; // year break; } // if none of the options is executed, then StartTime=0 (entire period)
Programda kullanılacak değişkenleri bildirin. Değişkenlerin amacı açıklamalarda belirtilmiştir.
int total_deals_number; // number of deals for history data int file_handle; // file handle int i,j; // loop counters int symb_total; // number of instruments, that were traded int symb_pointer; // pointer to current instrument char deal_status[]; // state of deal (processed/not processed) ulong ticket; // ticket of deal long hChart; // chart id double balance; // current balance value double balance_prev; // previous balance value double lot_current; // volume of current deal double lots_list[]; // list of open volumes by instruments double current_swap; // swap of current deal double current_profit; // profit of current deal double max_val,min_val; // maximal and minimal value string symb_list[]; // list of instruments, that were traded string in_table_volume; // volume of entering position string in_table_time; // time of entering position string in_table_price; // price of entering position string out_table_volume; // volume of exiting position string out_table_time; // time of exiting position string out_table_price; // price of exiting position string out_table_swap; // swap of exiting position string out_table_profit; // profit of exiting position bool symb_flag; // flag that instrument is in the list datetime time_prev; // previous value of time datetime time_curr; // current value of time datetime position_StartTime; // time of first enter to position datetime position_EndTime; // time of last exit from position ENUM_TIMEFRAMES Picture1_period; // period of balance chart
Yeni bir grafik açın ve özelliklerini ayarlayın; bu, raporun alt kısmındaki çıkış olacak fiyat grafiğidir.
// open a new chart and set its properties hChart=ChartOpen(Symbol(),0); ChartSetInteger(hChart,CHART_MODE,CHART_BARS); // bars chart ChartSetInteger(hChart,CHART_AUTOSCROLL,true); // autoscroll enabled ChartSetInteger(hChart,CHART_COLOR_BACKGROUND,White); // white background ChartSetInteger(hChart,CHART_COLOR_FOREGROUND,Black); // axes and labels are black ChartSetInteger(hChart,CHART_SHOW_OHLC,false); // OHLC are not shown ChartSetInteger(hChart,CHART_SHOW_BID_LINE,true); // show BID line ChartSetInteger(hChart,CHART_SHOW_ASK_LINE,false); // hide ASK line ChartSetInteger(hChart,CHART_SHOW_LAST_LINE,false); // hide LAST line ChartSetInteger(hChart,CHART_SHOW_GRID,true); // show grid ChartSetInteger(hChart,CHART_SHOW_PERIOD_SEP,true); // show period separators ChartSetInteger(hChart,CHART_COLOR_GRID,LightGray); // grid is light-gray ChartSetInteger(hChart,CHART_COLOR_CHART_LINE,Black); // chart lines are black ChartSetInteger(hChart,CHART_COLOR_CHART_UP,Black); // up bars are black ChartSetInteger(hChart,CHART_COLOR_CHART_DOWN,Black); // down bars are black ChartSetInteger(hChart,CHART_COLOR_BID,Gray); // BID line is gray ChartSetInteger(hChart,CHART_COLOR_VOLUME,Green); // volumes and orders levels are green ChartSetInteger(hChart,CHART_COLOR_STOP_LEVEL,Red); // SL and TP levels are red ChartSetString(hChart,CHART_COMMENT,ChartSymbol(hChart)); // comment contains instrument <end segm
Bir grafiğin ekran görüntüsünü alın ve "picture2.gif" olarak kaydedin.
// save chart as image file ChartScreenShot(hChart,"picture2.gif",Picture2_width,Picture2_height);
Tüm hesap varlığı süresi için yatırım geçmişi isteyin.
// request deals history for entire period HistorySelect(0,TimeCurrent());
Rapor içeren (ANSI kodlaması) HTML sayfasını yazacağımız "report.html" dosyasını açın.
// open report file file_handle=FileOpen("report.html",FILE_WRITE|FILE_ANSI);
HTML-belgesinin başlangıç kısmını yazın:
- html-belgesinin başlangıcı (<html>)
- Tarayıcı pencerenizin üst kısmında görüntülenecek olan başlık (<head><title>Expert Alım Satım Raporu</title></head>)
- arka plan rengiyle html-belgesinin ana bölümünün başlangıcı (<body bgcolor='#EFEFEF'>)
- Orta hizalama (<center> )
- Yatırımlar ve pozisyonlar tablosunun başlığı (<h2>Alım Satım Raporu</h2>)
- Hizalama, kenarlık genişliği, arka plan rengi, kenarlık rengi, hücre aralığı ve hücre dolgusu ile yatırımlar ve pozisyonlar tablosunun başlangıcı (<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>)
- Tablo başlığı
// write the beginning of HTML FileWrite(file_handle,"<html>"+ "<head>"+ "<title>Expert Trade Report</title>"+ "</head>"+ "<body bgcolor='#EFEFEF'>"+ "<center>"+ "<h2>Trade Report</h2>"+ "<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>"+ "<tr>"+ "<th rowspan=2>SYMBOL</th>"+ "<th rowspan=2>Direction</th>"+ "<th colspan=3>Open</th>"+ "<th colspan=3>Close</th>"+ "<th rowspan=2>Swap</th>"+ "<th rowspan=2>Profit</th>"+ "</tr>"+ "<tr>"+ "<th>Volume</th>"+ "<th>Time</th>"+ "<th>Price</th>"+ "<th>Volume</th>"+ "<th>Time</th>"+ "<th>Price</th>"+ "</tr>");
Listedeki yatırım sayısını alma.
// number of deals in history total_deals_number=HistoryDealsTotal();
symb_list[], lots_list[] ve deal_status[] dizileri için boyutları ayarlama.
// setting dimensions for the instruments list, the volumes list and the deals state arrays ArrayResize(symb_list,total_deals_number); ArrayResize(lots_list,total_deals_number); ArrayResize(deal_status,total_deals_number);
deal_status[] dizisinin tüm öğeleri 0 değeriyle başlatılıyor - Tüm yatırımlar işlenmez.
// setting all elements of array with value 0 - deals are not processed ArrayInitialize(deal_status,0);
Bir önceki bakiye değerini saklamak için kullanılan bakiye ve değişkenin başlangıç değerlerinin ayarlanması.
balance=0; // initial balance balance_prev=0; // previous balance
Listedeki finansal enstrümanların sayısını saklamak için kullanılan değişkenin başlangıç değerinin ayarlanması.
// number of instruments in the list symb_total=0;
Listedeki her yatırımı sıralı olarak işleyen bir döngü oluşturun.
// processing all deals in history for(i=0;i<total_deals_number;i++) {
Mevcut yatırımı seçin ve biletini alın.
//select deal, get ticket ticket=HistoryDealGetTicket(i);
Bakiyenin mevcut yatırımdaki kar miktarına göre değiştirilmesi.
// changing balance balance+=HistoryDealGetDouble(ticket,DEAL_PROFIT);
Yatırım zamanının elde edilmesi; bu, daha sık kullanılacaktır.
// reading the time of deal time_curr=HistoryDealGetInteger(ticket,DEAL_TIME);
Bu, listedeki ilk yatırım ise rapor döneminin sınırlarını ayarlamamız ve rapor döneminin süresine ve grafiğin çizileceği bölgenin genişliğine bağlı olarak bakiye grafiği için dönemi seçmemiz gerekir. Maksimum ve minimum bakiyelerin başlangıç değerlerinin ayarlanması (bu değişkenler, grafiğin maksimum ve minimum değerlerini ayarlamak için kullanılacaktır.)
// if this is the first deal if(i==0) { // if the report period starts before the first deal, // then the report period will start from the first deal if(StartTime<time_curr) StartTime=time_curr; // if report period ends before the current time, // then the end of report period corresponds to the current time if(EndTime>TimeCurrent()) EndTime=TimeCurrent(); // initial values of maximal and minimal balances // are equal to the current balance max_val=balance; min_val=balance; // calculating the period of balance chart depending on the duration of // report period Picture1_period=PERIOD_M1; if(EndTime-StartTime>(Picture1_width-Axis_Width)) Picture1_period=PERIOD_M2; if(EndTime-StartTime>(Picture1_width-Axis_Width)*120) Picture1_period=PERIOD_M3; if(EndTime-StartTime>(Picture1_width-Axis_Width)*180) Picture1_period=PERIOD_M4; if(EndTime-StartTime>(Picture1_width-Axis_Width)*240) Picture1_period=PERIOD_M5; if(EndTime-StartTime>(Picture1_width-Axis_Width)*300) Picture1_period=PERIOD_M6; if(EndTime-StartTime>(Picture1_width-Axis_Width)*360) Picture1_period=PERIOD_M10; if(EndTime-StartTime>(Picture1_width-Axis_Width)*600) Picture1_period=PERIOD_M12; if(EndTime-StartTime>(Picture1_width-Axis_Width)*720) Picture1_period=PERIOD_M15; if(EndTime-StartTime>(Picture1_width-Axis_Width)*900) Picture1_period=PERIOD_M20; if(EndTime-StartTime>(Picture1_width-Axis_Width)*1200) Picture1_period=PERIOD_M30; if(EndTime-StartTime>(Picture1_width-Axis_Width)*1800) Picture1_period=PERIOD_H1; if(EndTime-StartTime>(Picture1_width-Axis_Width)*3600) Picture1_period=PERIOD_H2; if(EndTime-StartTime>(Picture1_width-Axis_Width)*7200) Picture1_period=PERIOD_H3; if(EndTime-StartTime>(Picture1_width-Axis_Width)*10800) Picture1_period=PERIOD_H4; if(EndTime-StartTime>(Picture1_width-Axis_Width)*14400) Picture1_period=PERIOD_H6; if(EndTime-StartTime>(Picture1_width-Axis_Width)*21600) Picture1_period=PERIOD_H8; if(EndTime-StartTime>(Picture1_width-Axis_Width)*28800) Picture1_period=PERIOD_H12; if(EndTime-StartTime>(Picture1_width-Axis_Width)*43200) Picture1_period=PERIOD_D1; if(EndTime-StartTime>(Picture1_width-Axis_Width)*86400) Picture1_period=PERIOD_W1; if(EndTime-StartTime>(Picture1_width-Axis_Width)*604800) Picture1_period=PERIOD_MN1; // changing the period of opened chart ChartSetSymbolPeriod(hChart,Symbol(),Picture1_period); }
Bu ilk yatırım değilse bakiye değişikliği grafiğinin çizildiği "çizgi" nesnesini oluşturun. Çizgi, yalnızca en az birinin ucu rapor dönemindeyse çizilir. Her iki uç da rapor dönemindeyse çizgi "kalın" olacaktır. Bakiye çizgisinin rengi yeşildir. Bakiye, minimum ve maksimum bakiye aralığının dışındaysa bu aralık ayarlanır.
else // if this is not the first deal { // plotting the balance line, if the deal is in the report period, // and setting properties of the balance line if(time_curr>=StartTime && time_prev<=EndTime) { ObjectCreate(hChart,IntegerToString(i),OBJ_TREND,0,time_prev,balance_prev,time_curr,balance); ObjectSetInteger(hChart,IntegerToString(i),OBJPROP_COLOR,Green); // if both ends of line are in the report period, // it will be "thick" if(time_prev>=StartTime && time_curr<=EndTime) ObjectSetInteger(hChart,IntegerToString(i),OBJPROP_WIDTH,2); } // if new value of balance exceeds the range // of minimal and maximal values, it must be adjusted if(balance<min_val) min_val=balance; if(balance>max_val) max_val=balance; }
Karşılık gelen değişkene zamanın önceki değerini atayın.
// changing the previous time value
time_prev=time_curr;
Yatırım henüz işlenmediyse işleyin.
// if the deal has not been processed yet if(deal_status[i]<127) {
Bu yatırım bakiye yükü ise ve rapor döneminde ise rapora karşılık gelen dize yazılır. Yatırım, işlendi olarak işaretlenir.
// If this deal is balance charge if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BALANCE) { // if it's in the report period - write the corresponding string to report. if(time_curr>=StartTime && time_curr<=EndTime) FileWrite(file_handle,"<tr><td colspan='9'>Balance:</td><td align='right'>",HistoryDealGetDouble(ticket,DEAL_PROFIT), "</td></tr>"); // mark deal as processed deal_status[i]=127; }
Bu yatırım Al veya Sat ise, bu enstrümanın listede olup olmadığını kontrol edin (symb_list[] dizisi). Listede yoksa listeye dahil edin. symb_pointer değişkeni, geçerli yatırımın enstrüman adını içeren symb_list[] dizisinin öğesini gösterir.
// if this deal is buy or sell if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY || HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL) { // check if there is instrument of this deal in the list symb_flag=false; for(j=0;j<symb_total;j++) { if(symb_list[j]==HistoryDealGetString(ticket,DEAL_SYMBOL)) { symb_flag=true; symb_pointer=j; } } // if there is no instrument of this deal in the list if(symb_flag==false) { symb_list[symb_total]=HistoryDealGetString(ticket,DEAL_SYMBOL); lots_list[symb_total]=0; symb_pointer=symb_total; symb_total++; }
İlk ve son pozisyonun ömrünü saklayan position_StartTime ve position_EndTime değişkenlerinin başlangıç değerlerini ayarlayın.
// set the initial value for the beginning time of deal position_StartTime=time_curr; // set the initial value for the end time of deal position_EndTime=time_curr;
in_table_volume, in_table_time, in_table_price, out_table_volume, out_table_time, out_table_price, out_table_swap ve out_table_profit değişkenleri tabloları depolayacaktır; bunlar daha büyük tablonun hücrelerinde olacaktır: Hacim, piyasaya giriş zamanı ve fiyatı, hacim, zaman, fiyat, swap ve piyasadan çıkış karı. in_table_volume değişkeni ayrıca finansal enstrümanın adını depolar ve açık pozisyonun yönüne karşılık gelen bir resme bağlantı verir. Tüm bu değişkenlere başlangıç değerleri atayın.
// creating the string in report - instrument, position direction, beginning of table for volumes to enter the market if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY) StringConcatenate(in_table_volume,"<tr><td align='left'>",symb_list[symb_pointer], "</td><td align='center'><img src='buy.gif'></td><td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"); if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL) StringConcatenate(in_table_volume,"<tr><td align='left'>",symb_list[symb_pointer], "</td><td align='center'><img src='sell.gif'></td><td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"); // creating the beginning of time table to enter the market in_table_time="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of price table to enter the market in_table_price="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of volume table to exit the market out_table_volume="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of time table to exit the market out_table_time="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of price table to exit the market out_table_price="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of swap table to exit the market out_table_swap="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>"; // creating the beginning of profit table to exit the market out_table_profit="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>";
Mevcut ile başlayan tüm yatırımları pozisyon kapanana kadar işleyin. Bunlar daha önce işlenmemişlerse, hepsini işleyin.
// process all deals for this position starting with the current(until position is closed) for(j=i;j<total_deals_number;j++) { // if the deal has not been processed yet - process it if(deal_status[j]<127) {
Yatırımı seçin ve biletini alın.
// select deal, get ticket ticket=HistoryDealGetTicket(j);
Yatırım, açık pozisyonla aynı enstrümandaysa bunu işleyin. Yatırım zamanını alın. Yatırım süresi, pozisyon süresi aralığının ötesine geçerse aralığı genişletin. Yatırım hacmini alın.
// if the instrument of deal matches the instrument of position, that is processed if(symb_list[symb_pointer]==HistoryDealGetString(ticket,DEAL_SYMBOL)) { // get the deal time time_curr=HistoryDealGetInteger(ticket,DEAL_TIME); // If the deal time goes beyond the range of position time // - extend position time if(time_curr<position_StartTime) position_StartTime=time_curr; if(time_curr>position_EndTime) position_EndTime=time_curr; // get the volume of deal lot_current=HistoryDealGetDouble(ticket,DEAL_VOLUME);
Al ve Sat yatırımları ayrı olarak işlenir. Al yatırımlarıyla başlayın.
// if this deal is buy if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY) {
Halihazırda Sat için pozisyon açtıysanız bu Al yatırımı piyasadan çıkacaktır. Ve yatırım hacmi, açılan kısa pozisyon hacminden daha büyük olacaksa, bu giriş/çıkış olacaktır. Dize değişkenlerine gerekli değerleri atayın. deal_status[] dizisine, yatırım tam olarak işleniyorsa 127 değerini veya giriş/çıkış ise 1 değerini atayın; bu yatırım başka bir pozisyon için analiz edilmelidir.
// if position is opened for sell - this will be exit from market if(NormalizeDouble(lots_list[symb_pointer],2)<0) { // if buy volume is greater than volume of opened short position - then this is in/out if(NormalizeDouble(lot_current+lots_list[symb_pointer],2)>0) { // creating table of volumes to exit the market - indicate only volume of opened short position StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(-lots_list[symb_pointer],2),"</td></tr>"); // mark position as partially processed deal_status[j]=1; } else { // if buy volume is equal or less than volume of opened short position - then this is partial or full close // creating the volume table to exit the market StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>"); // mark deal as processed deal_status[j]=127; } // creating the time table to exit the market StringConcatenate(out_table_time,out_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>"); // creating the price table to exit the market StringConcatenate(out_table_price,out_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE), (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>"); // get the swap of current deal current_swap=HistoryDealGetDouble(ticket,DEAL_SWAP); // if swap is equal to zero - create empty string of the swap table to exit the market if(NormalizeDouble(current_swap,2)==0) StringConcatenate(out_table_swap,out_table_swap,"<tr></tr>"); // else create the swap string in the swap table to exit the market else StringConcatenate(out_table_swap,out_table_swap,"<tr><td align='right'>",DoubleToString(current_swap,2),"</td></tr>"); // get the profit of current deal current_profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); // if profit is negative (loss) - it is displayed as red in the profit table to exit the market if(NormalizeDouble(current_profit,2)<0) StringConcatenate(out_table_profit,out_table_profit,"<tr><td align=right><SPAN style='COLOR: #EF0000'>", DoubleToString(current_profit,2),"</SPAN></td></tr>"); // else - it is displayed as green else StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'><SPAN style='COLOR: #00EF00'>", DoubleToString(current_profit,2),"</SPAN></td></tr>"); }
Halihazırda uzun pozisyon açtıysanız bu yatırımdaki satın alma, piyasaya giriş olacaktır (ilk veya ek). Bu yatırıma karşılık gelen deal_status[] dizi öğesi 1 değerine sahipse giriş/çıkış yapılmış demektir. Dize değişkenlerini gerekli değerlerle atayın ve yatırımı işlendi olarak işaretleyin (dege_status[] dizisinin karşılık gelen öğesini 127 değerine atayın).
else // if position is opened for buy - this will be the enter to the market { // if this deal has been already partially processed (in/out) if(deal_status[j]==1) { // create the volume table of entering the market (volume, formed after in/out, is put here) StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lots_list[symb_pointer],2),"</td></tr>"); // indemnity of volume change, which will be produced (the volume of this deal is already taken into account) lots_list[symb_pointer]-=lot_current; } // if this deal has not been processed yet, create the volume table to enter the market else StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>"); // creating the time table of entering the market StringConcatenate(in_table_time,in_table_time,"<tr><td align center>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>"); // creating the price table of entering the market StringConcatenate(in_table_price,in_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE), (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>"); // mark deal as processed deal_status[j]=127; }
Pozisyon hacmini mevcut yatırım hacmi olarak değiştirin. Pozisyon kapalıysa (hacim sıfıra eşitse) bu pozisyonu işlemeyi bırakın (j değişkenli döngüden çıkın) ve sonraki işlenmemiş yatırımı arayın (i değişkenli döngüde).
// change of position volume by the current instrument, taking into account the volume of current deal lots_list[symb_pointer]+=lot_current; // if the volume of opened position by the current instrument became equal to zero - position is closed if(NormalizeDouble(lots_list[symb_pointer],2)==0 || deal_status[j]==1) break; }
Sat yatırımları benzer şekilde işlenir ve ardından j değişkenli döngüden çıkarız.
// if this deal is sell if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL) { // if position has been already opened for buy - this will be the exit from market if(NormalizeDouble(lots_list[symb_pointer],2)>0) { // if sell volume is greater than volume of opened long position - then this is in/out if(NormalizeDouble(lot_current-lots_list[symb_pointer],2)>0) { // creating table of volumes to exit the market - indicate only volume of opened long position StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lots_list[symb_pointer],2),"</td></tr>"); // mark position as partially processed deal_status[j]=1; } else { // if sell volume is equal or greater than volume of opened short position - then this is partial or full close // creating the volume table to exit the market StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>"); // mark deal as processed deal_status[j]=127; } // creating the time table to exit the market StringConcatenate(out_table_time,out_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>"); // creating the price table to exit the market StringConcatenate(out_table_price,out_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE), (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>"); // get the swap of current deal current_swap=HistoryDealGetDouble(ticket,DEAL_SWAP); // if swap is equal to zero - create empty string of the swap table to exit the market if(NormalizeDouble(current_swap,2)==0) StringConcatenate(out_table_swap,out_table_swap,"<tr></tr>"); // else create the swap string in the swap table to exit the market else StringConcatenate(out_table_swap,out_table_swap,"<tr><td align='right'>",DoubleToString(current_swap,2),"</td></tr>"); // get the profit of current deal current_profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); // if profit is negative (loss) - it is displayed as red in the profit table to exit the market if(NormalizeDouble(current_profit,2)<0) StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'> <SPAN style='COLOR: #EF0000'>",DoubleToString(current_profit,2),"</SPAN></td></tr>"); // else - it is displayed as green else StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'><SPAN style='COLOR: #00EF00'>", DoubleToString(current_profit,2),"</SPAN></td></tr>"); } else // if position is opened for sell - this will be the enter to the market { // if this deal has been already partially processed (in/out) if(deal_status[j]==1) { // create the volume table of entering the market (volume, formed after in/out, is put here) StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(-lots_list[symb_pointer],2),"</td></tr>"); // indemnity of volume change, which will be produced (the volume of this deal is already taken into account) lots_list[symb_pointer]+=lot_current; } // if this deal has not been processed yet, create the volume table to enter the market else StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>"); // creating the time table of entering the market StringConcatenate(in_table_time,in_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>"); // creating the price table of entering the market StringConcatenate(in_table_price,in_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE), (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>"); // mark deal as processed deal_status[j]=127; } // change of position volume by the current instrument, taking into account the volume of current deal lots_list[symb_pointer]-=lot_current; // if the volume of opened position by the current instrument became equal to zero - position is closed if(NormalizeDouble(lots_list[symb_pointer],2)==0 || deal_status[j]==1) break; } } } }
Pozisyonun açıldığı zaman rapor dönemindeyse (en azından kısmen) ilgili giriş "report.html" dosyasına gönderilir.
// if the position period is in the the report period - the position is printed to report if(position_EndTime>=StartTime && position_StartTime<=EndTime) FileWrite(file_handle, in_table_volume,"</table></td>", in_table_time,"</table></td>", in_table_price,"</table></td>", out_table_volume,"</table></td>", out_table_time,"</table></td>", out_table_price,"</table></td>", out_table_swap,"</table></td>", out_table_profit,"</table></td></tr>");
balance_prev değişkenini bakiye değeriyle atayın. i değişkenli döngüden çıkın.
}
// changing balance
balance_prev=balance;
}
HTML-dosyasının sonunu yazın (resimlere bağlantılar, orta hizalamanın sonu, ana bölümün sonu, HTML-belgesinin sonu). "report.html" dosyasını kapatın.
// create the end of html-file FileWrite(file_handle, "</table><br><br>"+ "<h2>Balance Chart</h2><img src='picture1.gif'><br><br><br>"+ "<h2>Price Chart</h2><img src='picture2.gif'>"+ "</center>"+ "</body>"+ "</html>"); // close file FileClose(file_handle);
Zaman aşımı sabitinde belirtilen süreden daha uzun olmayan grafik güncellemesinin beklenmesi.
// get current time time_curr=TimeCurrent(); // waiting for chart update while(SeriesInfoInteger(Symbol(),Picture1_period,SERIES_BARS_COUNT)==0 && TimeCurrent()-time_curr<timeout) Sleep(1000);
Grafiğin sabit maksimum ve minimum değerlerinin ayarlanması.
// setting maximal and minimal values for the balance chart (10% indent from upper and lower boundaries) ChartSetDouble(hChart,CHART_FIXED_MAX,max_val+(max_val-min_val)/10); ChartSetDouble(hChart,CHART_FIXED_MIN,min_val-(max_val-min_val)/10);
Bakiye grafiğinin özelliklerinin ayarlanması.
// setting properties of the balance chart ChartSetInteger(hChart,CHART_MODE,CHART_LINE); // chart as line ChartSetInteger(hChart,CHART_FOREGROUND,false); // chart on foreground ChartSetInteger(hChart,CHART_SHOW_BID_LINE,false); // hide BID line ChartSetInteger(hChart,CHART_COLOR_VOLUME,White); // volumes and orders levels are white ChartSetInteger(hChart,CHART_COLOR_STOP_LEVEL,White); // SL and TP levels are white ChartSetInteger(hChart,CHART_SHOW_GRID,true); // show grid ChartSetInteger(hChart,CHART_COLOR_GRID,LightGray); // grid is light-gray ChartSetInteger(hChart,CHART_SHOW_PERIOD_SEP,false); // hide period separators ChartSetInteger(hChart,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE); // hide volumes ChartSetInteger(hChart,CHART_COLOR_CHART_LINE,White); // chart is white ChartSetInteger(hChart,CHART_SCALE,0); // minimal scale ChartSetInteger(hChart,CHART_SCALEFIX,true); // fixed scale on vertical axis ChartSetInteger(hChart,CHART_SHIFT,false); // no chart shift ChartSetInteger(hChart,CHART_AUTOSCROLL,true); // autoscroll enabled ChartSetString(hChart,CHART_COMMENT,"BALANCE"); // comment on chart
Bakiye grafiğinin yeniden çizilmesi.
// redraw the balance chart ChartRedraw(hChart); Sleep(8000);
Grafiğin ekran görüntüsünü alın ("picture1.gif" resmini kaydedin). Grafiğin genişliği rapor döneminin genişliğine göre ayarlanır (ancak tatil günleri nedeniyle genellikle yanlışlıklar olur ve grafik, bakiye değişikliği eğrisinden daha geniş olur), yükseklik genişliğin yarısı olarak hesaplanır.
// screen shooting the balance chart ChartScreenShot(hChart,"picture1.gif",(int)(EndTime-StartTime)/PeriodSeconds(Picture1_period), (int)(EndTime-StartTime)/PeriodSeconds(Picture1_period)/2,ALIGN_RIGHT);
Grafikteki tüm nesneleri silin ve kapatın.
// delete all objects from the balance chart ObjectsDeleteAll(hChart); // close chart ChartClose(hChart);
FTP aracılığıyla dosya gönderimine izin veriliyorsa üç dosya gönderin: "report.html", picture1.gif "and" picture2.gif ".
// if report publication is enabled - send via FTP // HTML-file and two images - price chart and balance chart if(TerminalInfoInteger(TERMINAL_FTP_ENABLED)) { SendFTP("report.html"); SendFTP("picture1.gif"); SendFTP("picture2.gif"); } }
Şimdilik program açıklamasını tamamladık. FTP aracılığıyla dosya göndermek için MetaTrader 5 ayarlarını yapmalısınız - Araçlar menüsüne, ardından Seçenekler'e gidin ve Yayıncı sekmesini açın (Şekil 4).
Şekil 4. FTP aracılığıyla rapor yayınlama seçenekleri.
Seçenekler iletişim kutusunda "Etkinleştir" seçeneğini işaretlemeniz, erişim için hesap numarası, FTP adresi, yol, oturum açma ve parola belirtmeniz gerekir. Yenileme dönemselliği önemli değildir.
Şimdi script dosyasını çalıştırabilirsiniz. Çalıştırdıktan sonra bakiye grafiği ekranda birkaç saniyeliğine belirir ve ardından kaybolur. Günlük'te olası hatayı bulabilir ve dosyaların FTP aracılığıyla gönderilip gönderilmediğini görebilirsiniz. Her şey yolunda giderse, sunucuda belirtilen klasörde üç yeni dosya görünecektir. Oraya ok resimleri içeren iki dosya yerleştirirseniz ve WWW-sunucusu yapılandırılmışsa ve çalışıyorsa web tarayıcısı aracılığıyla bir rapor açabilirsiniz.
2. Cep telefonuna SMS olarak bildirim gönderme
Bilgisayarınızdan ve diğer elektronik cihazlarınızdan uzakta olduğunuz ve elinizin altında yalnızca bir cep telefonunun bulunduğu zamanlar vardır. Ancak, hesabınızdaki alım satımı kontrol etmek veya finansal enstrüman için fiyat tekliflerini izlemek istiyorsunuzdur. Bu durumda, cep telefonuna SMS ile bildirim gönderme seçeneğini ayarlayabilirsiniz. Birçok cep telefonu operatörü (ve üçüncü taraflar), belirli bir e-posta adresine gönderilen mesajları mektup olarak almanıza olanak tanıyan E-POSTA-SMS hizmeti sağlar.
Bunun için bir e-posta kutunuz olmalıdır (özellikle SMTP sunucunuzu bilmelisiniz). MetaTrader 5 ayarlarınızı yapın; Araçlar menüsüne, ardından Seçenekler'e gidin ve E-posta sekmesini açın (Şekil 5).
Şekil 5. E-posta yoluyla bildirim gönderme özelliğini ayarlama
"Etkinleştir" seçeneğini işaretleyin, SMTP sunucu adresini, kullanıcı adını ve parolayı, gönderenin adresini (e-postanız) ve alıcı adresini - SMS olarak mesaj göndermek için kullanılan e-posta adresini belirtin (cep telefonu operatörünüze danışın). Her şey doğruysa, "Test" düğmesine tıkladığınızda bir doğrulama mesajı gönderilecektir (Günlük'teki ek bilgilere bakınız).
Fiyat belirli bir düzeye ulaştığında haberdar olmanın en kolay yolu uyarı oluşturmaktır. Bunu yapmak için uygun "Araç Kutusu" sekmesini açın, sağ tıklayın ve "Oluştur" seçeneğini seçin (Şekil 6).
Şekil 6. Uyarı oluşturma.
Bu pencerede "Etkinleştir" seçeneğini işaretleyin, "E-posta" eylemini seçin, finansal enstrüman, durum seçin, durum için değer girin ve mesaj metnini yazın. Mesajın tekrar tekrar gelmesini istemiyorsanız "Maksimum yineleme" alanına 1 değerini girin. Tüm alanlar doldurulduğunda, Tamam'a tıklayın.
Bir MQL5 programından mesaj gönderirsek daha fazla imkanımız olacaktır. SendMail() işlevini kullanacağız. Bunun iki parametresi vardır. İlki başlık, ikincisi mesajın gövdesidir.
SendMail() işlevini alım satım talebinden sonra (OrderSend() işlevi) veya Alım Satım olay işleyicisinde çağırabilirsiniz. Böylece alım satım etkinlikleriyle ilgili bildirimler alacağız; piyasaya giriş, talimatlar verme, pozisyonları kapatma. Veya SendMail() işlevini OnTimer() işlevinin içine yerleştirebilirsiniz - mevcut fiyat teklifleri hakkında periyodik bildirimler alacağız. Belirli alım satım sinyalleri göründüğünde - gösterge çizgileri kesiştiğinde, fiyat bazı çizgilere ve düzeylere ulaştığında vb. - bildirimlerin gönderilmesini düzenleyebilirsiniz.
Birkaç örneği ele alalım.
Bir Expert Advisor'da veya Script dosyasında
OrderSend(request,result};
şunları değiştirdikten sonra
string msg_subj,msg_text; if(OrderSend(request,result)) { switch(request.action) { case TRADE_ACTION_DEAL: switch(request.type) { case ORDER_TYPE_BUY: StringConcatenate(msg_text,"Buy ",result.volume," ",request.symbol," at price ",result.price,", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_SELL: StringConcatenate(msg_text,"Sell ",result.volume," ",request.symbol," at price ",result.price,", SL=",request.sl,", TP=",request.tp); break; } break; case TRADE_ACTION_PENDING: switch(request.type) { case ORDER_TYPE_BUY_LIMIT: StringConcatenate(msg_text,"Set BuyLimit ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_SELL_LIMIT: StringConcatenate(msg_text,"Set SellLimit ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_BUY_STOP: StringConcatenate(msg_text,"Set BuyStop ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_SELL_STOP: StringConcatenate(msg_text,"Set SellStop ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_BUY_STOP_LIMIT: StringConcatenate(msg_text,"Set BuyStopLimit ",result.volume," ",request.symbol," at price ",request.price,", stoplimit=",request.stoplimit, ", SL=",request.sl,", TP=",request.tp); break; case ORDER_TYPE_SELL_STOP_LIMIT: StringConcatenate(msg_text,"Set SellStop ",result.volume," ",request.symbol," at price ",request.price,", stoplimit=",request.stoplimit, ", SL=",request.sl,", TP=",request.tp); break; } break; case TRADE_ACTION_SLTP: StringConcatenate(msg_text,"Modify SL&TP. SL=",request.sl,", TP=",request.tp); break; case TRADE_ACTION_MODIFY: StringConcatenate(msg_text,"Modify Order",result.price,", SL=",request.sl,", TP=",request.tp); break; case TRADE_ACTION_REMOVE: msg_text="Delete Order"; break; } } else msg_text="Error!"; StringConcatenate(msg_subj,AccountInfoInteger(ACCOUNT_LOGIN),"-",AccountInfoString(ACCOUNT_COMPANY)); SendMail(msg_subj,msg_text);
alım satım talebinden sonra OrderSend() işlevi SendMail() işlevini kullanarak bir mesaj gönderecektir. Bu, alım satım hesap numarası, brokerin adı ve yapılan işlemler (alma, satma, bekleyen talimat verme, talimatı değiştirme veya silme) hakkında aşağıdakiler gibi bilgileri içerecektir:
59181-MetaQuotes Software Corp. Buy 0.1 EURUSD at price 1.23809, SL=1.2345, TP=1.2415
Ve OnInit() gövdesi içindeki herhangi bir Expert Advisor veya Göstergedeyse, zamanlayıcıyı EventSetTimer() işlevini kullanarak başlatacaksınız (bu, yalnızca bir parametre içerir - saniye cinsinden zamanlayıcı dönemi):
void OnInit() { EventSetTimer(3600); }
OnDeinit() içinde, EventKillTimer() kullanarak kapatmayı unutmayın:
void OnDeinit(const int reason) { EventKillTimer(); }
ve SendMail() kullanarak mesajlar göndermek için OnTimer() içinde:
void OnTimer() { SendMail(Symbol(),DoubleToString(SymbolInfoDouble(Symbol(),SYMBOL_BID),_Digits)); }
o zaman mevcut finansal enstrümanın fiyatı ile ilgili belirli dönemlerle ilgili mesajlar alacaksınız.
Sonuç
Bu makalede, resim dosyaları ve bir HTML oluşturmak için MQL5 programının nasıl kullanılacağı ve bunların FTP aracılığıyla WWW-sunucusuna nasıl yükleneceği açıklanmıştır. Ayrıca cep telefonunuza SMS olarak bildirim gönderme özelliğini nasıl yapılandıracağınız da ele alınmıştır.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/61





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz