Created
September 7, 2023 08:53
-
-
Save tonkla/f9c281b7d132eaf94386d07a73b0e935 to your computer and use it in GitHub Desktop.
A Moving Average (MA) -based Expert Advisors (EA) for MetaTrader 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#property copyright "Stradeji" | |
#property link "https://www.stradeji.com" | |
#property version "1.0" | |
#property strict | |
#include <Trade\Trade.mqh> | |
CTrade ctrade; | |
ulong ACCOUNT_ID = 0; | |
input int m_magic; | |
input double m_lots; | |
input ENUM_TIMEFRAMES w_ma_timeframe; | |
input ENUM_TIMEFRAMES x_ma_timeframe; | |
input ENUM_TIMEFRAMES y_ma_timeframe; | |
input int w_ma_period; | |
input int x_ma_period; | |
input int y_ma_period; | |
input ENUM_MA_METHOD ma_method; | |
input ENUM_APPLIED_PRICE ma_applied_price_c; | |
input ENUM_APPLIED_PRICE ma_applied_price_m; | |
input double order_gap_atr; | |
input double mos_atr; | |
input int max_orders; | |
input int max_spread; | |
input int start_hour; | |
input int stop_hour; | |
input double max_sl_atr; | |
input double max_tp_atr; | |
input double sum_sl_atr; | |
input double sum_tp_atr; | |
input double sum_sl_usd; | |
input double sum_tp_usd; | |
input bool rest_on_sltp; | |
MqlDateTime time; | |
double sum_pip; | |
datetime stopped_at; | |
bool is_friday_night; | |
double x_ma_h_0, x_ma_l_0, x_ma_m_0, x_atr; | |
double y_ma_h_0, y_ma_l_0; | |
bool w_is_up, w_is_down; | |
bool x_is_up, x_is_down; | |
bool y_is_up, y_is_down; | |
ulong buy_positions[], sell_positions[]; | |
double buy_nearest_price, sell_nearest_price; | |
int OnInit() { | |
ctrade.SetExpertMagicNumber(m_magic); | |
return AccountInfoInteger(ACCOUNT_LOGIN) == ACCOUNT_ID && m_magic != 0 ? INIT_SUCCEEDED : INIT_FAILED; | |
} | |
void OnTick() { | |
TimeCurrent(time); | |
is_friday_night = time.hour == 23 && time.day_of_week == 5; | |
if (should_stop()) return; | |
get_ta_w(); | |
get_ta_x(); | |
get_ta_y(); | |
if (x_atr == 0) return; | |
get_positions(); | |
open_buy(); | |
open_sell(); | |
close_buys(); | |
close_sells(); | |
} | |
void get_ta_w() { | |
if (w_ma_period == 0) return; | |
int handle_ma_c = iMA(Symbol(), w_ma_timeframe, w_ma_period, 0, ma_method, ma_applied_price_c); | |
double buff_ma_c[]; | |
CopyBuffer(handle_ma_c, 0, 0, 2, buff_ma_c); | |
double w_ma_c_0 = buff_ma_c[1]; | |
double w_ma_c_1 = buff_ma_c[0]; | |
w_is_up = w_ma_c_1 < w_ma_c_0; | |
w_is_down = w_ma_c_1 > w_ma_c_0; | |
} | |
void get_ta_x() { | |
if (x_ma_period == 0) return; | |
int handle_ma_h = iMA(Symbol(), x_ma_timeframe, x_ma_period, 0, ma_method, PRICE_HIGH); | |
int handle_ma_l = iMA(Symbol(), x_ma_timeframe, x_ma_period, 0, ma_method, PRICE_LOW); | |
int handle_ma_c = iMA(Symbol(), x_ma_timeframe, x_ma_period, 0, ma_method, ma_applied_price_c); | |
int handle_ma_m = iMA(Symbol(), x_ma_timeframe, x_ma_period, 0, ma_method, ma_applied_price_m); | |
double buff_ma_h[]; | |
CopyBuffer(handle_ma_h, 0, 0, 1, buff_ma_h); | |
x_ma_h_0 = buff_ma_h[0]; | |
double buff_ma_l[]; | |
CopyBuffer(handle_ma_l, 0, 0, 1, buff_ma_l); | |
x_ma_l_0 = buff_ma_l[0]; | |
double buff_ma_c[]; | |
CopyBuffer(handle_ma_c, 0, 0, 2, buff_ma_c); | |
double x_ma_c_0 = buff_ma_c[1]; | |
double x_ma_c_1 = buff_ma_c[0]; | |
double buff_ma_m[]; | |
CopyBuffer(handle_ma_m, 0, 0, 1, buff_ma_m); | |
x_ma_m_0 = buff_ma_m[0]; | |
x_atr = x_ma_h_0 - x_ma_l_0; | |
x_is_up = x_ma_c_1 < x_ma_c_0; | |
x_is_down = x_ma_c_1 > x_ma_c_0; | |
} | |
void get_ta_y() { | |
if (y_ma_period == 0) return; | |
int handle_ma_h = iMA(Symbol(), y_ma_timeframe, y_ma_period, 0, ma_method, PRICE_HIGH); | |
int handle_ma_l = iMA(Symbol(), y_ma_timeframe, y_ma_period, 0, ma_method, PRICE_LOW); | |
int handle_ma_c = iMA(Symbol(), y_ma_timeframe, y_ma_period, 0, ma_method, ma_applied_price_c); | |
double buff_ma_h[]; | |
CopyBuffer(handle_ma_h, 0, 0, 1, buff_ma_h); | |
y_ma_h_0 = buff_ma_h[0]; | |
double buff_ma_l[]; | |
CopyBuffer(handle_ma_l, 0, 0, 1, buff_ma_l); | |
y_ma_l_0 = buff_ma_l[0]; | |
double buff_ma_c[]; | |
CopyBuffer(handle_ma_c, 0, 0, 2, buff_ma_c); | |
double y_ma_c_0 = buff_ma_c[1]; | |
double y_ma_c_1 = buff_ma_c[0]; | |
y_is_up = y_ma_c_1 < y_ma_c_0; | |
y_is_down = y_ma_c_1 > y_ma_c_0; | |
} | |
bool should_stop() { | |
if (stopped_at > 0) { | |
if (time.hour == start_hour && time.min == 0) { | |
stopped_at = 0; | |
return false; | |
} | |
return true; | |
} else if (sum_sl_atr > 0 || sum_tp_atr > 0) { | |
if ((sum_sl_atr > 0 && sum_pip < -sum_sl_atr * x_atr) || | |
(sum_tp_atr > 0 && sum_pip > sum_tp_atr * x_atr)) { | |
if (rest_on_sltp) stopped_at = TimeCurrent(); | |
close_all_positions(); | |
return true; | |
} | |
} else if (sum_sl_usd > 0 || sum_tp_usd > 0) { | |
double pl = AccountInfoDouble(ACCOUNT_PROFIT); | |
if ((sum_sl_usd > 0 && pl < -sum_sl_usd) || (sum_tp_usd > 0 && pl > sum_tp_usd)) { | |
if (rest_on_sltp) stopped_at = TimeCurrent(); | |
if (Symbol() == "EURUSD") close_all_positions(); | |
return true; | |
} | |
} | |
return false; | |
} | |
bool is_working_time() { | |
if (start_hour == 0 && stop_hour == 0) { | |
return !is_friday_night; | |
} else if (start_hour >= 0 && stop_hour > 0) { | |
return time.hour >= start_hour && time.hour < stop_hour; | |
} else if (start_hour > 0) { | |
return time.hour >= start_hour && time.hour < 23; | |
} else { | |
return time.hour < 23; | |
} | |
} | |
bool is_closing_time() { | |
if (stop_hour > 0) return time.hour == stop_hour; | |
return is_friday_night; | |
} | |
bool should_skip() { | |
if (!is_working_time()) return true; | |
if (SymbolInfoInteger(Symbol(), SYMBOL_SPREAD) > max_spread) return true; | |
return false; | |
} | |
bool should_open_buy() { | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_ASK); | |
if (w_ma_period > 0 && w_ma_timeframe != x_ma_timeframe) { | |
bool wx_is_up = w_is_up && (x_is_up || price < x_ma_l_0 - mos_atr * x_atr); | |
bool x_is_safe = price < x_ma_m_0; | |
bool y_is_safe = y_is_down && price < y_ma_l_0; | |
return x_is_safe && y_is_safe && wx_is_up; | |
} | |
bool x_is_safe = price < x_ma_m_0 + mos_atr * x_atr; | |
bool y_is_safe = y_is_down && price < y_ma_l_0; | |
return x_is_safe && y_is_safe && x_is_up; | |
} | |
bool should_open_sell() { | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_BID); | |
if (w_ma_period > 0 && w_ma_timeframe != x_ma_timeframe) { | |
bool wx_is_down = w_is_down && (x_is_down || price > x_ma_h_0 + mos_atr * x_atr); | |
bool x_is_safe = price > x_ma_m_0; | |
bool y_is_safe = y_is_up && price > y_ma_h_0; | |
return x_is_safe && y_is_safe && wx_is_down; | |
} | |
bool x_is_safe = price > x_ma_m_0 - mos_atr * x_atr; | |
bool y_is_safe = y_is_up && price > y_ma_h_0; | |
return x_is_safe && y_is_safe && x_is_down; | |
} | |
bool should_close_buy() { | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_BID); | |
double open_price = PositionGetDouble(POSITION_PRICE_OPEN); | |
double profit = price - open_price; | |
double loss = open_price - price; | |
bool is_tp = max_tp_atr > 0 && profit > max_tp_atr * x_atr; | |
bool is_sl = max_sl_atr > 0 && loss > max_sl_atr * x_atr; | |
return is_tp || is_sl; | |
} | |
bool should_close_sell() { | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_ASK); | |
double open_price = PositionGetDouble(POSITION_PRICE_OPEN); | |
double profit = open_price - price; | |
double loss = price - open_price; | |
bool is_tp = max_tp_atr > 0 && profit > max_tp_atr * x_atr; | |
bool is_sl = max_sl_atr > 0 && loss > max_sl_atr * x_atr; | |
return is_tp || is_sl; | |
} | |
void open_buy() { | |
if (should_skip()) return; | |
if (!should_open_buy()) return; | |
if (ArraySize(buy_positions) >= max_orders) return; | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_ASK); | |
if (buy_nearest_price > 0 && buy_nearest_price - price < order_gap_atr * x_atr) return; | |
ctrade.PositionOpen(Symbol(), ORDER_TYPE_BUY, m_lots, price, 0, 0, ""); | |
} | |
void open_sell() { | |
if (should_skip()) return; | |
if (!should_open_sell()) return; | |
if (ArraySize(sell_positions) >= max_orders) return; | |
double price = SymbolInfoDouble(Symbol(), SYMBOL_BID); | |
if (sell_nearest_price > 0 && price - sell_nearest_price < order_gap_atr * x_atr) return; | |
ctrade.PositionOpen(Symbol(), ORDER_TYPE_SELL, m_lots, price, 0, 0, ""); | |
} | |
void close_buys() { | |
if ((is_closing_time() && (sum_pip > 0 || x_is_down)) || is_friday_night) { | |
close_all_buys(); | |
return; | |
} | |
for (int i = 0; i < ArraySize(buy_positions); i++) { | |
if (!PositionSelectByTicket(buy_positions[i])) continue; | |
if (should_close_buy()) ctrade.PositionClose(PositionGetInteger(POSITION_TICKET)); | |
} | |
} | |
void close_sells() { | |
if ((is_closing_time() && (sum_pip > 0 || x_is_up)) || is_friday_night) { | |
close_all_sells(); | |
return; | |
} | |
for (int i = 0; i < ArraySize(sell_positions); i++) { | |
if (!PositionSelectByTicket(sell_positions[i])) continue; | |
if (should_close_sell()) ctrade.PositionClose(PositionGetInteger(POSITION_TICKET)); | |
} | |
} | |
void get_positions() { | |
int size = 0; | |
ArrayFree(buy_positions); | |
ArrayFree(sell_positions); | |
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); | |
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); | |
sum_pip = 0; | |
for (int i = PositionsTotal() - 1; i >= 0; i--) { | |
ulong ticket = PositionGetTicket(i); | |
if (ticket == 0) continue; | |
if (PositionGetString(POSITION_SYMBOL) != Symbol() || | |
PositionGetInteger(POSITION_MAGIC) != m_magic) continue; | |
double open_price = PositionGetDouble(POSITION_PRICE_OPEN); | |
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { | |
size = ArraySize(buy_positions); | |
ArrayResize(buy_positions, size + 1); | |
buy_positions[size] = ticket; | |
if (buy_nearest_price == 0 || MathAbs(open_price - Ask) < MathAbs(buy_nearest_price - Ask)) { | |
buy_nearest_price = open_price; | |
} | |
sum_pip += Bid - open_price; | |
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { | |
size = ArraySize(sell_positions); | |
ArrayResize(sell_positions, size + 1); | |
sell_positions[size] = ticket; | |
if (sell_nearest_price == 0 || MathAbs(open_price - Bid) < MathAbs(sell_nearest_price - Bid)) { | |
sell_nearest_price = open_price; | |
} | |
sum_pip += open_price - Ask; | |
} | |
} | |
} | |
void close_all_buys() { | |
for (int i = 0; i < ArraySize(buy_positions); i++) { | |
if (!PositionSelectByTicket(buy_positions[i])) continue; | |
ctrade.PositionClose(PositionGetInteger(POSITION_TICKET)); | |
} | |
} | |
void close_all_sells() { | |
for (int i = 0; i < ArraySize(sell_positions); i++) { | |
if (!PositionSelectByTicket(sell_positions[i])) continue; | |
ctrade.PositionClose(PositionGetInteger(POSITION_TICKET)); | |
} | |
} | |
void close_all_positions() { | |
for (int i = PositionsTotal() - 1; i >= 0; i--) { | |
ulong ticket = PositionGetTicket(i); | |
if (ticket == 0) continue; | |
if (PositionGetInteger(POSITION_MAGIC) != m_magic) continue; | |
ctrade.PositionClose(ticket); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment