Skip to content

Instantly share code, notes, and snippets.

@tonkla
Created September 7, 2023 08:53
Show Gist options
  • Save tonkla/f9c281b7d132eaf94386d07a73b0e935 to your computer and use it in GitHub Desktop.
Save tonkla/f9c281b7d132eaf94386d07a73b0e935 to your computer and use it in GitHub Desktop.
A Moving Average (MA) -based Expert Advisors (EA) for MetaTrader 5
#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