หน้าแรก การเทรดด้วยระบบ โพสต์

Moving Average EA: เครื่องมือทำเงินใน MetaTrader 5

ไฟล์แนบ
1921.zip (1.81 KB, ดาวน์โหลด 0 ครั้ง)

Moving Average EA เป็นเครื่องมือที่มีอยู่ในแพคเกจมาตรฐานของ MetaTrader 5 และเป็นตัวอย่างของ EA ที่ใช้ในการเทรดโดยอิงจาก Moving Average indicator.

ไฟล์ EA ที่ชื่อ Moving Average.mq5 จะอยู่ในโฟลเดอร์ "terminal_data_folder\MQL5\Experts\Examples\Moving Average" โดย EA นี้เป็นตัวอย่างการใช้ ตัวชี้วัดทางเทคนิค, ฟังก์ชัน ประวัติการซื้อขาย และ คลาสการเทรด ที่มีอยู่ใน Standard Library นอกจากนี้ EA ยังมีระบบการจัดการเงินที่อิงจากผลการเทรดอีกด้วย。

มาดูกันว่าโครงสร้างของ Expert Advisor นี้ทำงานอย่างไรบ้าง

1. คุณสมบัติของ EA

//+------------------------------------------------------------------+ //|                                              Moving Averages.mq5 | //|                   Copyright 2009-2013, MetaQuotes Software Corp. | //|                                              https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2009-2013, MetaQuotes Software Corp." #property link      "https://www.mql5.com" #property version   "1.00"

ใน 5 บรรทัดแรกจะประกอบไปด้วยความคิดเห็น ส่วน 3 บรรทัดถัดไปจะตั้งค่าคุณสมบัติของโปรแกรม MQL5 (ลิขสิทธิ์, ลิงก์, เวอร์ชัน) โดยใช้ #property directives

เมื่อคุณรัน Expert Advisor เหล่านี้จะถูกแสดงในแท็บ "Common"


รูปที่ 1. พารามิเตอร์ทั่วไปของ Moving Average EA


1.2. ไฟล์ที่รวมเข้า

ต่อไปนี้ #include directive จะบอกให้คอมไพเลอร์รวมไฟล์ "Trade.mqh"

ไฟล์นี้เป็นส่วนหนึ่งของ Standard Library ซึ่งมี CTrade class สำหรับเข้าถึงฟังก์ชันการเทรดได้ง่าย

#include <Trade\Trade.mqh>

ชื่อไฟล์ที่รวมเข้าแสดงในวงเล็บ "<>;" ดังนั้นเส้นทางจึงถูกตั้งค่าให้สัมพันธ์กับไดเรกทอรี: "terminal_data_folder\Include"

1.3 พารามิเตอร์นำเข้า

ถัดไปคือประเภท, ชื่อ, ค่าปริยายและความคิดเห็น บทบาทของพวกเขาจะเห็นในรูปที่ 2

input double MaximumRisk        = 0.02;    // ความเสี่ยงสูงสุดเป็นเปอร์เซ็นต์ input double DecreaseFactor     = 3;       // ปัจจัยการลดลง input int    MovingPeriod       = 12;      // ระยะเวลาของ Moving Average input int    MovingShift        = 6;       // การเลื่อนของ Moving Average

พารามิเตอร์ MaximumRisk และ DecreaseFactor จะถูกใช้สำหรับการจัดการเงิน, MovingPeriod และ MovingShift จะตั้งค่าช่วงและการเลื่อนของ Moving Average ตัวชี้วัดทางเทคนิคที่จะใช้ในการตรวจสอบเงื่อนไขการเทรด

ข้อความในความคิดเห็นในบรรทัดพารามิเตอร์นำเข้า พร้อมค่าปริยายจะแสดงในแท็บ "Options" แทนชื่อของพารามิเตอร์นำเข้า:


รูปที่ 2. พารามิเตอร์นำเข้าสำหรับ Moving Average EA

1.4. ตัวแปรทั่วโลก

จากนั้นประกาศตัวแปรทั่วโลก ExtHandle เพื่อใช้เก็บข้อมูลของ Moving Average indicator

