Initial commit: MAEA Expert Advisor v1.00
- Implemented complete trend-following strategy with EMA-based signals - Added 5 visual indicator lines (3 EMAs + 2 Border Lines) - Implemented breakthrough and pullback signal detection - Added dynamic lot sizing (0.01/0.02 based on pullback) - Implemented comprehensive filters: * Volume filter (20-bar average) * Spread filter (max 30 points) * Multiple Timeframe filter (H1 trading, D1 trend confirmation) * News filter (Thailand timezone) - Added advanced risk management: * Take Profit in USD * Stop Loss at Border Lines * Breakeven (100 points) * Trailing Stop (100 points) * Max drawdown protection (10%) - Created comprehensive documentation - Connected to Gitea repository
This commit is contained in:
775
MAEA.mq4
Normal file
775
MAEA.mq4
Normal file
@@ -0,0 +1,775 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MAEA.mq4 |
|
||||
//| Moving Average Expert Advisor |
|
||||
//| Advanced Trend-Following Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "MAEA"
|
||||
#property link "https://git.moreminimore.com/kunthawat/MAEA"
|
||||
#property version "1.00"
|
||||
#property strict
|
||||
#property indicator_chart_window
|
||||
|
||||
//--- Indicator buffers
|
||||
#property indicator_buffers 5
|
||||
#property indicator_plots 5
|
||||
|
||||
//--- Plot settings for EMA High
|
||||
#property indicator_label1 "EMA High"
|
||||
#property indicator_type1 DRAW_LINE
|
||||
#property indicator_color1 clrLightBlue
|
||||
#property indicator_style1 STYLE_SOLID
|
||||
#property indicator_width1 2
|
||||
|
||||
//--- Plot settings for EMA Medium
|
||||
#property indicator_label2 "EMA Medium"
|
||||
#property indicator_type2 DRAW_LINE
|
||||
#property indicator_color2 clrYellow
|
||||
#property indicator_style2 STYLE_SOLID
|
||||
#property indicator_width2 2
|
||||
|
||||
//--- Plot settings for EMA Low
|
||||
#property indicator_label3 "EMA Low"
|
||||
#property indicator_type3 DRAW_LINE
|
||||
#property indicator_color3 clrOrange
|
||||
#property indicator_style3 STYLE_SOLID
|
||||
#property indicator_width3 2
|
||||
|
||||
//--- Plot settings for High Border
|
||||
#property indicator_label4 "High Border"
|
||||
#property indicator_type4 DRAW_LINE
|
||||
#property indicator_color4 clrPurple
|
||||
#property indicator_style4 STYLE_DASH
|
||||
#property indicator_width4 1
|
||||
|
||||
//--- Plot settings for Low Border
|
||||
#property indicator_label5 "Low Border"
|
||||
#property indicator_type5 DRAW_LINE
|
||||
#property indicator_color5 clrPurple
|
||||
#property indicator_style5 STYLE_DASH
|
||||
#property indicator_width5 1
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Input Parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
input string Section1 = "=== EMA Settings ===";
|
||||
input int EMAPeriod = 30; // EMA Period for all lines
|
||||
|
||||
input string Section2 = "=== Lot Settings ===";
|
||||
input double LotSizeNormal = 0.01; // Lot size without pullback
|
||||
input double LotSizePullback = 0.02; // Lot size with pullback
|
||||
|
||||
input string Section3 = "=== Risk Management ===";
|
||||
input double TakeProfitUSD = 5.0; // Take Profit target in USD
|
||||
input int BreakevenPoints = 100; // Points to trigger breakeven
|
||||
input int TrailingStopPoints = 100; // Trailing stop distance
|
||||
input double MaxDrawdownPercent = 10.0;// Max drawdown percentage
|
||||
|
||||
input string Section4 = "=== Filters ===";
|
||||
input int MaxSpread = 30; // Maximum allowed spread in points
|
||||
input int VolumePeriod = 20; // Period for volume average
|
||||
input bool UseMTFFilter = true; // Enable MTF filter
|
||||
input bool UseNewsFilter = true; // Enable news filter
|
||||
input string NewsAvoidHours = "14,15,20,21"; // Hours to avoid (Thailand time)
|
||||
input string NewsAvoidDays = "1,5"; // Days to avoid (Monday=1, Friday=5)
|
||||
|
||||
input string Section5 = "=== General ===";
|
||||
input int MagicNumber = 12345; // EA unique identifier
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables |
|
||||
//+------------------------------------------------------------------+
|
||||
// Indicator buffers
|
||||
double EMAHighBuffer[];
|
||||
double EMAMediumBuffer[];
|
||||
double EMALowBuffer[];
|
||||
double HighBorderBuffer[];
|
||||
double LowBorderBuffer[];
|
||||
|
||||
// EMA handles
|
||||
int EMAHighHandle;
|
||||
int EMAMediumHandle;
|
||||
int EMALowHandle;
|
||||
|
||||
// D1 EMA handles for MTF filter
|
||||
int D1_EMAHighHandle;
|
||||
int D1_EMAMediumHandle;
|
||||
int D1_EMALowHandle;
|
||||
|
||||
// State tracking
|
||||
bool PullbackBuy = false;
|
||||
bool PullbackSell = false;
|
||||
bool BreakevenTriggered = false;
|
||||
double OrderOpenPrice = 0;
|
||||
double OrderStopLoss = 0;
|
||||
double OrderTakeProfit = 0;
|
||||
int OrderTicket = 0;
|
||||
|
||||
// Drawdown tracking
|
||||
double AccountEquityPeak = 0;
|
||||
|
||||
// Previous bar values for signal detection
|
||||
double PrevClose = 0;
|
||||
double PrevEMAHigh = 0;
|
||||
double PrevEMAMedium = 0;
|
||||
double PrevEMALow = 0;
|
||||
|
||||
// News filter arrays
|
||||
int AvoidHoursArray[];
|
||||
int AvoidDaysArray[];
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
// Set indicator buffers
|
||||
SetIndexBuffer(0, EMAHighBuffer);
|
||||
SetIndexBuffer(1, EMAMediumBuffer);
|
||||
SetIndexBuffer(2, EMALowBuffer);
|
||||
SetIndexBuffer(3, HighBorderBuffer);
|
||||
SetIndexBuffer(4, LowBorderBuffer);
|
||||
|
||||
// Set indicator labels
|
||||
PlotIndexSetString(0, PLOT_LABEL, "EMA High");
|
||||
PlotIndexSetString(1, PLOT_LABEL, "EMA Medium");
|
||||
PlotIndexSetString(2, PLOT_LABEL, "EMA Low");
|
||||
PlotIndexSetString(3, PLOT_LABEL, "High Border");
|
||||
PlotIndexSetString(4, PLOT_LABEL, "Low Border");
|
||||
|
||||
// Initialize EMA handles
|
||||
EMAHighHandle = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_HIGH);
|
||||
EMAMediumHandle = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
||||
EMALowHandle = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_LOW);
|
||||
|
||||
// Initialize D1 EMA handles for MTF filter
|
||||
D1_EMAHighHandle = iMA(Symbol(), PERIOD_D1, EMAPeriod, 0, MODE_EMA, PRICE_HIGH);
|
||||
D1_EMAMediumHandle = iMA(Symbol(), PERIOD_D1, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
||||
D1_EMALowHandle = iMA(Symbol(), PERIOD_D1, EMAPeriod, 0, MODE_EMA, PRICE_LOW);
|
||||
|
||||
// Check handles
|
||||
if(EMAHighHandle == INVALID_HANDLE || EMAMediumHandle == INVALID_HANDLE || EMALowHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print("Error creating EMA handles");
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
if(UseMTFFilter && (D1_EMAHighHandle == INVALID_HANDLE || D1_EMAMediumHandle == INVALID_HANDLE || D1_EMALowHandle == INVALID_HANDLE))
|
||||
{
|
||||
Print("Error creating D1 EMA handles");
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
// Parse news filter arrays
|
||||
ParseNewsFilterArrays();
|
||||
|
||||
// Initialize account equity peak
|
||||
AccountEquityPeak = AccountEquity();
|
||||
|
||||
Print("MAEA initialized successfully");
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
// Release indicator handles
|
||||
if(EMAHighHandle != INVALID_HANDLE) IndicatorRelease(EMAHighHandle);
|
||||
if(EMAMediumHandle != INVALID_HANDLE) IndicatorRelease(EMAMediumHandle);
|
||||
if(EMALowHandle != INVALID_HANDLE) IndicatorRelease(EMALowHandle);
|
||||
if(D1_EMAHighHandle != INVALID_HANDLE) IndicatorRelease(D1_EMAHighHandle);
|
||||
if(D1_EMAMediumHandle != INVALID_HANDLE) IndicatorRelease(D1_EMAMediumHandle);
|
||||
if(D1_EMALowHandle != INVALID_HANDLE) IndicatorRelease(D1_EMALowHandle);
|
||||
|
||||
Print("MAEA deinitialized");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator iteration function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnCalculate(const int rates_total,
|
||||
const int prev_calculated,
|
||||
const datetime &time[],
|
||||
const double &open[],
|
||||
const double &high[],
|
||||
const double &low[],
|
||||
const double &close[],
|
||||
const long &tick_volume[],
|
||||
const long &volume[],
|
||||
const int &spread[])
|
||||
{
|
||||
// Check for minimum bars
|
||||
if(rates_total < EMAPeriod + 1) return(0);
|
||||
|
||||
// Set arrays as series
|
||||
ArraySetAsSeries(EMAHighBuffer, false);
|
||||
ArraySetAsSeries(EMAMediumBuffer, false);
|
||||
ArraySetAsSeries(EMALowBuffer, false);
|
||||
ArraySetAsSeries(HighBorderBuffer, false);
|
||||
ArraySetAsSeries(LowBorderBuffer, false);
|
||||
|
||||
// Calculate start position
|
||||
int start;
|
||||
if(prev_calculated == 0)
|
||||
{
|
||||
start = EMAPeriod;
|
||||
// Initialize buffers
|
||||
for(int i = 0; i < start; i++)
|
||||
{
|
||||
EMAHighBuffer[i] = 0;
|
||||
EMAMediumBuffer[i] = 0;
|
||||
EMALowBuffer[i] = 0;
|
||||
HighBorderBuffer[i] = 0;
|
||||
LowBorderBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = prev_calculated - 1;
|
||||
}
|
||||
|
||||
// Calculate EMA values and border lines
|
||||
for(int i = start; i < rates_total; i++)
|
||||
{
|
||||
// Get EMA values
|
||||
double emaHigh = GetEMAValue(EMAHighHandle, i);
|
||||
double emaMedium = GetEMAValue(EMAMediumHandle, i);
|
||||
double emaLow = GetEMAValue(EMALowHandle, i);
|
||||
|
||||
// Calculate range
|
||||
double range = emaMedium - emaLow;
|
||||
|
||||
// Calculate border lines
|
||||
double highBorder = emaHigh + range;
|
||||
double lowBorder = emaLow - range;
|
||||
|
||||
// Store values in buffers
|
||||
EMAHighBuffer[i] = emaHigh;
|
||||
EMAMediumBuffer[i] = emaMedium;
|
||||
EMALowBuffer[i] = emaLow;
|
||||
HighBorderBuffer[i] = highBorder;
|
||||
LowBorderBuffer[i] = lowBorder;
|
||||
}
|
||||
|
||||
// Only process trading logic on new bar
|
||||
static datetime lastBarTime = 0;
|
||||
if(time[rates_total - 1] != lastBarTime)
|
||||
{
|
||||
lastBarTime = time[rates_total - 1];
|
||||
|
||||
// Update previous bar values
|
||||
int lastBar = rates_total - 1;
|
||||
int prevBar = rates_total - 2;
|
||||
|
||||
if(prevBar >= EMAPeriod)
|
||||
{
|
||||
PrevClose = close[prevBar];
|
||||
PrevEMAHigh = EMAHighBuffer[prevBar];
|
||||
PrevEMAMedium = EMAMediumBuffer[prevBar];
|
||||
PrevEMALow = EMALowBuffer[prevBar];
|
||||
|
||||
// Process trading logic
|
||||
ProcessTradingLogic(rates_total, time, open, high, low, close, tick_volume, spread);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage open orders on every tick
|
||||
ManageOpenOrders();
|
||||
|
||||
return(rates_total);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get EMA value from handle |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetEMAValue(int handle, int shift)
|
||||
{
|
||||
double value[];
|
||||
ArraySetAsSeries(value, true);
|
||||
CopyBuffer(handle, 0, shift, 1, value);
|
||||
return(value[0]);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Parse news filter arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
void ParseNewsFilterArrays()
|
||||
{
|
||||
// Parse hours
|
||||
string hoursStr = NewsAvoidHours;
|
||||
ArrayResize(AvoidHoursArray, 0);
|
||||
while(hoursStr != "")
|
||||
{
|
||||
int pos = StringFind(hoursStr, ",");
|
||||
string hourStr;
|
||||
if(pos >= 0)
|
||||
{
|
||||
hourStr = StringSubstr(hoursStr, 0, pos);
|
||||
hoursStr = StringSubstr(hoursStr, pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
hourStr = hoursStr;
|
||||
hoursStr = "";
|
||||
}
|
||||
StringTrimLeft(hourStr);
|
||||
StringTrimRight(hourStr);
|
||||
if(hourStr != "")
|
||||
{
|
||||
int hour = (int)StringToInteger(hourStr);
|
||||
int size = ArraySize(AvoidHoursArray);
|
||||
ArrayResize(AvoidHoursArray, size + 1);
|
||||
AvoidHoursArray[size] = hour;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse days
|
||||
string daysStr = NewsAvoidDays;
|
||||
ArrayResize(AvoidDaysArray, 0);
|
||||
while(daysStr != "")
|
||||
{
|
||||
int pos = StringFind(daysStr, ",");
|
||||
string dayStr;
|
||||
if(pos >= 0)
|
||||
{
|
||||
dayStr = StringSubstr(daysStr, 0, pos);
|
||||
daysStr = StringSubstr(daysStr, pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dayStr = daysStr;
|
||||
daysStr = "";
|
||||
}
|
||||
StringTrimLeft(dayStr);
|
||||
StringTrimRight(dayStr);
|
||||
if(dayStr != "")
|
||||
{
|
||||
int day = (int)StringToInteger(dayStr);
|
||||
int size = ArraySize(AvoidDaysArray);
|
||||
ArrayResize(AvoidDaysArray, size + 1);
|
||||
AvoidDaysArray[size] = day;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Process trading logic |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessTradingLogic(const int rates_total,
|
||||
const datetime &time[],
|
||||
const double &open[],
|
||||
const double &high[],
|
||||
const double &low[],
|
||||
const double &close[],
|
||||
const long &tick_volume[],
|
||||
const int &spread[])
|
||||
{
|
||||
// Check if we have an open order
|
||||
if(HasOpenOrder()) return;
|
||||
|
||||
// Check drawdown
|
||||
if(!CheckDrawdown()) return;
|
||||
|
||||
// Check news filter
|
||||
if(UseNewsFilter && !CheckNewsFilter(time[rates_total - 1])) return;
|
||||
|
||||
// Check spread filter
|
||||
if(spread[rates_total - 1] > MaxSpread) return;
|
||||
|
||||
// Check volume filter
|
||||
if(!CheckVolumeFilter(tick_volume, rates_total)) return;
|
||||
|
||||
// Check MTF filter
|
||||
if(UseMTFFilter && !CheckMTFFilter()) return;
|
||||
|
||||
// Get current values
|
||||
int lastBar = rates_total - 1;
|
||||
double currentClose = close[lastBar];
|
||||
double currentEMAHigh = EMAHighBuffer[lastBar];
|
||||
double currentEMALow = EMALowBuffer[lastBar];
|
||||
|
||||
// Detect pullback signals
|
||||
DetectPullbackSignals(currentClose, currentEMAHigh, PrevEMAHigh, currentEMALow, PrevEMALow, PrevEMAMedium);
|
||||
|
||||
// Detect breakthrough signals
|
||||
if(DetectBreakthroughBuy(currentClose, currentEMAHigh, PrevClose, PrevEMAHigh))
|
||||
{
|
||||
OpenBuyOrder();
|
||||
}
|
||||
else if(DetectBreakthroughSell(currentClose, currentEMALow, PrevClose, PrevEMALow))
|
||||
{
|
||||
OpenSellOrder();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect pullback signals |
|
||||
//+------------------------------------------------------------------+
|
||||
void DetectPullbackSignals(double currentClose, double currentEMAHigh, double prevEMAHigh,
|
||||
double currentEMALow, double prevEMALow, double prevEMAMedium)
|
||||
{
|
||||
// Buy pullback: price moved down to hit a line, then closed above it
|
||||
if(PrevClose < prevEMAMedium && currentClose > currentEMALow)
|
||||
{
|
||||
PullbackBuy = true;
|
||||
}
|
||||
else if(PrevClose < prevEMALow && currentClose > currentEMALow)
|
||||
{
|
||||
PullbackBuy = true;
|
||||
}
|
||||
else if(PrevClose < prevEMAHigh && currentClose > currentEMAHigh)
|
||||
{
|
||||
PullbackBuy = true;
|
||||
}
|
||||
|
||||
// Sell pullback: price moved up to hit a line, then closed below it
|
||||
if(PrevClose > prevEMAMedium && currentClose < currentEMAHigh)
|
||||
{
|
||||
PullbackSell = true;
|
||||
}
|
||||
else if(PrevClose > prevEMAHigh && currentClose < currentEMAHigh)
|
||||
{
|
||||
PullbackSell = true;
|
||||
}
|
||||
else if(PrevClose > prevEMALow && currentClose < currentEMALow)
|
||||
{
|
||||
PullbackSell = true;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect breakthrough buy signal |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DetectBreakthroughBuy(double currentClose, double currentEMAHigh, double prevClose, double prevEMAHigh)
|
||||
{
|
||||
return (prevClose <= prevEMAHigh && currentClose > currentEMAHigh);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detect breakthrough sell signal |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DetectBreakthroughSell(double currentClose, double currentEMALow, double prevClose, double prevEMALow)
|
||||
{
|
||||
return (prevClose >= prevEMALow && currentClose < currentEMALow);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check volume filter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CheckVolumeFilter(const long &tick_volume[], int rates_total)
|
||||
{
|
||||
if(rates_total < VolumePeriod + 1) return false;
|
||||
|
||||
// Calculate average volume
|
||||
double avgVolume = 0;
|
||||
for(int i = rates_total - VolumePeriod - 1; i < rates_total - 1; i++)
|
||||
{
|
||||
avgVolume += tick_volume[i];
|
||||
}
|
||||
avgVolume /= VolumePeriod;
|
||||
|
||||
// Check if current volume is above average
|
||||
return (tick_volume[rates_total - 1] > avgVolume);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check MTF filter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CheckMTFFilter()
|
||||
{
|
||||
double d1Close = iClose(Symbol(), PERIOD_D1, 0);
|
||||
double d1EMAHigh = GetEMAValue(D1_EMAHighHandle, 0);
|
||||
double d1EMALow = GetEMAValue(D1_EMALowHandle, 0);
|
||||
|
||||
if(d1Close > d1EMAHigh)
|
||||
{
|
||||
// Only buy orders allowed
|
||||
return true;
|
||||
}
|
||||
else if(d1Close < d1EMALow)
|
||||
{
|
||||
// Only sell orders allowed
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Price between lines - no orders allowed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check news filter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CheckNewsFilter(datetime currentTime)
|
||||
{
|
||||
MqlDateTime timeStruct;
|
||||
TimeToStruct(currentTime, timeStruct);
|
||||
|
||||
// Convert to Thailand timezone (UTC+7)
|
||||
// MT4 server time is usually UTC, so add 7 hours
|
||||
int thailandHour = (timeStruct.hour + 7) % 24;
|
||||
int thailandDay = timeStruct.day_of_week;
|
||||
|
||||
// Check if current hour is in avoid list
|
||||
for(int i = 0; i < ArraySize(AvoidHoursArray); i++)
|
||||
{
|
||||
if(thailandHour == AvoidHoursArray[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if current day is in avoid list
|
||||
for(int i = 0; i < ArraySize(AvoidDaysArray); i++)
|
||||
{
|
||||
if(thailandDay == AvoidDaysArray[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check drawdown |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CheckDrawdown()
|
||||
{
|
||||
double currentEquity = AccountEquity();
|
||||
|
||||
// Update peak equity
|
||||
if(currentEquity > AccountEquityPeak)
|
||||
{
|
||||
AccountEquityPeak = currentEquity;
|
||||
}
|
||||
|
||||
// Calculate drawdown percentage
|
||||
double drawdownPercent = ((AccountEquityPeak - currentEquity) / AccountEquityPeak) * 100;
|
||||
|
||||
// Check if drawdown exceeds limit
|
||||
if(drawdownPercent >= MaxDrawdownPercent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open buy order |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenBuyOrder()
|
||||
{
|
||||
double lotSize = PullbackBuy ? LotSizePullback : LotSizeNormal;
|
||||
double stopLoss = LowBorderBuffer[ArraySize(LowBorderBuffer) - 1];
|
||||
double takeProfit = CalculateTakeProfit(lotSize, OP_BUY);
|
||||
|
||||
OrderTicket = OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, stopLoss, takeProfit, "MAEA Buy", MagicNumber, 0, clrBlue);
|
||||
|
||||
if(OrderTicket > 0)
|
||||
{
|
||||
OrderOpenPrice = Ask;
|
||||
OrderStopLoss = stopLoss;
|
||||
OrderTakeProfit = takeProfit;
|
||||
BreakevenTriggered = false;
|
||||
|
||||
// Reset pullback flags
|
||||
PullbackBuy = false;
|
||||
PullbackSell = false;
|
||||
|
||||
Print("Buy order opened: Ticket=", OrderTicket, " Price=", Ask, " SL=", stopLoss, " TP=", takeProfit);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Error opening buy order: ", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open sell order |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenSellOrder()
|
||||
{
|
||||
double lotSize = PullbackSell ? LotSizePullback : LotSizeNormal;
|
||||
double stopLoss = HighBorderBuffer[ArraySize(HighBorderBuffer) - 1];
|
||||
double takeProfit = CalculateTakeProfit(lotSize, OP_SELL);
|
||||
|
||||
OrderTicket = OrderSend(Symbol(), OP_SELL, lotSize, Bid, 3, stopLoss, takeProfit, "MAEA Sell", MagicNumber, 0, clrRed);
|
||||
|
||||
if(OrderTicket > 0)
|
||||
{
|
||||
OrderOpenPrice = Bid;
|
||||
OrderStopLoss = stopLoss;
|
||||
OrderTakeProfit = takeProfit;
|
||||
BreakevenTriggered = false;
|
||||
|
||||
// Reset pullback flags
|
||||
PullbackBuy = false;
|
||||
PullbackSell = false;
|
||||
|
||||
Print("Sell order opened: Ticket=", OrderTicket, " Price=", Bid, " SL=", stopLoss, " TP=", takeProfit);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Error opening sell order: ", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate take profit in pips from USD target |
|
||||
//+------------------------------------------------------------------+
|
||||
double CalculateTakeProfit(double lotSize, int orderType)
|
||||
{
|
||||
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
|
||||
double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
|
||||
double pipValue = tickValue / tickSize * Point;
|
||||
|
||||
double profitInPips = TakeProfitUSD / (lotSize * pipValue);
|
||||
double profitInPrice = profitInPips * Point;
|
||||
|
||||
if(orderType == OP_BUY)
|
||||
{
|
||||
return Ask + profitInPrice;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Bid - profitInPrice;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if we have an open order |
|
||||
//+------------------------------------------------------------------+
|
||||
bool HasOpenOrder()
|
||||
{
|
||||
if(OrderTicket == 0) return false;
|
||||
|
||||
if(OrderSelect(OrderTicket, SELECT_BY_TICKET))
|
||||
{
|
||||
if(OrderCloseTime() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
OrderTicket = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OrderTicket = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Manage open orders |
|
||||
//+------------------------------------------------------------------+
|
||||
void ManageOpenOrders()
|
||||
{
|
||||
if(!HasOpenOrder()) return;
|
||||
|
||||
if(!OrderSelect(OrderTicket, SELECT_BY_TICKET)) return;
|
||||
|
||||
double currentPrice = OrderType() == OP_BUY ? Bid : Ask;
|
||||
double currentProfit = OrderProfit();
|
||||
double openPrice = OrderOpenPrice();
|
||||
|
||||
// Check take profit
|
||||
if(currentProfit >= TakeProfitUSD)
|
||||
{
|
||||
CloseOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check stop loss
|
||||
if(OrderType() == OP_BUY && currentPrice <= OrderStopLoss())
|
||||
{
|
||||
CloseOrder();
|
||||
return;
|
||||
}
|
||||
else if(OrderType() == OP_SELL && currentPrice >= OrderStopLoss())
|
||||
{
|
||||
CloseOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate profit in points
|
||||
double profitPoints = 0;
|
||||
if(OrderType() == OP_BUY)
|
||||
{
|
||||
profitPoints = (currentPrice - openPrice) / Point;
|
||||
}
|
||||
else
|
||||
{
|
||||
profitPoints = (openPrice - currentPrice) / Point;
|
||||
}
|
||||
|
||||
// Check breakeven
|
||||
if(!BreakevenTriggered && profitPoints >= BreakevenPoints)
|
||||
{
|
||||
double newSL = openPrice;
|
||||
if(OrderModify(OrderTicket, openPrice, newSL, OrderTakeProfit(), 0, clrNONE))
|
||||
{
|
||||
BreakevenTriggered = true;
|
||||
OrderStopLoss = newSL;
|
||||
Print("Breakeven triggered: SL moved to ", newSL);
|
||||
}
|
||||
}
|
||||
|
||||
// Check trailing stop
|
||||
if(BreakevenTriggered && profitPoints >= BreakevenPoints + TrailingStopPoints)
|
||||
{
|
||||
double newSL;
|
||||
if(OrderType() == OP_BUY)
|
||||
{
|
||||
newSL = currentPrice - TrailingStopPoints * Point;
|
||||
if(newSL > OrderStopLoss())
|
||||
{
|
||||
if(OrderModify(OrderTicket, openPrice, newSL, OrderTakeProfit(), 0, clrNONE))
|
||||
{
|
||||
OrderStopLoss = newSL;
|
||||
Print("Trailing stop: SL moved to ", newSL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newSL = currentPrice + TrailingStopPoints * Point;
|
||||
if(newSL < OrderStopLoss())
|
||||
{
|
||||
if(OrderModify(OrderTicket, openPrice, newSL, OrderTakeProfit(), 0, clrNONE))
|
||||
{
|
||||
OrderStopLoss = newSL;
|
||||
Print("Trailing stop: SL moved to ", newSL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close order |
|
||||
//+------------------------------------------------------------------+
|
||||
void CloseOrder()
|
||||
{
|
||||
if(OrderSelect(OrderTicket, SELECT_BY_TICKET))
|
||||
{
|
||||
double closePrice = OrderType() == OP_BUY ? Bid : Ask;
|
||||
if(OrderClose(OrderTicket, OrderLots(), closePrice, 3, clrNONE))
|
||||
{
|
||||
Print("Order closed: Ticket=", OrderTicket, " Profit=", OrderProfit());
|
||||
OrderTicket = 0;
|
||||
BreakevenTriggered = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Error closing order: ", GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user