Saat ini, saya sedang mengembangkan sebuah Expert Advisor untuk minyak mentah dan Brent. Saya ingin mengambil tanggal dan waktu pasti dari laporan 'Inventaris Minyak Mentah' dari ForexFactory.com. Laporan ini biasanya dirilis pada hari Rabu pukul 10:30 pagi waktu Timur, namun jika ada hari libur, tanggal rilisnya bisa berubah. Karena ini adalah laporan penting bagi EA saya, satu-satunya cara adalah memeriksa layanan online untuk memvalidasi tanggal rilisnya.
Langkah pertama adalah menambahkan di tab OPTIONS | EXPERT ADVISOR situs web yang akan digunakan untuk melakukan WebRequest, yaitu ForexFactory (lihat gambar 1).

Selanjutnya, kita perlu mendefinisikan struktur dalam kode kita untuk menyimpan event. Ini diletakkan di bagian atas kode yang akan mendeklarasikan DailyEvents sebagai variabel global dengan jumlah maksimum event yang disimpan didefinisikan oleh variabel MaxDailyEvents.
// Definisikan struktur event struct EVENTS { string time; string title; string currency; bool displayed; }; #define MaxDailyEvents 20 // Jika Anda berpikir akan ada lebih dari 20 event berdampak tinggi, tingkatkan angka ini. EVENTS DailyEvents[MaxDailyEvents];
Selanjutnya, kita perlu mengambil kode HTML dari ForexFactory.com dan mem-parsenya. Jika Anda tidak mengerti kode HTML, jangan khawatir, saya akan membimbing Anda :)
Kita perlu membangun URL untuk WebRequest. Karena saya hanya ingin kalender mereka untuk hari ini dan bukan default (seminggu), kita dapat melakukannya dengan mengatur parameter day dari permintaan ke tanggal hari ini dan mengirim permintaan.
string url="http://www.forexfactory.com/calendar.php?day="; url += MthName(Month()) + DoubleToStr(Day(), 0) + "." + DoubleToStr(Year(), 0);
Kemudian kita mengirim permintaan, memeriksa kode error (jika ada) dan mengonversi array karakter yang dikembalikan menjadi string. Ini memudahkan kita untuk mem-parsing kode HTML.
// Kirim permintaan web ResetLastError(); res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers); // Periksa error if(res == -1) { Print("Error in WebRequest. Kode error = ", GetLastError()); MessageBox("Tambahkan alamat 'http://forexfactory.com/' pada list URL yang diizinkan di" + " tab 'Expert Advisors'", "Error", MB_ICONINFORMATION); return(false); }
Jika tidak ada error, kita kemudian mengonversi array karakter result menjadi string untuk parsing yang lebih baik.
// Konversi array karakter menjadi string HTML = CharArrayToString(result);
Sekarang kita memiliki string, kita bisa menggunakan fungsi StringFind untuk menemukan elemen HTML. Hal pertama yang harus dilakukan adalah memastikan HTML yang dikembalikan adalah untuk tanggal hari ini dan memotong apapun sebelum tag HTML ini. Fungsi GetHTMLElement digunakan untuk mem-parsing kode HTML dan mengembalikan nilai antara tag HTML yang ditentukan. Lihat di bawah untuk definisinya.
// Kalender dimuat, pastikan itu untuk tanggal hari ini int i = StringFind(HTML, "<span class=\"date\">"); if(i == -1) return(false); HTML = StringSubstr(HTML, i); string date = GetHTMLElement(HTML, "<span>", "</span>"); if(date != MthName(Month()) + " " + DoubleToStr(Day(), 0)) return(false);
Definisi dari fungsi GetHTMLElement.
//+------------------------------------------------------------------+ //| Ekstrak elemen HTML //+------------------------------------------------------------------+ string GetHTMLElement(string HTML, string ElementStart, string ElementEnd) { string data = NULL; // Temukan posisi awal dan akhir untuk elemen int s = StringFind(HTML, ElementStart) + StringLen(ElementStart); int e = StringFind(StringSubstr(HTML, s), ElementEnd); // Kembalikan konten elemen if(e != 0) data = StringSubstr(HTML, s, e); return(data); }
Ok, sekarang kita sudah memastikan kalender yang dikembalikan adalah untuk tanggal hari ini, mari kita mulai mem-parsing setiap baris tabel dan mengekstrak elemen yang kita butuhkan. Yaitu waktu event, mata uang event, dampak event, dan judul event. Kita perlu melakukan ini untuk setiap baris tabel yang ada dalam kode HTML sampai akhir kalender atau hingga MaxDailyEvents tercapai.
Setelah data untuk setiap baris diekstrak, kita tambahkan ke struktur DailyEvents.
// Sekarang dapatkan baris tabel untuk setiap event lasttime = NULL; cnrt = 0; date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " "; do { // Dapatkan informasi event time = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__time time\">", "</td>"); if(StringFind(time, "<a name=\"upnext\"") == 0) time = GetHTMLElement(time, "class=\"upnext\">", "</span>"); if(StringLen(time) != 0) lasttime = time; if(StringLen(time) == 0) time = lasttime; time = date + time; currency = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__currency currency\">", "</td>"); impact = GetHTMLElement(HTML, "<span title=\"", "\" class=\""); i = StringFind(impact, " Impact"); if(i != -1) impact = StringSubstr(impact, 0, i); title = GetHTMLElement(HTML, "\"calendar__event-title\">", "</span>"); // Apakah ini merupakan event berdampak tinggi? if(StringFind(Symbol(), currency) != -1 && impact == "High") { // Tambahkan ke struktur event harian DailyEvents[cntr].displayed = false; DailyEvents[cntr].time = time; DailyEvents[cntr].title = title; DailyEvents[cntr++].currency = currency; } // Potong string HTML ke baris tabel berikutnya i = StringFind(HTML, "</tbody> </table> </td> </tr> "); if(i != -1) HTML = StringSubstr(HTML, i+30); if(StringFind(HTML, "</table> <div class=\"foot\">") == 0) i = -1; } while(i != -1 || cntr == MaxDailyEvents);
Setelah kita mem-parsing semua baris tabel dan mencapai akhir kalender, kita perlu menampilkan event pada chart. Jika event tersebut di masa depan, saya ingin menampilkan garis vertikal dan jika di masa lalu, tidak ada garis.
// Tampilkan event berdampak tinggi, jika ada lasttime = NULL; for(cntr = 0; cntr < MaxDailyEvents; cntr++) { if(StringLen(DailyEvents[cntr].time) == 0) break; // Buat penanda event di chart jika pasar terakhir bukan waktu yang sama if(lasttime != DailyEvents[cntr].time) { res = cntr; // Jika kita memiliki 'pm' dalam string, tambahkan 12 jam ke waktu if(StringFind(DailyEvents[cntr].time, "pm") != -1) DailyEvents[cntr].time = TimeToStr(StrToTime(DailyEvents[cntr].time) + 43200); if(ObjectCreate(0, Event + cntr, OBJ_EVENT, 0, StrToTime(DailyEvents[cntr].time), 0)) { ObjectSetString(0, Event + cntr, OBJPROP_TEXT, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); ObjectSetInteger(0, Event + cntr, OBJPROP_COLOR, Red); ObjectSetInteger(0, Event + cntr, OBJPROP_WIDTH, 2); ObjectSetInteger(0, Event + cntr, OBJPROP_BACK, true); ObjectSetInteger(0, Event + cntr, OBJPROP_SELECTABLE,false); ObjectSetInteger(0, Event + cntr, OBJPROP_SELECTED, false); ObjectSetInteger(0, Event + cntr, OBJPROP_HIDDEN, true); ObjectSetString( 0, Event + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); } // Buat garis vertikal jika event di masa depan if(TimeCurrent() < TimeOffset(DailyEvents[cntr].time, 0)) { if(ObjectCreate(0, VLine + cntr, OBJ_VLINE, 0, TimeOffset(DailyEvents[cntr].time, 0), 0)) { ObjectSetInteger( 0, VLine + cntr, OBJPROP_COLOR, Red); ObjectSetInteger( 0, VLine + cntr, OBJPROP_WIDTH, 1); ObjectSetInteger( 0, VLine + cntr, OBJPROP_BACK, true); ObjectSetInteger( 0, VLine + cntr, OBJPROP_SELECTABLE, false); ObjectSetInteger( 0, VLine + cntr, OBJPROP_SELECTED, false); ObjectSetInteger( 0, VLine + cntr, OBJPROP_HIDDEN, true); ObjectSetString( 0, VLine + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); } } else DailyEvents[cntr].displayed = true; } else { title = ObjectGetString( 0, Event + res, OBJPROP_TOOLTIP); title += "\n" + DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"; ObjectSetString( 0, Event + res, OBJPROP_TOOLTIP, title); if( TimeCurrent() < TimeOffset(DailyEvents[cntr].time, 0)) ObjectSetString( 0, VLine + res, OBJPROP_TOOLTIP, title); } lasttime = DailyEvents[cntr].time; }
Jika event yang ada di masa depan, saya ingin memberi tahu pengguna tentang event yang akan datang jika dalam waktu 5 menit dari waktu saat ini dan menghapus garis vertikal tersebut. Hal ini dilakukan dengan menambahkan beberapa kode di fungsi start() dari EA atau indikator Anda.
//+------------------------------------------------------------------+ //| Fungsi start Expert | //+------------------------------------------------------------------+ void start() { string event = NULL; // Apakah ada event berdampak tinggi dalam 5 menit ke depan? for(int i = 0; i < MaxDailyEvents; i++) { if(StringLen(DailyEvents[i].time) ==0) break; if( TimeCurrent() >= StrToTime(DailyEvents[i].time) - 300 && TimeCurrent() < StrToTime(DailyEvents[i].time) && !DailyEvents[i].displayed) { // Event dalam 5 menit... event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), "; DailyEvents[i].displayed = true; // Hapus garis vertikal yang terkait dengan event if(ObjectFind( "VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete( "VLine" + DoubleToStr(i, 0)); } } // Apakah ada yang perlu ditampilkan? if(StringLen(event) != 0) { event += "dalam 5 menit."; Alert(event); } }
Dan akhirnya, kita perlu mendapatkan event harian. Hal ini dilakukan dengan menambahkan satu baris di fungsi OnInit() Anda.
//+------------------------------------------------------------------+ //| Fungsi inisialisasi Expert | //+------------------------------------------------------------------+ int OnInit() { // Dapatkan event hari ini GetHighImpactEvents(); return(INIT_SUCCEEDED); }
Bagus dan sederhana. Anda tentu saja dapat memodifikasi kode untuk menampilkan semua event untuk pasangan mata uang atau menambahkan parameter input ke indikator atau EA Anda untuk menentukan dampak mana yang akan ditampilkan (tinggi, sedang, atau rendah) dan tentu saja menambahkan pemeriksaan untuk pergantian tengah malam untuk mendapatkan daftar event harian yang baru, tapi saya akan biarkan Anda bermain dengan itu :)
Salam!
-Claude.
Komentar 0