//--- int   ExtHandle=0;

ในส่วนนี้จะมีฟังก์ชัน 6 ตัว โดยแต่ละตัวจะมีวัตถุประสงค์ที่อธิบายไว้ในความคิดเห็นก่อนร่างฟังก์ชัน:

  1. TradeSizeOptimized() - คำนวณขนาดล็อตที่เหมาะสม;
  2. CheckForOpen() - ตรวจสอบเงื่อนไขเปิดตำแหน่ง;
  3. CheckForClose() - ตรวจสอบเงื่อนไขปิดตำแหน่ง;
  4. OnInit() - ฟังก์ชันเริ่มต้น Expert;
  5. OnTick() - ฟังก์ชันการประมวลผลแต่ละเทียน;
  6. OnDeinit() - ฟังก์ชันการยกเลิกการใช้งาน Expert;

ฟังก์ชันสุดท้ายทั้งสามเป็น ฟังก์ชันจัดการเหตุการณ์; ฟังก์ชันบริการทั้งสามจะถูกเรียกในโค้ดของพวกมัน


2. ฟังก์ชันจัดการเหตุการณ์

2.1. ฟังก์ชันเริ่มต้น OnInit()

ฟังก์ชัน OnInit() จะถูกเรียกเพียงครั้งเดียวเมื่อเริ่ม Expert Advisor เป็นครั้งแรก โดยทั่วไปใน OnInit() จะเตรียม EA ให้พร้อมทำงาน: ตรวจสอบพารามิเตอร์นำเข้า, ตั้งค่าตัวชี้วัดและพารามิเตอร์, ฯลฯ ในกรณีที่เกิดข้อผิดพลาดร้ายแรงเมื่อการทำงานต่อไปไม่มีความหมาย ฟังก์ชันจะออกด้วยรหัสคืนค่า INIT_FAILED

//+------------------------------------------------------------------+ //| ฟังก์ชันเริ่มต้น Expert                                   | //+------------------------------------------------------------------+ int OnInit(void)   { //---    ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);    if(ExtHandle==INVALID_HANDLE)      {       printf("เกิดข้อผิดพลาดในการสร้าง MA indicator");       return(INIT_FAILED);      } //---    return(INIT_SUCCEEDED);   } 

เนื่องจากการเทรด EA อิงจากตัวชี้วัด Moving Average โดยการเรียก iMA() ตัวชี้วัด Moving Average จะถูกสร้างและจับมือได้ในตัวแปรทั่วโลก ExtHandle

ในกรณีที่เกิดข้อผิดพลาด, OnInit() จะถูกออกด้วยรหัสคืนค่า INIT_FAILED - เป็นวิธีที่ถูกต้องในการสิ้นสุดการทำงานของ EA/indicator ในกรณีที่การเริ่มต้นไม่สำเร็จ


2.2. ฟังก์ชัน OnTick()

ฟังก์ชัน OnTick() จะถูกเรียกทุกครั้งที่ได้รับราคาข้อเสนอใหม่สำหรับสัญลักษณ์ของกราฟที่ EA ทำงานอยู่

//+------------------------------------------------------------------+ //| ฟังก์ชันการประมวลผลแต่ละเทียน                                             | //+------------------------------------------------------------------+ void OnTick(void)   { //---    if(PositionSelect(_Symbol))       CheckForClose();    else       CheckForOpen(); //---   }

ฟังก์ชัน PositionSelect() ใช้สำหรับกำหนดว่ามีตำแหน่งเปิดอยู่สำหรับสัญลักษณ์ปัจจุบันหรือไม่

หากมีตำแหน่งเปิดอยู่ ฟังก์ชัน CheckForClose() จะถูกเรียกซึ่งวิเคราะห์สถานะปัจจุบันของตลาดและปิดตำแหน่งที่เปิดอยู่ มิฉะนั้นจะเรียก CheckForOpen() ซึ่งจะตรวจสอบเงื่อนไขการเข้าตลาดและเปิดตำแหน่งใหม่หากมีเงื่อนไขเกิดขึ้น


