안녕하세요, 트레이더 여러분! 오늘은 MetaTrader 5에서 사용할 수 있는 강력한 스캘퍼 EA, "AK-47 EA"에 대해 이야기해보려고 합니다. 이 EA는 스캘핑 전략을 통해 단기 거래에서 수익을 극대화하도록 설계되었습니다.
1. 입력 파라미터
#define ExtBotName "AK-47 EA" // 봇 이름 #define Version "1.00" // 입력 클래스 가져오기 #include <Trade\PositionInfo.mqh> #include <Trade\Trade.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\AccountInfo.mqh> #include <Trade\OrderInfo.mqh> //--- 코드 가독성을 위한 미리 정의된 변수 소개 #define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK) #define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID) //--- 입력 파라미터 input string EASettings = "---------------------------------------------"; //-------- <EA 설정> -------- input int InpMagicNumber = 124656; // 매직 넘버 input string MoneySettings = "---------------------------------------------"; //-------- <자금 설정> -------- input bool isVolume_Percent = true; // 볼륨 퍼센트 허용 input double InpRisk = 3; // 잔고의 리스크 비율 (%) input string TradingSettings = "---------------------------------------------"; //-------- <거래 설정> -------- input double Inpuser_lot = 0.01; // 로트 input double InpSL_Pips = 3.5; // 손절(핍 단위) input double InpTP_Pips = 7; // 목표 수익(핍 단위) (0 = 목표 수익 없음) input int InpMax_slippage = 3; // 허용 최대 슬리피지(핍 단위) input double InpMax_spread = 5; // 허용 최대 스프레드(포인트 단위) (0 = 변동형) input string TimeSettings = "---------------------------------------------"; //-------- <거래 시간 설정> -------- input bool InpTimeFilter = true; // 거래 시간 필터 input int InpStartHour = 2; // 시작 시간 input int InpStartMinute = 30; // 시작 분 input int InpEndHour = 21 // 종료 시간 input int InpEndMinute = 0 // 종료 분
2. 로컬 변수 초기화
//--- 변수들 int Pips2Points; // 슬리피지 3핍 3=포인트 30=포인트 double Pips2Double; // 손절 15핍 0.015 0.0150 bool isOrder = false; int slippage; long acSpread; string strComment = ""; CPositionInfo m_position; // 거래 포지션 객체 CTrade m_trade; // 거래 객체 CSymbolInfo m_symbol; // 심볼 정보 객체 CAccountInfo m_account; // 계좌 정보 래퍼 COrderInfo m_order; // 미체결 주문 객체
3. 메인 코드
a/ 전문가 초기화 함수
//+------------------------------------------------------------------+ //| 전문가 초기화 함수 | //+------------------------------------------------------------------+ int OnInit() { //3 또는 5자리 감지 // 핍과 포인트 if(_Digits % 2 == 1) { Pips2Double = _Point*10; Pips2Points = 10; slippage = 10* InpMax_slippage; } else { Pips2Double = _Point; Pips2Points = 1; slippage = InpMax_slippage; } if(!m_symbol.Name(Symbol())) // 심볼 이름 설정 return(INIT_FAILED); RefreshRates(); //--- m_trade.SetExpertMagicNumber(InpMagicNumber); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(m_symbol.Name()); m_trade.SetDeviationInPoints(slippage); //--- return(INIT_SUCCEEDED); }
b/ 전문가 틱 함수
//+------------------------------------------------------------------+ //| 전문가 틱 함수 | //+------------------------------------------------------------------+ void OnTick() { if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) { Comment("LazyBot\n거래가 허용되지 않습니다."); return; } MqlDateTime structTime; TimeCurrent(structTime); structTime.sec = 0; // 시작 시간 설정 structTime.hour = InpStartHour; structTime.min = InpStartMinute; datetime timeStart = StructToTime(structTime); // 종료 시간 설정 structTime.hour = InpEndHour; structTime.min = InpEndMinute; datetime timeEnd = StructToTime(structTime); acSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); strComment = "\n" + ExtBotName + " - v." + (string)Version; strComment += "\n서버 시간 = " + TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS) + " - " + DayOfWeekDescription(structTime.day_of_week); strComment += "\n거래 시간 = [" + (string)InpStartHour + "h" + (string)InpStartMinute + " --> " + (string)InpEndHour + "h" + (string)InpEndMinute + "]"; strComment += "\n현재 스프레드 = " + (string)acSpread + " 포인트"; Comment(strComment); // 값 업데이트 UpdateOrders(); TrailingStop(); // 거래 조건 if(InpTimeFilter) { if(TimeCurrent() >= timeStart && TimeCurrent() < timeEnd) { if(!isOrder) OpenOrder(); } } else { if(!isOrder) OpenOrder(); } } //--- 함수 종료
3.1 주문 전송을 위한 신호 계산
//+------------------------------------------------------------------+ //| 신호 계산 및 주문 전송 | //+------------------------------------------------------------------+ void OpenOrder(){ ENUM_ORDER_TYPE OrdType = ORDER_TYPE_SELL;//-1; double TP = 0; double SL = 0; string comment = ExtBotName; // 로트 계산 double lot1 = CalculateVolume(); if(OrdType == ORDER_TYPE_SELL) { double OpenPrice = Bid - NormalizeDouble(InpSL_Pips/2 * Pips2Double, _Digits); TP = OpenPrice - NormalizeDouble(InpTP_Pips * Pips2Double, _Digits); SL = Ask + NormalizeDouble(InpSL_Pips/2 * Pips2Double, _Digits); if(CheckSpreadAllow() // 스프레드 확인 && CheckVolumeValue(lot1) // 볼륨 확인 && CheckOrderForFREEZE_LEVEL(ORDER_TYPE_SELL_STOP, OpenPrice) // OpenPrice에서 Bid까지의 거리 확인 && CheckStopLoss(OpenPrice, SL, TP) // SL, TP와 OpenPrice 간의 거리 확인 && CheckMoneyForTrade(m_symbol.Name(), lot1, ORDER_TYPE_SELL)) // 명령이 실행 가능한지 확인 { if(!m_trade.SellStop(lot1, OpenPrice, m_symbol.Name(), SL, TP, ORDER_TIME_GTC, 0, comment)) Print(__FUNCTION__,"--> 주문 전송 오류 ", m_trade.ResultComment()); } } else if(OrdType == ORDER_TYPE_BUY) { double OpenPrice = Ask + NormalizeDouble(InpSL_Pips/2 * Pips2Double, _Digits); SL = Bid - NormalizeDouble(InpSL_Pips/2 * Pips2Double, _Digits); if(CheckSpreadAllow() // 스프레드 확인 && CheckVolumeValue(lot1) // 볼륨 확인 && CheckOrderForFREEZE_LEVEL(ORDER_TYPE_BUY_STOP, OpenPrice) // OpenPrice에서 Bid까지의 거리 확인 && CheckStopLoss(OpenPrice, SL, TP) // SL, TP와 OpenPrice 간의 거리 확인 && CheckMoneyForTrade(m_symbol.Name(), lot1, ORDER_TYPE_BUY)) // 명령이 실행 가능한지 확인 { if(!m_trade.BuyStop(lot1, OpenPrice, m_symbol.Name(), SL, TP, ORDER_TIME_GTC, 0, comment))// 만료일이 0일 때는 "ORDER_TIME_GTC" 사용 Print(__FUNCTION__,"--> 주문 전송 오류 ", m_trade.ResultComment()); } } }
3.2 볼륨 계산
//+------------------------------------------------------------------+ //| 볼륨 계산 | //+------------------------------------------------------------------+ // 포지션 크기를 계산하고 주문할 로트를 반환하는 함수입니다. double CalculateVolume() { double LotSize = 0; if(isVolume_Percent == false) { LotSize = Inpuser_lot; } else { LotSize = (InpRisk) * m_account.FreeMargin(); LotSize = LotSize /100000; double n = MathFloor(LotSize/Inpuser_lot); //Comment((string)n); LotSize = n * Inpuser_lot; if(LotSize < Inpuser_lot) LotSize = Inpuser_lot; if(LotSize > m_symbol.LotsMax()) LotSize = m_symbol.LotsMax(); if(LotSize < m_symbol.LotsMin()) LotSize = m_symbol.LotsMin(); } //--- return(LotSize); }3.3 EA의