2.3. ฟังก์ชัน OnDeInit()

ฟังก์ชัน OnDeInit() จะถูกเรียกเมื่อ EA ถูกลบออกจากกราฟ หากโปรแกรมวางวัตถุกราฟิกระหว่างการทำงาน สามารถลบได้จากกราฟ

//+------------------------------------------------------------------+ //| ฟังก์ชันยกเลิกการใช้งาน Expert                                 | //+------------------------------------------------------------------+ void OnDeinit(const int reason)   {   } //+------------------------------------------------------------------+

ในกรณีนี้ไม่มีการดำเนินการใด ๆ ในระหว่างการยกเลิกการใช้งาน Expert Advisor


3. ฟังก์ชันบริการ

3.1. ฟังก์ชัน TradeSizeOptimized()

ฟังก์ชันนี้คำนวณและคืนค่าขนาดล็อตที่เหมาะสมสำหรับการเปิดตำแหน่งด้วยระดับความเสี่ยงที่กำหนดและผลการซื้อขาย

//+------------------------------------------------------------------+ //| คำนวณขนาดล็อตที่เหมาะสม                                     | //+------------------------------------------------------------------+ double TradeSizeOptimized(void)   {    double price=0.0;    double margin=0.0; //--- คำนวณขนาดล็อต    if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))       return(0.0);    if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))       return(0.0);    if(margin<=0.0)       return(0.0);    double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2); //--- คำนวณความยาวของชุดการซื้อขายที่ขาดทุนติดต่อกัน    if(DecreaseFactor>0)      {       //--- ขอประวัติการเทรดทั้งหมด       HistorySelect(0,TimeCurrent());       //--       int    orders=HistoryDealsTotal();  // จำนวนดีลทั้งหมด       int    losses=0                    // จำนวนดีลที่ขาดทุนในชุด            for(int i=orders-1;i>=0;i--)       {         ulong ticket=HistoryDealGetTicket(i);          if(ticket==0)            {             Print("HistoryDealGetTicket ล้มเหลว ไม่มีประวัติการเทรด");             break;            }          //--- ตรวจสอบสัญลักษณ์ของดีล          if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)             continue;          //--- ตรวจสอบกำไร          double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);          if(profit>0.0)             break;          if(profit<0.0)             losses++;         }       //---       if(losses>1)          lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);      } //--- ปรับขนาดล็อตให้ถูกต้องและตรวจสอบค่าที่อนุญาตของปริมาณการซื้อขาย    double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);    lot=stepvol*NormalizeDouble(lot/stepvol,0);    double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);    if(lot<minvol)       lot=minvol;    double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);    if(lot>maxvol)       lot=maxvol; //--- คืนค่าขนาดปริมาณการซื้อขาย    return(lot);   }

ฟังก์ชัน SymbolInfoDouble() ใช้สำหรับตรวจสอบความพร้อมของราคาสำหรับสัญลักษณ์ปัจจุบัน ถัดไปฟังก์ชัน OrderCalcMargin() จะใช้สำหรับการขอจำนวนมาร์จินที่ต้องการในการวางคำสั่ง (ในกรณีนี้คำสั่งซื้อ) ขนาดล็อตเริ่มต้นจะถูกกำหนดจากมูลค่าของมาร์จินที่ต้องการสำหรับการวางคำสั่ง, มาร์จินฟรีของบัญชี (AccountInfoDouble(ACCOUNT_FREEMARGIN)) และค่าความเสี่ยงสูงสุดที่อนุญาตซึ่งระบุในพารามิเตอร์นำเข้า MaximumRisk

หากค่าของพารามิเตอร์นำเข้า DecreaseFactor เป็นบวก จะมีการวิเคราะห์ดีลในประวัติศาสตร์และขนาดล็อตจะถูกปรับตามข้อมูลเกี่ยวกับชุดการซื้อขายที่ขาดทุนสูงสุด: ขนาดล็อตเริ่มต้นจะถูกคูณด้วยขนาด (1-losses/DecreaseFactor)

จากนั้นปริมาณการซื้อขายจะ "ปัด" ไปยังค่าที่เป็นไปตามจำนวนขั้นต่ำที่อนุญาต (stepvol) สำหรับสัญลักษณ์ปัจจุบัน นอกจากนี้ยังมีการขอค่าต่ำสุด (minvol) และค่ามากที่สุด (maxvol) ของปริมาณการซื้อขาย และหากค่าล็อตออกนอกขอบเขตที่อนุญาต จะต้องปรับให้เหมาะสม โดยผลสุดท้ายจะคืนค่าขนาดปริมาณการซื้อขายที่คำนวณ


3.2. ฟังก์ชัน CheckForOpen()

CheckForOpen() ใช้ในการตรวจสอบเงื่อนไขการเปิดตำแหน่งและเปิดมันเมื่อมีเงื่อนไขการเทรดเกิดขึ้น (ในกรณีนี้เมื่อราคาข้าม Moving Average)

//+------------------------------------------------------------------+ //| ตรวจสอบเงื่อนไขเปิดตำแหน่ง                               | //+------------------------------------------------------------------+ void CheckForOpen(void)   {    MqlRates rt[2]; //--- คัดลอกค่าราคา    if(CopyRates(_Symbol,_Period,0,2,rt)!=2)      {       Print("CopyRates ของ ",_Symbol," ล้มเหลว ไม่มีประวัติ");       return;      } //--- เทรดเฉพาะในแท็บแรกของแท่งใหม่    if(rt[1].tick_volume>1)       return; //--- รับค่าปัจจุบันของ Moving Average indicator     double   ma[1];    if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)      {       Print("CopyBuffer จาก iMA ล้มเหลว ไม่มีข้อมูล");       return;      } //--- ตรวจสอบสัญญาณ    ENUM_ORDER_TYPE signal=WRONG_VALUE;       if(rt[0].open>ma[0] && rt[0].close<ma[0])       signal=ORDER_TYPE_SELL    // เงื่อนไขขาย    else        {          if(rt[0].open<ma[0] && rt[0].close>ma[0])          signal=ORDER_TYPE_BUY  // เงื่อนไขซื้อ      } //--- ตรวจสอบเพิ่มเติม       if(signal!=WRONG_VALUE)          if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))          if(Bars(_Symbol,_Period)>100)            {             CTrade trade;             trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),                                SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),                                0,0);            } //---   }

เมื่อทำการเทรดโดยใช้ Moving Average จะต้องตรวจสอบว่าราคาได้ข้าม Moving Average หรือไม่ โดยใช้ฟังก์ชัน CopyRates() จะคัดลอกค่าราคาสองค่าลงในอาร์เรย์ของโครงสร้าง rt[], rt[1] จะสอดคล้องกับแท่งปัจจุบัน, rt[0] - แท่งที่เสร็จสมบูรณ์

การเริ่มต้นแท่งใหม่จะตรวจสอบจากปริมาณการติ๊กของแท่งปัจจุบันว่าเท่ากับ 1 หรือไม่ ถ้าเท่ากับ 1 ก็แสดงว่าแท่งใหม่ได้เริ่มต้นขึ้น ควรทราบว่าวิธีการนี้อาจล้มเหลวในบางกรณี (เมื่อราคามาเป็นกลุ่ม) ดังนั้นการเริ่มต้นการสร้างแท่งใหม่จะต้องบันทึกและเปรียบเทียบเวลาของราคาปัจจุบัน (ดู IsNewBar)

ค่าปัจจุบันของ Moving Average indicator จะถูกเรียกโดยใช้ฟังก์ชัน CopyBuffer() และบันทึกในอาร์เรย์ ma[] ที่มีค่าเพียงค่าเดียว จากนั้นโปรแกรมจะตรวจสอบว่าราคาได้ข้าม Moving Average หรือไม่และทำการตรวจสอบเพิ่มเติม (หากการเทรดโดยใช้ EA เป็นไปได้และมีแท่งในประวัติ) หากสำเร็จจะเปิดตำแหน่งที่เหมาะสมสำหรับสัญลักษณ์โดยการเรียก PositionOpen() วิธีการของวัตถุการค้า (อินสแตนซ์ของ CTrade)

ราคาการเปิดตำแหน่งจะถูกตั้งค่าด้วยฟังก์ชัน SymbolInfoDouble() ซึ่งคืนค่าราคาประมูลหรือราคาเสนอขึ้นอยู่กับค่าของตัวแปร signal ขนาดของตำแหน่งจะถูกกำหนดโดยเรียก TradeSizeOptimized() ที่ได้กล่าวถึงข้างต้น


3.3. ฟังก์ชัน CheckForClose()

CheckForClose() ตรวจสอบเงื่อนไขสำหรับการปิดตำแหน่งและปิดมันหากมีเงื่อนไขในการปิดเกิดขึ้น

//+------------------------------------------------------------------+ //| ตรวจสอบเงื่อนไขปิดตำแหน่ง                              | //+------------------------------------------------------------------+ void CheckForClose(void)   {    MqlRates rt[2]; //--- คัดลอกค่าราคา    if(CopyRates(_Symbol,_Period,0,2,rt)!=2)      {       Print("CopyRates ของ ",_Symbol," ล้มเหลว ไม่มีประวัติ");       return;      } //--- เทรดเฉพาะในแท็บแรกของแท่งใหม่    if(rt[1].tick_volume>1)       return; //--- รับค่าปัจจุบันของ Moving Average indicator    double   ma[1];    if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)      {       Print("CopyBuffer จาก iMA ล้มเหลว ไม่มีข้อมูล");       return;      } //--- รับประเภทของตำแหน่งที่เลือกก่อนหน้านี้โดยใช้ PositionSelect()    bool signal=false;    long type=PositionGetInteger(POSITION_TYPE);       if(type==(long)POSITION_TYPE_BUY   && rt[0].open>ma[0] && rt[0].close<ma[0])       signal=true;    if(type==(long)POSITION_TYPE_SELL  && rt[0].open<ma[0] && rt[0].close>ma[0true; //--- ตรวจสอบเพิ่มเติม       if(signal)       if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))          if(Bars(_Symbol,_Period)>100)            {             CTrade trade;             trade.PositionClose(_Symbol,3);            } //---   }

อัลกอริธึมของฟังก์ชัน CheckForClose() จะคล้ายคลึงกับอัลกอริธึมของ CheckForOpen() ขึ้นอยู่กับทิศทางของตำแหน่งที่เปิดอยู่ จะมีการตรวจสอบเงื่อนไขในการปิด (ราคาข้าม MA ลงไปสำหรับการซื้อ หรือ ขึ้นไปสำหรับการขาย) ตำแหน่งที่เปิดอยู่จะถูกปิดโดยการเรียก PositionClose() วิธีการของวัตถุการค้า (อินสแตนซ์ของ CTrade)


4. การทดสอบย้อนหลัง

ค่าที่ดีที่สุดของพารามิเตอร์สามารถค้นหาได้โดยใช้ Strategy Tester ของ MetaTrader 5 terminal

ตัวอย่างเช่น เมื่อทำการปรับแต่งพารามิเตอร์ MovingPeriod ในช่วงวันที่ 2012.01.01-2013.08.01 ผลลัพธ์ที่ดีที่สุดจะได้แก่ MovingPeriod=45:

ผลการทดสอบย้อนหลังของ Moving Average Expert Advisor

ผลการทดสอบย้อนหลังของ Moving Average Expert Advisor

บทสรุป:

Moving Average Expert Advisor ที่รวมอยู่ในแพคเกจมาตรฐานของ MetaTrader 5 เป็นตัวอย่างของการใช้ ตัวชี้วัดทางเทคนิค, ฟังก์ชัน ประวัติการเทรด และ คลาสการเทรด ของ Standard Library นอกจากนี้ EA ยังมีระบบการจัดการเงินที่อิงจากผลการเทรดอีกด้วย


โพสต์ที่เกี่ยวข้อง

ความคิดเห็น (0)