feat(maea): migrate from MQL4 to MQL5 and simplify strategy

Migrate MAEA Expert Advisor from MetaTrader 4 to MetaTrader 5 platform with
significant strategy simplification and architectural improvements.

Key changes:
- Platform: MQL4 → MQL5
- Indicators: Reduced from 5 lines (3 EMAs + 2 borders) to 2 EMAs with zone fill
- Strategy: Removed pullback signals and dynamic lot sizing
- Lot sizing: Changed from dynamic (0.01/0.02) to fixed 0.01 lot
- Stop loss: Changed from Border Lines to opposite EMA (Buy: EMA Low, Sell: EMA High)
- Signal logic: Added opposite signal close for reversal protection
- New filter: Added minimum zone width filter (100 points)
- Documentation: Updated implementation plans and project summary
- New files: Added AGENTS.md, MAEA_Indicator.mq5, and opencode.jsonc

BREAKING CHANGE: Complete rewrite from MQL4 to MQL5 with simplified strategy.
Previous MAEA.mq4 and README.md deleted. New implementation requires MetaTrader 5.
This commit is contained in:
Kunthawat Greethong
2026-01-03 14:25:25 +07:00
parent cd0b2e35a2
commit db575179ae
8 changed files with 1019 additions and 1243 deletions

162
AGENTS.md Normal file
View File

@@ -0,0 +1,162 @@
# MAEA Development Guidelines
## Build and Test Commands
### Compilation
- Use MetaEditor (MT5 built-in editor) to compile the EA
- Press F7 or click Compile button in MetaEditor
- Check "Errors" tab in Toolbox for compilation issues
- All MQL5 files must compile with 0 errors before testing
### Testing
- Use MT5 Strategy Tester (Ctrl+T or View → Strategy Tester)
- Select "MAEA" from Expert Advisor dropdown
- Set testing parameters:
- Symbol: Desired currency pair
- Model: "Every tick" for accurate testing
- Period: H1 (recommended timeframe)
- Spread: Use current or specify fixed value
- Run single test: Click Start button in Strategy Tester
- Run optimization: Enable Genetic Algorithm or slow complete algorithm
- Optimization criteria: Balance, Profit Factor, Drawdown, or Sharpe Ratio
### Key Testing Scenarios
- Test EMA calculations accuracy by comparing with manual calculations
- Test breakthrough signals on historical data
- Test pullback detection on ranging markets
- Test all filters individually (enable one at a time)
- Test risk management (TP, SL, breakeven, trailing stop)
- Test max drawdown protection with aggressive parameters
## Code Style Guidelines
### File Naming and Organization
- EA file: `MAEA.mq5` (root directory)
- Use #include for external functions if needed
- Keep single file structure preferred for portability
### Naming Conventions
- **Input parameters**: PascalCase (e.g., `EMAPeriod`, `LotSizeNormal`, `TakeProfitUSD`)
- **Global variables**: g_PascalCase (e.g., `g_EMAHighBuffer`, `g_PullbackBuyDetected`)
- **Local variables**: camelCase (e.g., `currentClose`, `signalDetected`)
- **Functions**: PascalCase (e.g., `CalculateEMA()`, `CheckFilters()`, `OpenOrder()`)
- **Constants**: UPPER_CASE with underscore prefix (e.g., `_MAX_ORDERS`, `_DEFAULT_TP`)
### Imports and Includes
- MQL5 standard headers:
```mql5
#include <Trade\Trade.mqh>
#include <Indicators\Indicators.mqh>
#include <Arrays\ArrayDouble.mqh>
```
(Required for MT5 position management and indicator handling)
- Use MT5 standard functions and objects:
- CTrade class for position operations
- Indicator handles via iMA()
- Position operations: PositionSelect(), PositionGetSymbol()
- Use <Trade\Trade.mqh> as it's essential for MT5 trading operations
### Code Formatting
- Indentation: 4 spaces (no tabs)
- Braces: K&R style (opening brace on same line)
- Line length: Max 120 characters
- Blank line between functions
- Comment section headers like `// === INDICATOR CALCULATIONS ===`
### Variable Types
- Use explicit types, not auto
- Integer counts: `int`
- Prices and averages: `double`
- Boolean flags: `bool`
- Time values: `datetime`
- Array buffers: `double[]`
- String values: `string`
### Error Handling
- Always check return values for:
- CTrade.OrderOpen() - check return value
- CTrade.PositionModify() - check return value
- CTrade.PositionClose() - check return value
- Indicator handle creation - check if handle != INVALID_HANDLE
- ObjectCreate() - check return value
- Use GetLastError() after failed operations
- Log errors using Print() or Alert() for critical issues
- Example:
```mql5
CTrade trade;
trade.SetExpertMagicNumber(MagicNumber);
if(!trade.Buy(lotSize, Symbol(), price, sl, tp)) {
int err = GetLastError();
Print("OrderOpen failed. Error: ", err, " - ", ErrorDescription(err));
return;
}
```
### Input Parameters Structure
- Group related parameters together
- Use clear, descriptive comments
- Example format:
```mql5
// === EMA SETTINGS ===
input int EMAPeriod = 30; // EMA period for all indicator lines
// === RISK MANAGEMENT ===
input double TakeProfitUSD = 5.0; // Take profit target in USD
input int BreakevenPoints = 100; // Points to trigger breakeven
// === FILTERS ===
input bool UseMTFFilter = true; // Enable MTF filter
input int MaxSpread = 30; // Maximum spread in points
```
### Function Design
- Keep functions focused and under 40 lines if possible
- Use descriptive parameter names
- Return meaningful values (bool for success/failure when applicable)
- Document complex logic with inline comments
- Separate calculation logic from trading logic
### Timezone Handling
- All time-based logic uses Thailand timezone (UTC+7)
- Use TimeGMT() + 25200 seconds for Thailand time
- Convert server time to Thailand time for news filter checks
- Document timezone conversions explicitly in code
### Testing Best Practices
- Use MT5 Strategy Tester with "Every tick" model
- Test on multiple currency pairs (EURUSD, GBPUSD, XAUUSD)
- Test on different timeframes (M15, H1, H4)
- Verify indicators by visual inspection in tester
- Check both profitable and losing scenarios
- Validate filter logic by comparing tester results with expected behavior
- Paper trade on demo account before live trading
### Safety Constraints
- Never change code to bypass risk management
- Test all parameter changes in Strategy Tester first
- Ensure only one position can be open at a time (MT5 uses positions, not orders)
- Drawdown protection must be always active
- Stop Loss must always be set when opening positions
- Verify position count using PositionsTotal() and filter by MagicNumber
### Code Comments
- Comment complex calculations (especially EMA and Border Line formulas)
- Document edge cases and special conditions
- Include formula explanations: `// Border Line = EMA High + (EMA Medium - EMA Low)`
- No excessive comments for obvious code
### Trading Logic Organization
- Typical entry points: OnTick() (per tick) or OnNewBar() (on new candle)
- Structure: Indicators → Filters → Signals → Orders → Risk Management
- Use state variables to track:
- Pullback detection (buy and sell separately)
- Current drawdown
- Last bar time for new bar detection
- Order tracking for management
### Git Practices
- Commit after implementing each phase from the implementation plan
- Commit message format: "Phase X: Title - Brief description"
- Verify compilation before committing
- Test major features before committing
- Pull latest changes before starting new work

698
MAEA.mq4
View File

@@ -1,698 +0,0 @@
//+------------------------------------------------------------------+
//| 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
#property indicator_buffers 5
//+------------------------------------------------------------------+
//| 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[];
// 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
SetIndexLabel(0, "EMA High");
SetIndexLabel(1, "EMA Medium");
SetIndexLabel(2, "EMA Low");
SetIndexLabel(3, "High Border");
SetIndexLabel(4, "Low Border");
// Set indicator styles
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, clrLightBlue);
SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2, clrYellow);
SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 2, clrOrange);
SetIndexStyle(3, DRAW_LINE, STYLE_DASH, 1, clrPurple);
SetIndexStyle(4, DRAW_LINE, STYLE_DASH, 1, clrPurple);
// 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)
{
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 using iMA function (MQL4 style)
double emaHigh = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_HIGH, i);
double emaMedium = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
double emaLow = iMA(Symbol(), PERIOD_CURRENT, EMAPeriod, 0, MODE_EMA, PRICE_LOW, 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 timeframe, int applied_price, int shift)
{
return iMA(Symbol(), timeframe, EMAPeriod, 0, MODE_EMA, applied_price, shift);
}
//+------------------------------------------------------------------+
//| 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(PERIOD_D1, PRICE_HIGH, 0);
double d1EMALow = GetEMAValue(PERIOD_D1, PRICE_LOW, 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)
{
// Convert to Thailand timezone (UTC+7)
// MT4 server time is usually UTC, so add 7 hours
datetime thailandTime = currentTime + 7 * 3600; // 7 hours in seconds
int thailandHour = TimeHour(thailandTime);
int thailandDay = TimeDayOfWeek(thailandTime);
// 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());
}
}
}
//+------------------------------------------------------------------+

509
MAEA.mq5 Normal file
View File

@@ -0,0 +1,509 @@
//+------------------------------------------------------------------+
//| MAEA.mq5 |
//| Moving Average EA |
//| Trend-following EA with EMA zone breakout |
//+------------------------------------------------------------------+
#property copyright "MAEA"
#property link ""
#property version "1.00"
#property strict
#include <Trade\Trade.mqh>
#include <Indicators\Indicators.mqh>
// === EMA SETTINGS ===
input int EMAPeriod = 30;
input int EMAShift = 0;
input int MinZoneWidthPoints = 100;
// === RISK MANAGEMENT ===
input double LotSize = 0.01;
input double TakeProfitUSD = 5.0;
input int BreakevenPoints = 100;
input int TrailingStopPoints = 100;
// === FILTERS ===
input bool UseMTFFilter = true;
input bool UseNewsFilter = true;
input int MaxSpread = 30;
input int VolumePeriod = 20;
// === NEWS FILTER ===
input string NewsAvoidHours = "14,15,20,21";
input string NewsAvoidDays = "1,5";
// === RISK PROTECTION ===
input double MaxDrawdownPercent = 10.0;
// === EA SETTINGS ===
input int MagicNumber = 12345;
// === GLOBAL VARIABLES ===
CTrade trade;
int handleEMAHigh = INVALID_HANDLE;
int handleEMALow = INVALID_HANDLE;
int handleD1EMAHigh = INVALID_HANDLE;
int handleD1EMALow = INVALID_HANDLE;
double g_EMAHighBuffer[];
double g_EMALowBuffer[];
double g_D1EMAHighBuffer[];
double g_D1EMALowBuffer[];
datetime g_LastBarTime = 0;
double g_EntryPrice = 0;
double g_BreakevenPrice = 0;
bool g_BreakevenTriggered = false;
bool g_TradingAllowed = true;
double g_AccountHighBalance = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
Print("[MAEA] Initializing EA...");
trade.SetExpertMagicNumber(MagicNumber);
handleEMAHigh = iMA(_Symbol, PERIOD_CURRENT, EMAPeriod, EMAShift, MODE_EMA, PRICE_HIGH);
handleEMALow = iMA(_Symbol, PERIOD_CURRENT, EMAPeriod, EMAShift, MODE_EMA, PRICE_LOW);
handleD1EMAHigh = iMA(_Symbol, PERIOD_D1, EMAPeriod, EMAShift, MODE_EMA, PRICE_HIGH);
handleD1EMALow = iMA(_Symbol, PERIOD_D1, EMAPeriod, EMAShift, MODE_EMA, PRICE_LOW);
if(handleEMAHigh == INVALID_HANDLE || handleEMALow == INVALID_HANDLE ||
handleD1EMAHigh == INVALID_HANDLE || handleD1EMALow == INVALID_HANDLE) {
Print("[MAEA] Failed to create EMA handles");
return INIT_FAILED;
}
Print("[MAEA] Handles - EMAHigh: ", handleEMAHigh, ", EMALow: ", handleEMALow);
ArraySetAsSeries(g_EMAHighBuffer, true);
ArraySetAsSeries(g_EMALowBuffer, true);
ArraySetAsSeries(g_D1EMAHighBuffer, true);
ArraySetAsSeries(g_D1EMALowBuffer, true);
g_AccountHighBalance = AccountInfoDouble(ACCOUNT_BALANCE);
g_LastBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
Print("[MAEA] Initialization successful");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
Print("[MAEA] Deinitializing. Reason: ", reason);
if(handleEMAHigh != INVALID_HANDLE) IndicatorRelease(handleEMAHigh);
if(handleEMALow != INVALID_HANDLE) IndicatorRelease(handleEMALow);
if(handleD1EMAHigh != INVALID_HANDLE) IndicatorRelease(handleD1EMAHigh);
if(handleD1EMALow != INVALID_HANDLE) IndicatorRelease(handleD1EMALow);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime != g_LastBarTime) {
g_LastBarTime = currentBarTime;
CheckDrawdown();
OnNewBar();
}
ManageOpenPosition();
}
//+------------------------------------------------------------------+
//| New bar processing |
//+------------------------------------------------------------------+
void OnNewBar() {
if(HasOpenPosition()) {
CheckOppositeSignal();
return;
}
CheckBreakthroughSignal();
}
//+------------------------------------------------------------------+
//| Check breakthrough signal and open position |
//+------------------------------------------------------------------+
void CheckBreakthroughSignal() {
if(!CopyIndicatorData()) return;
double prevClose = iClose(_Symbol, PERIOD_CURRENT, 1);
double currClose = iClose(_Symbol, PERIOD_CURRENT, 0);
double emaHigh = g_EMAHighBuffer[0];
double emaLow = g_EMALowBuffer[0];
double zoneWidth = MathAbs(emaHigh - emaLow);
if(zoneWidth < MinZoneWidthPoints * _Point) return;
bool prevInsideZone = (prevClose <= emaHigh && prevClose >= emaLow);
if(!prevInsideZone) return;
bool buySignal = (currClose > emaHigh);
bool sellSignal = (currClose < emaLow);
if(!buySignal && !sellSignal) return;
if(buySignal && !AllFiltersPass(true)) return;
if(sellSignal && !AllFiltersPass(false)) return;
if(buySignal) {
OpenBuyPosition();
}
else if(sellSignal) {
OpenSellPosition();
}
}
//+------------------------------------------------------------------+
//| Check opposite signal and close position |
//+------------------------------------------------------------------+
void CheckOppositeSignal() {
if(!CopyIndicatorData()) return;
if(!HasOpenPosition()) return;
double currClose = iClose(_Symbol, PERIOD_CURRENT, 0);
double prevClose = iClose(_Symbol, PERIOD_CURRENT, 1);
double emaHigh = g_EMAHighBuffer[0];
double emaLow = g_EMALowBuffer[0];
bool buySignal = (prevClose <= emaHigh && prevClose >= emaLow && currClose > emaHigh);
bool sellSignal = (prevClose <= emaHigh && prevClose >= emaLow && currClose < emaLow);
if(!buySignal && !sellSignal) return;
ulong positionTicket = GetPositionTicket();
if(positionTicket == 0) return;
ENUM_POSITION_TYPE posType = GetPositionType(positionTicket);
if(posType == POSITION_TYPE_BUY && sellSignal) {
trade.PositionClose(positionTicket);
ResetPositionVariables();
Print("Buy position closed due to opposite sell signal");
}
else if(posType == POSITION_TYPE_SELL && buySignal) {
trade.PositionClose(positionTicket);
ResetPositionVariables();
Print("Sell position closed due to opposite buy signal");
}
}
//+------------------------------------------------------------------+
//| Manage open position (TP, SL, breakeven, trailing stop) |
//+------------------------------------------------------------------+
void ManageOpenPosition() {
if(!HasOpenPosition()) return;
ulong positionTicket = GetPositionTicket();
if(positionTicket == 0) return;
if(!PositionSelectByTicket(positionTicket)) return;
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double profit = PositionGetDouble(POSITION_PROFIT);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(currentTP > 0 && profit >= TakeProfitUSD) {
trade.PositionClose(positionTicket);
ResetPositionVariables();
Print("Position closed by Take Profit");
return;
}
double pointsProfit = 0;
double breakevenLevel = 0;
if(posType == POSITION_TYPE_BUY) {
pointsProfit = (currentPrice - openPrice) / _Point;
breakevenLevel = openPrice + BreakevenPoints * _Point;
}
else {
pointsProfit = (openPrice - currentPrice) / _Point;
breakevenLevel = openPrice - BreakevenPoints * _Point;
}
if(!g_BreakevenTriggered && pointsProfit >= BreakevenPoints) {
if(posType == POSITION_TYPE_BUY) {
trade.PositionModify(positionTicket, openPrice, currentTP);
}
else {
trade.PositionModify(positionTicket, openPrice, currentTP);
}
g_BreakevenTriggered = true;
Print("Breakeven triggered for position ", positionTicket);
}
if(g_BreakevenTriggered && TrailingStopPoints > 0) {
double trailDistance = TrailingStopPoints * _Point;
double newSL;
if(posType == POSITION_TYPE_BUY) {
newSL = currentPrice - trailDistance;
if(newSL > currentSL + _Point && newSL > openPrice) {
trade.PositionModify(positionTicket, newSL, currentTP);
}
}
else {
newSL = currentPrice + trailDistance;
if(newSL < currentSL - _Point && newSL < openPrice) {
trade.PositionModify(positionTicket, newSL, currentTP);
}
}
}
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
void OpenBuyPosition() {
if(!CopyIndicatorData()) return;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = g_EMALowBuffer[0];
double tp = CalculateTakeProfit(ask, sl, true);
if(!trade.Buy(LotSize, _Symbol, ask, sl, tp, "MAEA Buy")) {
int err = GetLastError();
Print("Buy order failed. Error: ", err);
}
else {
g_EntryPrice = ask;
g_BreakevenTriggered = false;
Print("Buy position opened at ", ask);
}
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
void OpenSellPosition() {
if(!CopyIndicatorData()) return;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = g_EMAHighBuffer[0];
double tp = CalculateTakeProfit(bid, sl, false);
if(!trade.Sell(LotSize, _Symbol, bid, sl, tp, "MAEA Sell")) {
int err = GetLastError();
Print("Sell order failed. Error: ", err);
}
else {
g_EntryPrice = bid;
g_BreakevenTriggered = false;
Print("Sell position opened at ", bid);
}
}
//+------------------------------------------------------------------+
//| Calculate take profit in price |
//+------------------------------------------------------------------+
double CalculateTakeProfit(double entryPrice, double sl, bool isBuy) {
double pointValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double profitPoints = TakeProfitUSD / (tickValue * LotSize / tickSize);
double profitPrice = profitPoints * pointValue;
if(isBuy) {
return entryPrice + profitPrice;
}
else {
return entryPrice - profitPrice;
}
}
//+------------------------------------------------------------------+
//| Copy indicator data |
//+------------------------------------------------------------------+
bool CopyIndicatorData() {
if(CopyBuffer(handleEMAHigh, 0, 0, 10, g_EMAHighBuffer) <= 0) return false;
if(CopyBuffer(handleEMALow, 0, 0, 10, g_EMALowBuffer) <= 0) return false;
if(UseMTFFilter) {
if(CopyBuffer(handleD1EMAHigh, 0, 0, 2, g_D1EMAHighBuffer) <= 0) return false;
if(CopyBuffer(handleD1EMALow, 0, 0, 2, g_D1EMALowBuffer) <= 0) return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check all filters |
//+------------------------------------------------------------------+
bool AllFiltersPass(bool isBuyDirection) {
if(!CheckVolumeFilter()) return false;
if(!CheckSpreadFilter()) return false;
if(!CheckDrawdownAllowed()) return false;
if(UseMTFFilter && !CheckMTFFilter(isBuyDirection)) return false;
if(UseNewsFilter && !CheckNewsFilter()) return false;
return true;
}
//+------------------------------------------------------------------+
//| Volume filter |
//+------------------------------------------------------------------+
bool CheckVolumeFilter() {
long currentVolume = iVolume(_Symbol, PERIOD_CURRENT, 0);
long avgVolume = 0;
for(int i = 1; i <= VolumePeriod; i++) {
avgVolume += iVolume(_Symbol, PERIOD_CURRENT, i);
}
avgVolume = avgVolume / VolumePeriod;
return (currentVolume > avgVolume);
}
//+------------------------------------------------------------------+
//| Spread filter |
//+------------------------------------------------------------------+
bool CheckSpreadFilter() {
long spread;
SymbolInfoInteger(_Symbol, SYMBOL_SPREAD, spread);
return (spread <= MaxSpread);
}
//+------------------------------------------------------------------+
//| MTF filter |
//+------------------------------------------------------------------+
bool CheckMTFFilter(bool isBuyDirection) {
double d1Close = iClose(_Symbol, PERIOD_D1, 0);
double d1EMAHigh = g_D1EMAHighBuffer[0];
double d1EMALow = g_D1EMALowBuffer[0];
if(d1Close > d1EMAHigh) {
return isBuyDirection;
}
else if(d1Close < d1EMALow) {
return !isBuyDirection;
}
else {
return false;
}
}
//+------------------------------------------------------------------+
//| News filter |
//+------------------------------------------------------------------+
bool CheckNewsFilter() {
datetime gmtTime = TimeGMT();
datetime thaiTime = gmtTime + 25200;
MqlDateTime timeStruct;
TimeToStruct(thaiTime, timeStruct);
string hoursArr[];
StringSplit(NewsAvoidHours, ',', hoursArr);
for(int i = 0; i < ArraySize(hoursArr); i++) {
string h = hoursArr[i];
StringTrimRight(h);
StringTrimLeft(h);
if(h == IntegerToString(timeStruct.hour)) {
return false;
}
}
string daysArr[];
StringSplit(NewsAvoidDays, ',', daysArr);
for(int i = 0; i < ArraySize(daysArr); i++) {
string d = daysArr[i];
StringTrimRight(d);
StringTrimLeft(d);
if(d == IntegerToString(timeStruct.day_of_week)) {
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check drawdown |
//+------------------------------------------------------------------+
void CheckDrawdown() {
double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
if(currentBalance > g_AccountHighBalance) {
g_AccountHighBalance = currentBalance;
}
if(currentBalance > 0 && g_AccountHighBalance > 0) {
double drawdownPercent = ((g_AccountHighBalance - currentBalance) / g_AccountHighBalance) * 100;
if(drawdownPercent >= MaxDrawdownPercent) {
g_TradingAllowed = false;
Print("Drawdown limit reached. Trading stopped.");
}
else {
g_TradingAllowed = true;
}
}
}
//+------------------------------------------------------------------+
//| Check if trading is allowed based on drawdown |
//+------------------------------------------------------------------+
bool CheckDrawdownAllowed() {
return g_TradingAllowed;
}
//+------------------------------------------------------------------+
//| Check if has open position |
//+------------------------------------------------------------------+
bool HasOpenPosition() {
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(PositionGetSymbol(i) == _Symbol) {
ulong magic = PositionGetInteger(POSITION_MAGIC);
if(magic == MagicNumber) {
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Get position ticket |
//+------------------------------------------------------------------+
ulong GetPositionTicket() {
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(PositionGetSymbol(i) == _Symbol) {
ulong ticket = PositionGetInteger(POSITION_TICKET);
ulong magic = PositionGetInteger(POSITION_MAGIC);
if(magic == MagicNumber) {
return ticket;
}
}
}
return 0;
}
//+------------------------------------------------------------------+
//| Get position type |
//+------------------------------------------------------------------+
ENUM_POSITION_TYPE GetPositionType(ulong ticket) {
if(PositionSelectByTicket(ticket)) {
return (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
return POSITION_TYPE_BUY;
}
//+------------------------------------------------------------------+
//| Reset position variables |
//+------------------------------------------------------------------+
void ResetPositionVariables() {
g_EntryPrice = 0;
g_BreakevenTriggered = false;
}
//+------------------------------------------------------------------+

109
MAEA_Indicator.mq5 Normal file
View File

@@ -0,0 +1,109 @@
//+------------------------------------------------------------------+
//| MAEA_Indicator.mq5 |
//| Moving Average EA |
//| Visual indicator for EMA zone breakout |
//+------------------------------------------------------------------+
#property copyright "MAEA"
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_label1 "EMA High"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrLightBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_label2 "EMA Low"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrOrange
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
#property indicator_label3 "EMA Zone"
#property indicator_type3 DRAW_FILLING
#property indicator_color3 clrYellow
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
input int EMAPeriod = 30;
input int EMAShift = 0;
int handleEMAHigh;
int handleEMALow;
double BufferEMAHigh[];
double BufferEMALow[];
double BufferZone[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit() {
ArraySetAsSeries(BufferEMAHigh, true);
ArraySetAsSeries(BufferEMALow, true);
ArraySetAsSeries(BufferZone, true);
SetIndexBuffer(0, BufferEMAHigh, INDICATOR_DATA);
SetIndexBuffer(1, BufferEMALow, INDICATOR_DATA);
SetIndexBuffer(2, BufferZone, INDICATOR_CALCULATIONS);
ArraySetAsSeries(BufferEMAHigh, true);
ArraySetAsSeries(BufferEMALow, true);
ArraySetAsSeries(BufferZone, true);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, EMAPeriod + EMAShift);
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, EMAPeriod + EMAShift);
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, EMAPeriod + EMAShift);
handleEMAHigh = iMA(_Symbol, PERIOD_CURRENT, EMAPeriod, EMAShift, MODE_EMA, PRICE_HIGH);
handleEMALow = iMA(_Symbol, PERIOD_CURRENT, EMAPeriod, EMAShift, MODE_EMA, PRICE_LOW);
if(handleEMAHigh == INVALID_HANDLE || handleEMALow == INVALID_HANDLE) {
Print("Failed to create EMA handles");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
IndicatorRelease(handleEMAHigh);
IndicatorRelease(handleEMALow);
}
//+------------------------------------------------------------------+
//| 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[]) {
if(rates_total < EMAPeriod + EMAShift) return 0;
int copied = CopyBuffer(handleEMAHigh, 0, 0, rates_total, BufferEMAHigh);
if(copied <= 0) return 0;
copied = CopyBuffer(handleEMALow, 0, 0, rates_total, BufferEMALow);
if(copied <= 0) return 0;
return rates_total;
}
//+------------------------------------------------------------------+

345
README.md
View File

@@ -1,345 +0,0 @@
# MAEA - Moving Average Expert Advisor
Advanced trend-following Expert Advisor for MetaTrader 4 with sophisticated filtering and risk management features.
## 📋 Table of Contents
- [Overview](#overview)
- [Features](#features)
- [Strategy Details](#strategy-details)
- [Installation](#installation)
- [Parameters](#parameters)
- [Usage](#usage)
- [Visual Indicators](#visual-indicators)
- [Risk Management](#risk-management)
- [Troubleshooting](#troubleshooting)
- [Disclaimer](#disclaimer)
## 🎯 Overview
MAEA is a sophisticated trading robot that uses Exponential Moving Averages (EMAs) with dynamic border lines to identify trend-following opportunities. The EA includes multiple filters to ensure high-quality trade entries and comprehensive risk management to protect your account.
**Repository:** https://git.moreminimore.com/kunthawat/MAEA
**Platform:** MetaTrader 4
**Language:** MQL4
**Timezone:** Thailand (UTC+7)
## ✨ Features
### Core Strategy
- **5 Visual Indicator Lines:** 3 EMA lines + 2 dynamic Border Lines
- **Breakthrough Signals:** Entry when price breaks through EMA High/Low
- **Pullback Signals:** Enhanced lot sizing after pullback detection
- **Dynamic Lot Sizing:** 0.01 or 0.02 lots based on market behavior
- **Single Order Management:** Prevents over-trading
### Advanced Filters
- **Volume Filter:** Trade only when volume exceeds 20-bar average
- **Spread Filter:** Avoid high spread periods (max 30 points)
- **Multiple Timeframe Filter:** D1 trend confirmation (optional)
- **News Filter:** Avoid specific hours/days (Thailand timezone, optional)
### Risk Management
- **Take Profit:** Target in USD (default $5)
- **Stop Loss:** At dynamic Border Lines
- **Breakeven:** Move SL to entry at 100 points profit
- **Trailing Stop:** Trail by 100 points after breakeven
- **Max Drawdown Protection:** Stop trading at 10% drawdown
## 📊 Strategy Details
### Indicator System
#### EMA Lines (3 Base Lines)
All EMAs use period 30 with different price sources:
1. **EMA High** (Light Blue) - EMA of High prices
2. **EMA Medium** (Yellow) - EMA of Close prices
3. **EMA Low** (Orange) - EMA of Low prices
#### Border Lines (2 Dynamic Lines)
Calculated based on the range between EMAs:
1. **High Border** (Purple) = EMA High + (EMA Medium - EMA Low)
2. **Low Border** (Purple) = EMA Low - (EMA Medium - EMA Low)
**Example Calculation:**
```
EMA High = 3500
EMA Medium = 3400
EMA Low = 3300
Range = EMA Medium - EMA Low = 3400 - 3300 = 100
High Border = 3500 + 100 = 3600
Low Border = 3300 - 100 = 3200
```
### Signal Types
#### 1. Breakthrough Signal
- **Buy Signal:** Close price breaks above EMA High
- **Sell Signal:** Close price breaks below EMA Low
- **Purpose:** Triggers order opening
#### 2. Pullback Signal
- **Buy Pullback:** Price moves down to hit any line, then closes above the line
- **Sell Pullback:** Price moves up to hit any line, then closes below the line
- **Purpose:** Increases lot size when breakthrough occurs in same direction
- **Tracking:** Separate for buy and sell directions
### Order Management
- **Single Order:** Only one order at a time
- **Dynamic Lot Sizing:**
- 0.01 lot (no pullback before breakthrough)
- 0.02 lot (pullback occurred before breakthrough)
- **Stop Loss:** At Border Lines (Low Border for buys, High Border for sells)
- **Take Profit:** Target in USD (default $5)
- **Breakeven:** Move SL to entry at X points profit (default 100)
- **Trailing Stop:** Trail by X points after breakeven (default 100)
## 🚀 Installation
1. **Download the EA:**
- Clone the repository: `git clone https://git.moreminimore.com/kunthawat/MAEA.git`
- Or download [`MAEA.mq4`](MAEA.mq4) directly
2. **Copy to MT4:**
- Navigate to your MT4 data folder
- Go to `MQL4/Indicators` or `MQL4/Experts`
- Copy [`MAEA.mq4`](MAEA.mq4) to that folder
3. **Compile in MetaEditor:**
- Open MetaEditor (press F4 in MT4)
- Open [`MAEA.mq4`](MAEA.mq4)
- Press F7 to compile
- Ensure no compilation errors
4. **Attach to Chart:**
- Open MT4
- Drag MAEA from Navigator to your chart
- Recommended timeframe: H1
- Configure parameters as needed
5. **Enable Auto Trading:**
- Click "Auto Trading" button in MT4 toolbar
- Ensure EA is allowed to trade in Tools → Options → Expert Advisors
## ⚙️ Parameters
### EMA Settings
| Parameter | Default | Description |
|-----------|---------|-------------|
| `EMAPeriod` | 30 | EMA period for all lines |
### Lot Settings
| Parameter | Default | Description |
|-----------|---------|-------------|
| `LotSizeNormal` | 0.01 | Lot size without pullback |
| `LotSizePullback` | 0.02 | Lot size with pullback |
### Risk Management
| Parameter | Default | Description |
|-----------|---------|-------------|
| `TakeProfitUSD` | 5.0 | Take profit target in USD |
| `BreakevenPoints` | 100 | Points to trigger breakeven |
| `TrailingStopPoints` | 100 | Trailing stop distance |
| `MaxDrawdownPercent` | 10.0 | Maximum drawdown percentage |
### Filters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `MaxSpread` | 30 | Maximum allowed spread in points |
| `VolumePeriod` | 20 | Period for volume average |
| `UseMTFFilter` | true | Enable MTF filter |
| `UseNewsFilter` | true | Enable news filter |
| `NewsAvoidHours` | "14,15,20,21" | Hours to avoid (Thailand time) |
| `NewsAvoidDays` | "1,5" | Days to avoid (Monday=1, Friday=5) |
### General
| Parameter | Default | Description |
|-----------|---------|-------------|
| `MagicNumber` | 12345 | EA unique identifier |
## 📖 Usage
### Basic Setup
1. Attach MAEA to an H1 chart
2. Adjust parameters according to your risk tolerance
3. Enable Auto Trading
4. Monitor the EA's performance
### Recommended Timeframes
- **Trading Timeframe:** H1 (recommended)
- **Filter Timeframe:** D1 (for MTF filter)
### Currency Pairs
- Works on all major currency pairs
- Best performance on trending pairs (EURUSD, GBPUSD, USDJPY)
### Account Types
- Compatible with any MT4 account type
- Ensure sufficient margin for lot sizes
## 🎨 Visual Indicators
The EA displays 5 lines on your chart:
| Line | Color | Style | Description |
|------|-------|-------|-------------|
| EMA High | Light Blue | Solid | EMA of High prices |
| EMA Medium | Yellow | Solid | EMA of Close prices |
| EMA Low | Orange | Solid | EMA of Low prices |
| High Border | Purple | Dashed | Upper dynamic border |
| Low Border | Purple | Dashed | Lower dynamic border |
### Reading the Indicators
- **Price above all lines:** Strong uptrend
- **Price below all lines:** Strong downtrend
- **Price between lines:** Consolidation/ranging
- **Border Lines:** Dynamic support/resistance levels
## 🛡️ Risk Management
### Take Profit
- Closes order when profit reaches target amount in USD
- Automatically calculated based on lot size and symbol
### Stop Loss
- **Buy Orders:** SL at Low Border Line
- **Sell Orders:** SL at High Border Line
- Moves dynamically as Border Lines update
### Breakeven
- Triggered when profit reaches specified points (default 100)
- Moves Stop Loss to breakeven (entry price)
- Protects profits while allowing room for trend continuation
### Trailing Stop
- Activates after breakeven is reached
- Trails Stop Loss by specified points (default 100)
- Locks in profits as trend continues
### Drawdown Protection
- Calculates drawdown percentage from peak equity
- Stops trading if drawdown exceeds limit (default 10%)
- Resumes trading when drawdown is below limit
## 🔧 Troubleshooting
### EA Not Opening Orders
**Problem:** EA is attached but not opening any orders
**Solutions:**
1. Check if Auto Trading is enabled (green button in MT4 toolbar)
2. Verify EA is allowed in Tools → Options → Expert Advisors
3. Check if filters are too restrictive:
- Reduce `MaxSpread` if spread is too high
- Disable `UseMTFFilter` temporarily
- Disable `UseNewsFilter` temporarily
4. Verify account has sufficient margin
5. Check Experts tab for error messages
### Compilation Errors
**Problem:** EA fails to compile in MetaEditor
**Solutions:**
1. Ensure you're using MT4 (not MT5)
2. Check for missing brackets or semicolons
3. Verify all function names are spelled correctly
4. Update MetaEditor to latest version
### Incorrect Indicator Display
**Problem:** Lines not displaying correctly on chart
**Solutions:**
1. Ensure sufficient historical data (at least 50 bars)
2. Check if `EMAPeriod` is too high for available data
3. Refresh chart (right-click → Refresh)
4. Reattach EA to chart
### Orders Closing Prematurely
**Problem:** Orders closing too early or not reaching TP
**Solutions:**
1. Check if `TakeProfitUSD` is too low
2. Verify `MaxDrawdownPercent` is not too restrictive
3. Check if spread is causing SL hits
4. Review trade logs for closure reasons
### Drawdown Protection Triggering
**Problem:** EA stops trading due to drawdown
**Solutions:**
1. Increase `MaxDrawdownPercent` if too conservative
2. Wait for equity to recover above threshold
3. Review trading strategy and risk settings
4. Consider reducing lot sizes
### Timezone Issues
**Problem:** News filter not working at expected times
**Solutions:**
1. Verify your MT4 server timezone
2. Adjust `NewsAvoidHours` accordingly
3. Thailand timezone is UTC+7
4. Test with different hour values
### Performance Issues
**Problem:** EA slow or causing MT4 lag
**Solutions:**
1. Reduce `EMAPeriod` for faster calculations
2. Disable MTF filter if not needed
3. Close unnecessary charts and indicators
4. Check MT4 and computer performance
## 📝 Best Practices
1. **Start Small:** Begin with minimum lot sizes and conservative settings
2. **Test Thoroughly:** Use demo account before live trading
3. **Monitor Regularly:** Check EA performance and adjust as needed
4. **Keep Records:** Track trades and analyze performance
5. **Stay Informed:** Be aware of market conditions and news events
6. **Use Stop Loss:** Never disable risk management features
7. **Diversify:** Don't rely on a single EA or strategy
## ⚠️ Disclaimer
**IMPORTANT NOTICE:**
Trading Forex and CFDs involves significant risk of loss and may not be suitable for all investors. MAEA is provided as-is without any warranty or guarantee of performance.
- Past performance is not indicative of future results
- Always trade with money you can afford to lose
- Test thoroughly on demo accounts before live trading
- The authors are not responsible for any financial losses
- Use at your own risk
**By using MAEA, you acknowledge that:**
- You understand the risks involved in trading
- You are solely responsible for your trading decisions
- You will not hold the authors liable for any losses
- You have read and understood this disclaimer
## 📞 Support
For issues, questions, or contributions:
- **Repository:** https://git.moreminimore.com/kunthawat/MAEA
- **Issues:** Report bugs or request features via repository issues
## 📄 License
This project is provided for educational and research purposes. Use responsibly and in accordance with your broker's terms of service.
---
**Version:** 1.00
**Last Updated:** 2026-01-02
**Timezone:** Thailand (UTC+7)

13
opencode.jsonc Normal file
View File

@@ -0,0 +1,13 @@
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"mql5_help": {
"type": "local",
"command": [
"npx",
"-y",
"github:caoshuo594/mql5-help-mcp"
]
}
}
}

View File

@@ -2,58 +2,44 @@
## Project Overview ## Project Overview
- **Name**: MAEA - **Name**: MAEA
- **Type**: MQL4 Expert Advisor for MetaTrader 4 - **Type**: MQL5 Expert Advisor for MetaTrader 5
- **Strategy**: Advanced trend-following with EMA-based signals, multiple filters, and risk management - **Strategy**: Advanced trend-following with EMA-based signals, multiple filters, and risk management
- **Repository**: https://git.moreminimore.com/kunthawat/MAEA - **Repository**: https://git.moreminimore.com/kunthawat/MAEA
- **Timezone**: Thailand (UTC+7) - **Timezone**: Thailand (UTC+7)
## Strategy Details ## Strategy Details
### 1. EMA Lines (3 Base Lines) ### 1. EMA Lines (2 Base Lines)
All EMAs use period 30 with different price sources: All EMAs use period 30 with different price sources:
- **EMA High**: EMA of High prices - Light Blue color - **EMA High**: EMA of High prices - Light Blue color
- **EMA Medium**: EMA of Close prices - Yellow color
- **EMA Low**: EMA of Low prices - Orange color - **EMA Low**: EMA of Low prices - Orange color
### 2. Border Lines (2 Dynamic Lines) ### 2. EMA Zone (Visual Area)
Calculated based on the range between EMAs: - **Zone Definition**: The area between EMA High and EMA Low
- **High Border Line**: EMA High + (EMA Medium - EMA Low) - Purple color - **Visual**: Light yellow transparent fill between EMA High and EMA Low
- **Low Border Line**: EMA Low - (EMA Medium - EMA Low) - Purple color
**Example Calculation:** ### 3. Signal Type
```
EMA High = 3500
EMA Medium = 3400
EMA Low = 3300
Range = EMA Medium - EMA Low = 3400 - 3300 = 100
High Border = 3500 + 100 = 3600
Low Border = 3300 - 100 = 3200
```
### 3. Signal Types
#### 3.1 Breakthrough Signal #### 3.1 Breakthrough Signal
- **Buy Signal**: Close price breaks above EMA High - **Buy Signal**: Close price breaks above EMA High (zone breakout upward)
- **Sell Signal**: Close price breaks below EMA Low - **Sell Signal**: Close price breaks below EMA Low (zone breakout downward)
- **Purpose**: Triggers order opening - **Purpose**: Triggers position opening/closing
- **Logic**:
- Previous close must be inside zone (between EMA High and EMA Low)
- Current close must be outside zone
- For buy: previous_close <= EMA_High AND current_close > EMA_High
- For sell: previous_close >= EMA_Low AND current_close < EMA_Low
#### 3.2 Pullback Signal #### 3.2 Opposite Signal Close
- **Definition**: Price hits a line and closes on the opposite side - **Close Buy Position**: When sell signal occurs (price breaks below EMA Low)
- **Buy Pullback**: Price moves down to hit any line, then closes above the line - **Close Sell Position**: When buy signal occurs (price breaks above EMA High)
- **Sell Pullback**: Price moves up to hit any line, then closes below the line - **Priority**: Opposite signal closes existing position immediately before opening new one
- **Purpose**: Increases lot size when breakthrough occurs in the same direction
- **Tracking**: Separate tracking for buy and sell directions, resets when order opens
- **Lot Size Impact**:
- No pullback before breakthrough = 0.01 lot
- Pullback occurred before breakthrough = 0.02 lot
### 4. Order Opening Logic ### 4. Order Opening Logic
- **Only one order at a time** - **Only one position at a time**
- **Lot Size**: - **Lot Size**: Fixed 0.01 lot for all trades
- 0.01 lot if no pullback occurred before breakthrough
- 0.02 lot if at least one pullback occurred before breakthrough in the same direction
- **Trigger**: Breakthrough signal only - **Trigger**: Breakthrough signal only
- **Minimum Zone Width**: Zone must be at least 100 points before trading
- **Filters Applied**: - **Filters Applied**:
- Volume filter must pass - Volume filter must pass
- Spread filter must pass - Spread filter must pass
@@ -67,8 +53,8 @@ Low Border = 3300 - 100 = 3200
- Closes order when profit reaches target amount - Closes order when profit reaches target amount
#### 5.2 Stop Loss #### 5.2 Stop Loss
- **Buy Orders**: SL at Low Border Line - **Buy Orders**: SL at EMA Low
- **Sell Orders**: SL at High Border Line - **Sell Orders**: SL at EMA High
#### 5.3 Breakeven #### 5.3 Breakeven
- Triggered when profit reaches specified number of points (e.g., 100 points) - Triggered when profit reaches specified number of points (e.g., 100 points)
@@ -90,10 +76,10 @@ Low Border = 3300 - 100 = 3200
- **Timeframes**: H1 (trading) and D1 (filter) - **Timeframes**: H1 (trading) and D1 (filter)
- **Status**: Optional feature (can be turned on/off) - **Status**: Optional feature (can be turned on/off)
- **D1 Filter Logic**: - **D1 Filter Logic**:
- If D1 close > D1 EMA High: Only buy orders allowed - If D1 close > D1 EMA High: Only buy positions allowed (bullish trend)
- If D1 close < D1 EMA Low: Only sell orders allowed - If D1 close < D1 EMA Low: Only sell positions allowed (bearish trend)
- If D1 close between D1 EMA High and D1 EMA Low: No orders allowed - If D1 close between D1 EMA High and D1 EMA Low: No positions allowed (no clear trend)
- **Behavior**: Order opens immediately when filter condition is met - **Behavior**: Position opens immediately when filter condition is met
### 8. Spread Filter ### 8. Spread Filter
- **Purpose**: Avoid trading during high spread periods - **Purpose**: Avoid trading during high spread periods
@@ -115,80 +101,83 @@ Low Border = 3300 - 100 = 3200
```mermaid ```mermaid
graph TD graph TD
A[Start New Bar] --> B[Calculate EMAs] A[Start New Bar] --> B[Calculate EMA High/Low]
B --> C[Calculate Border Lines] B --> C[Fill Zone Between EMAs]
C --> D[Check for Open Orders] C --> D[Check for Open Positions]
D -->|Has Open Order| E[Manage Open Order] D -->|Has Open Position| E[Check Opposite Signal]
D -->|No Open Order| F[Check Pullback Signals] D -->|No Open Position| F[Check Breakthrough Signals]
E --> E1[Check Take Profit] E --> E1{Opposite Signal?}
E1 -->|TP Reached| E2[Close Order] E1 -->|Buy open, Sell signal| E2[Close Buy Position]
E1 -->|TP Not Reached| E3[Check Breakeven] E1 -->|Sell open, Buy signal| E3[Close Sell Position]
E3 -->|Breakeven Reached| E4[Move SL to Entry] E1 -->|No opposite signal| E4[Manage Position Risks]
E3 -->|Breakeven Not Reached| E5[Check Stop Loss] E2 --> A
E5 -->|SL Hit| E2 E3 --> A
E5 -->|SL Not Hit| A
F --> F1[Close Below EMA High] E4 --> E5[Check Take Profit]
F1 -->|Yes| F2[Set Pullback Flag] E5 -->|TP Reached| E6[Close Position]
F1 -->|No| F3[Close Below EMA Medium] E5 -->|TP Not Reached| E7[Check Breakeven]
F3 -->|Yes| F2 E7 -->|Breakeven Reached| E8[Move SL to Entry]
F3 -->|No| F4[Close Below EMA Low] E7 -->|Breakeven Not Reached| E9[Check SL Hit]
F4 -->|Yes| F2 E9 -->|SL Hit| E6
F4 -->|No| F5[Check Breakthrough Signals] E9 -->|SL Not Hit| A
E6 --> A
F2 --> F5 F --> F1{Previous Close Inside Zone?}
F5 --> F6[Close Above EMA High] F1 -->|No| A
F6 -->|Yes| F7[Open Buy Order] F1 -->|Yes| F2{Zone Width >= 100 points?}
F6 -->|No| F8[Close Below EMA Low] F2 -->|No| A
F8 -->|Yes| F9[Open Sell Order] F2 -->|Yes| F3{Current Close Direction}
F8 -->|No| A F3 -->|Close > EMA High| F4[Check Filters]
F3 -->|Close < EMA Low| F5[Check Filters]
F3 -->|Still Inside| A
F7 --> F10[Set Lot Size] F4 --> F6{Volume OK? Spread OK? MTF OK? News OK?}
F10 -->|Pullback| F11[0.02 Lot] F5 --> F6
F10 -->|No Pullback| F12[0.01 Lot] F6 -->|All Pass| F7[Open Buy Position]
F11 --> F13[Set SL at Low Border] F6 -->|Any Fail| A
F12 --> F13
F13 --> F14[Set TP based on USD Target]
F14 --> F15[Reset Pullback Flag]
F15 --> A
F9 --> F16[Set Lot Size] F7 --> F8[Set SL at EMA Low]
F16 -->|Pullback| F17[0.02 Lot] F8 --> F9[Set TP based on USD Target]
F16 -->|No Pullback| F18[0.01 Lot] F9 --> A
F17 --> F19[Set SL at High Border]
F18 --> F19
F19 --> F20[Set TP based on USD Target]
F20 --> F21[Reset Pullback Flag]
F21 --> A
E2 --> F15 F5 --> F10{Volume OK? Spread OK? MTF OK? News OK?}
F10 -->|All Pass| F11[Open Sell Position]
F10 -->|Any Fail| A
F11 --> F12[Set SL at EMA High]
F12 --> F13[Set TP based on USD Target]
F13 --> A
``` ```
## Implementation Steps ## Implementation Steps
### Phase 1: Project Setup & Git Configuration ### Phase 1: Project Setup & Git Configuration
1. Create MQL4 project structure 1. Create MQL5 project structure
2. Initialize Git repository 2. Initialize Git repository
3. Configure remote to Gitea server (https://git.moreminimore.com/kunthawat/MAEA) 3. Configure remote to Gitea server (https://git.moreminimore.com/kunthawat/MAEA)
### Phase 2: Core EA Structure ### Phase 2: Core EA Structure
4. Create [`MAEA.mq4`](MAEA.mq4) with basic EA framework 4. Create [`MAEA.mq5`](MAEA.mq5) with basic EA framework
5. Define all input parameters (EMA period, lot sizes, TP, breakeven, trailing stop, filters, etc.) 5. Define all input parameters (EMA period, lot size, TP, breakeven, trailing stop, filters, etc.)
6. Set up indicator buffers for 5 visual lines 6. Set up indicator buffers for 2 EMA lines + zone fill (3 buffers total)
7. Initialize global variables for state tracking 7. Initialize global variables for state tracking
### Phase 3: Indicator Calculations ### Phase 3: Indicator Calculations
8. Implement EMA calculations for High, Medium, Low (period 30) 8. Implement EMA calculations for High and Low (period 30)
9. Implement Border Line calculations (High Border = High + Range, Low Border = Low - Range) 9. Implement zone fill between EMA High and EMA Low (transparent light yellow)
10. Add visual indicators with correct colors (Light Blue, Yellow, Orange, Purple) 10. Add visual indicators with correct colors (Light Blue for EMA High, Orange for EMA Low)
11. Implement Volume average calculation (20-bar average) 11. Implement Volume average calculation (20-bar average)
### Phase 4: Signal Detection ### Phase 4: Signal Detection
12. Implement breakthrough signal detection (price breaks High/Low EMA) 12. Implement breakthrough signal detection
13. Implement pullback signal detection (price hits line and closes on opposite side) - Check if previous close was inside zone
14. Implement separate pullback tracking for buy and sell directions - Check if current close broke above EMA High or below EMA Low
15. Implement pullback flag reset logic after order opens 13. Implement opposite signal detection and position closing
- If buy position open and sell signal occurs: close buy
- If sell position open and buy signal occurs: close sell
14. Implement minimum zone width check (100 points)
15. Implement single position check
### Phase 5: Multiple Timeframe Filter ### Phase 5: Multiple Timeframe Filter
16. Implement D1 EMA calculations for MTF filter 16. Implement D1 EMA calculations for MTF filter
@@ -202,13 +191,15 @@ graph TD
22. Add enable/disable toggles for news filter 22. Add enable/disable toggles for news filter
### Phase 7: Order Management ### Phase 7: Order Management
23. Implement order opening logic with all filter checks 23. Implement position opening logic with all filter checks
24. Implement dynamic lot sizing (0.01 no pullback, 0.02 with pullback) 24. Implement fixed lot sizing (0.01 lot)
25. Implement Stop Loss placement at Border Lines 25. Implement Stop Loss placement at opposite EMA
- Buy: SL at EMA Low
- Sell: SL at EMA High
26. Implement Take Profit calculation (convert USD target to pips) 26. Implement Take Profit calculation (convert USD target to pips)
27. Implement Breakeven logic (move SL to entry at X points) 27. Implement Breakeven logic (move SL to entry at X points)
28. Implement Trailing Stop logic (trail by X points after breakeven) 28. Implement Trailing Stop logic (trail by X points after breakeven)
29. Implement single order restriction 29. Implement single position restriction (use PositionsTotal())
### Phase 8: Risk Management ### Phase 8: Risk Management
30. Implement max drawdown calculation 30. Implement max drawdown calculation
@@ -216,20 +207,24 @@ graph TD
32. Implement trading resume logic when drawdown is below limit 32. Implement trading resume logic when drawdown is below limit
### Phase 9: Order Monitoring & Management ### Phase 9: Order Monitoring & Management
33. Implement Take Profit checking on each tick 33. Implement opposite signal checking on each tick
34. Implement Breakeven checking and SL modification 34. If opposite signal detected, close existing position immediately
35. Implement Trailing Stop checking and SL modification 35. Implement Take Profit checking on each tick
36. Implement Stop Loss checking 36. Implement Breakeven checking and SL modification
37. Implement order closure logic 37. Implement Trailing Stop checking and SL modification
38. Implement Stop Loss checking
39. Implement position closure logic
### Phase 10: Testing & Validation ### Phase 10: Testing & Validation
38. Test all EMA and Border Line calculations 38. Test EMA High and Low calculations
39. Test breakthrough and pullback signal detection 39. Test zone fill visualization (transparent yellow)
40. Test all filters (volume, spread, MTF, news) 40. Test breakthrough signal detection
41. Test order opening with correct lot sizes - Verify breakout requires previous close inside zone
42. Test TP, SL, breakeven, and trailing stop 41. Test all filters (volume, spread, MTF, news)
43. Test drawdown protection 42. Test position opening with fixed 0.01 lot
44. Test visual indicators display 43. Test TP, SL (at opposite EMA), breakeven, and trailing stop
44. Test drawdown protection
45. Test visual indicators display
### Phase 11: Documentation & Deployment ### Phase 11: Documentation & Deployment
45. Create comprehensive [`README.md`](README.md) with strategy documentation 45. Create comprehensive [`README.md`](README.md) with strategy documentation
@@ -243,15 +238,15 @@ graph TD
| Parameter | Description | Default Value | | Parameter | Description | Default Value |
|-----------|-------------|---------------| |-----------|-------------|---------------|
| `EMAPeriod` | EMA period for all lines | 30 | | `EMAPeriod` | EMA period for both lines | 30 |
| `LotSizeNormal` | Lot size without pullback | 0.01 | | `LotSize` | Fixed lot size | 0.01 |
| `LotSizePullback` | Lot size with pullback | 0.02 |
| `TakeProfitUSD` | Take profit target in USD | 5.0 | | `TakeProfitUSD` | Take profit target in USD | 5.0 |
| `BreakevenPoints` | Points to trigger breakeven | 100 | | `BreakevenPoints` | Points to trigger breakeven | 100 |
| `TrailingStopPoints` | Points for trailing stop distance | 100 | | `TrailingStopPoints` | Points for trailing stop distance | 100 |
| `MagicNumber` | EA unique identifier | 12345 | | `MagicNumber` | EA unique identifier | 12345 |
| `MaxSpread` | Maximum allowed spread in points | 30 | | `MaxSpread` | Maximum allowed spread in points | 30 |
| `VolumePeriod` | Period for volume average calculation | 20 | | `VolumePeriod` | Period for volume average calculation | 20 |
| `MinZoneWidthPoints` | Minimum zone width to trade (points) | 100 |
| `MaxDrawdownPercent` | Maximum drawdown percentage | 10.0 | | `MaxDrawdownPercent` | Maximum drawdown percentage | 10.0 |
| `UseMTFFilter` | Enable/disable MTF filter | true | | `UseMTFFilter` | Enable/disable MTF filter | true |
| `UseNewsFilter` | Enable/disable news filter | true | | `UseNewsFilter` | Enable/disable news filter | true |
@@ -263,61 +258,73 @@ graph TD
| Line | Color | Description | | Line | Color | Description |
|------|-------|-------------| |------|-------|-------------|
| EMA High | Light Blue (clrLightBlue) | EMA of High prices | | EMA High | Light Blue (clrLightBlue) | EMA of High prices |
| EMA Medium | Yellow (clrYellow) | EMA of Close prices |
| EMA Low | Orange (clrOrange) | EMA of Low prices | | EMA Low | Orange (clrOrange) | EMA of Low prices |
| High Border | Purple (clrPurple) | Upper dynamic border | | Zone Fill | Light Yellow (transparent) | Area between EMA High and EMA Low |
| Low Border | Purple (clrPurple) | Lower dynamic border |
## Key Considerations ## Key Considerations
1. **Pullback Detection**: Track price hitting lines and closing on opposite side separately for buy/sell 1. **Breakthrough Detection**: Previous close must be inside zone, current close outside zone
2. **Pullback Reset**: Reset pullback flag immediately after opening an order 2. **Opposite Signal Close**: Close existing position when opposite breakthrough signal occurs
3. **Single Order**: Only one order open at any time 3. **Minimum Zone Width**: Zone must be at least 100 points wide before trading
4. **Dynamic SL**: Stop Loss moves with Border Lines as they update 4. **Single Position**: Only one position open at any time (MT5 uses positions, not orders)
5. **Breakeven**: Only moves SL to entry price, not to profit 5. **SL at Opposite EMA**: Buy SL at EMA Low, Sell SL at EMA High
6. **TP Calculation**: Convert USD target to pips based on lot size and symbol 6. **Fixed Lot Size**: Always 0.01 lot regardless of market conditions
7. **Volume Filter**: Only trade when current volume exceeds 20-bar average 7. **Breakeven**: Only moves SL to entry price, not to profit
8. **MTF Filter**: D1 timeframe acts as trend filter, H1 for entry signals 8. **TP Calculation**: Convert USD target to pips based on lot size and symbol
9. **Spread Filter**: Avoid high spread periods 9. **Volume Filter**: Only trade when current volume exceeds 20-bar average
10. **Timezone**: All time-based filters use Thailand timezone (UTC+7) 10. **MTF Filter**: D1 price position relative to zone determines allowed direction
11. **Trailing Stop**: Activates after breakeven, trails by specified points 11. **Spread Filter**: Avoid high spread periods
12. **Drawdown Protection**: Stops trading if max drawdown exceeded 12. **Timezone**: All time-based filters use Thailand timezone (UTC+7)
13. **Trailing Stop**: Activates after breakeven, trails by specified points
14. **Drawdown Protection**: Stops trading if max drawdown exceeded
15. **Zone Visualization**: Light yellow transparent fill between EMA High and EMA Low
## Technical Specifications ## Technical Specifications
- **Platform**: MetaTrader 4 - **Platform**: MetaTrader 5
- **Language**: MQL4 - **Language**: MQL5
- **Trading Timeframe**: H1 (recommended) - **Trading Timeframe**: H1 (recommended)
- **Filter Timeframe**: D1 (for MTF filter) - **Filter Timeframe**: D1 (for MTF filter)
- **Currency Pairs**: All pairs (user-selectable) - **Currency Pairs**: All pairs (user-selectable)
- **Account Types**: Any MT4 account type - **Account Types**: Any MT5 account type
- **Server Timezone**: Thailand (UTC+7) - **Server Timezone**: Thailand (UTC+7)
## Testing Checklist ## Testing Checklist
### Core Strategy ### Core Strategy
- [ ] EMA calculations verify correctly (High, Medium, Low) - [ ] EMA calculations verify correctly (High and Low)
- [ ] Border Line calculations verify correctly - [ ] Zone fill displays correctly (light yellow, transparent)
- [ ] Zone width calculation verify correctly (in points)
- [ ] Minimum zone width filter works (100 points minimum)
- [ ] Breakthrough signals trigger correctly - [ ] Breakthrough signals trigger correctly
- [ ] Pullback signals detect correctly (buy and sell separately) - [ ] Previous close inside zone check
- [ ] Pullback flag resets after order opens - [ ] Buy signal: close > EMA High
- [ ] Lot sizes apply correctly (0.01 vs 0.02) - [ ] Sell signal: close < EMA Low
- [ ] Opposite signal detection works
- [ ] Buy position closes when sell signal occurs
- [ ] Sell position closes when buy signal occurs
### Filters ### Filters
- [ ] Volume filter works (20-bar average, current > average) - [ ] Volume filter works (20-bar average, current > average)
- [ ] Spread filter prevents high spread trades - [ ] Spread filter prevents high spread trades
- [ ] MTF filter works correctly (D1 > High = buy only, D1 < Low = sell only, between = no trade) - [ ] MTF filter works correctly
- [ ] D1 close > EMA High: buy only
- [ ] D1 close < EMA Low: sell only
- [ ] D1 close between: no trade
- [ ] MTF filter can be enabled/disabled - [ ] MTF filter can be enabled/disabled
- [ ] Min zone width filter works (100 points minimum)
- [ ] News filter avoids specified times (Thailand timezone) - [ ] News filter avoids specified times (Thailand timezone)
- [ ] News filter can be enabled/disabled - [ ] News filter can be enabled/disabled
### Order Management ### Order Management
- [ ] Stop Loss places at correct Border Lines - [ ] Stop Loss places at opposite EMA (Buy: EMA Low, Sell: EMA High)
- [ ] Take Profit closes at correct USD amount - [ ] Take Profit closes at correct USD amount
- [ ] Breakeven triggers at correct points - [ ] Breakeven triggers at correct points
- [ ] Trailing stop activates after breakeven - [ ] Trailing stop activates after breakeven
- [ ] Trailing stop trails by correct distance - [ ] Trailing stop trails by correct distance
- [ ] Only one order opens at a time - [ ] Opposite signal closes existing position immediately
- [ ] Only one position opens at a time
- [ ] Fixed lot size always 0.01
### Risk Management ### Risk Management
- [ ] Max drawdown protection works - [ ] Max drawdown protection works
@@ -332,11 +339,15 @@ graph TD
## Notes ## Notes
- The strategy uses 5 visual lines on the chart - The strategy uses 2 EMA lines with a filled zone between them
- Pullback tracking is separate for buy and sell directions - No pullback tracking or dynamic lot sizing - simplified approach
- Border Lines expand the range beyond the EMAs for wider stops - Fixed lot size: 0.01 for all trades
- Positions close when opposite signal occurs (reversal protection)
- Minimum zone width of 100 points ensures meaningful setups
- The strategy is trend-following and works best in trending markets - The strategy is trend-following and works best in trending markets
- Breakthrough signals require price to be inside zone before breaking out
- Multiple filters ensure quality trade entries - Multiple filters ensure quality trade entries
- All time-based calculations use Thailand timezone (UTC+7) - All time-based calculations use Thailand timezone (UTC+7)
- MTF filter provides higher timeframe trend confirmation - MTF filter matches price position relative to D1 zone
- Risk management features protect account from excessive losses - Risk management features protect account from excessive losses
- Zone fill uses light yellow color with transparency for better visibility

View File

@@ -1,39 +1,37 @@
# MAEA Project Summary # MAEA Project Summary
## Project Overview ## Project Overview
**MAEA (Moving Average Expert Advisor)** - An advanced trend-following trading robot for MetaTrader 4 with sophisticated filtering and risk management features. **MAEA (Moving Average Expert Advisor)** - An advanced trend-following trading robot for MetaTrader 5 with sophisticated filtering and risk management features.
**Repository:** https://git.moreminimore.com/kunthawat/MAEA **Repository:** https://git.moreminimore.com/kunthawat/MAEA
**Timezone:** Thailand (UTC+7) **Timezone:** Thailand (UTC+7)
## Core Strategy ## Core Strategy
### Indicator System (5 Visual Lines) ### Indicator System (2 EMA Lines + Zone)
1. **EMA High** (Light Blue) - EMA of High prices, period 30 1. **EMA High** (Light Blue) - EMA of High prices, period 30
2. **EMA Medium** (Yellow) - EMA of Close prices, period 30 2. **EMA Low** (Orange) - EMA of Low prices, period 30
3. **EMA Low** (Orange) - EMA of Low prices, period 30 3. **Zone Fill** (Light Yellow, transparent) - Area between EMA High and EMA Low
4. **High Border** (Purple) - EMA High + (EMA Medium - EMA Low)
5. **Low Border** (Purple) - EMA Low - (EMA Medium - EMA Low)
### Signal Types ### Signal Types
#### 1. Breakthrough Signal #### 1. Breakthrough Signal
- **Buy:** Close price breaks above EMA High - **Buy:** Close price breaks above EMA High (must have previous close inside zone)
- **Sell:** Close price breaks below EMA Low - **Sell:** Close price breaks below EMA Low (must have previous close inside zone)
- **Purpose:** Triggers order opening - **Purpose:** Triggers position opening
- **Verification:** Previous bar close must be inside zone between EMA High and EMA Low
#### 2. Pullback Signal #### 2. Opposite Signal Close
- **Buy Pullback:** Price moves down to hit any line, then closes above the line - **Close Buy:** When sell signal occurs (price breaks below EMA Low)
- **Sell Pullback:** Price moves up to hit any line, then closes below the line - **Close Sell:** When buy signal occurs (price breaks above EMA High)
- **Purpose:** Increases lot size when breakthrough occurs in same direction - **Immediate Action:** Position closes before checking for new trade
- **Tracking:** Separate for buy and sell directions
### Order Management ### Order Management
- **Single Order:** Only one order at a time - **Single Position:** Only one position open at a time (MT5 uses positions, not orders)
- **Dynamic Lot Sizing:** - **Fixed Lot Size:** 0.01 lot for all trades
- 0.01 lot (no pullback before breakthrough) - **Stop Loss:** At opposite EMA (Buy: EMA Low, Sell: EMA High)
- 0.02 lot (pullback occurred before breakthrough) - **Reverse Protection:** Close position when opposite signal occurs
- **Stop Loss:** At Border Lines (Low Border for buys, High Border for sells) - **Min Zone Width:** Zone must be at least 100 points to trade
- **Take Profit:** Target in USD (default $5) - **Take Profit:** Target in USD (default $5)
- **Breakeven:** Move SL to entry at X points profit (default 100) - **Breakeven:** Move SL to entry at X points profit (default 100)
- **Trailing Stop:** Trail by X points after breakeven (default 100) - **Trailing Stop:** Trail by X points after breakeven (default 100)
@@ -42,8 +40,9 @@
### 1. Volume Filter ### 1. Volume Filter
- Calculate 20-bar volume average - Calculate 20-bar volume average
- Trade only when current volume > average - Trade only when current volume > average
- Ensures sufficient market activity - Ensures sufficient market activity
- Note: MT5 uses tick volume by default (similar to MT4)
### 2. Spread Filter ### 2. Spread Filter
- Maximum allowed spread: 30 points - Maximum allowed spread: 30 points
@@ -53,9 +52,9 @@
- **Trading Timeframe:** H1 - **Trading Timeframe:** H1
- **Filter Timeframe:** D1 - **Filter Timeframe:** D1
- **Logic:** - **Logic:**
- D1 close > D1 EMA High: Only buy orders allowed - D1 close > D1 EMA High: Only buy positions allowed (bullish)
- D1 close < D1 EMA Low: Only sell orders allowed - D1 close < D1 EMA Low: Only sell positions allowed (bearish)
- D1 close between: No orders allowed - D1 close between: No positions allowed (no trend)
- Can be enabled/disabled - Can be enabled/disabled
### 4. News Filter (Optional) ### 4. News Filter (Optional)
@@ -69,30 +68,38 @@
- Stops trading if drawdown exceeds limit - Stops trading if drawdown exceeds limit
- Resumes trading when drawdown is below limit - Resumes trading when drawdown is below limit
### 6. Zone Width Filter
- **Min Zone Width:** 100 points minimum before trading
- Ensures meaningful trend setups
- Prevents trading during tight consolidation
## Implementation Phases ## Implementation Phases
### Phase 1: Project Setup & Git Configuration (3 tasks) ### Phase 1: Project Setup & Git Configuration (3 tasks)
- Create MQL4 project structure - Create MQL5 project structure
- Initialize Git repository - Initialize Git repository
- Configure remote to Gitea server - Configure remote to Gitea server
### Phase 2: Core EA Structure (4 tasks) ### Phase 2: Core EA Structure (4 tasks)
- Create MAEA.mq4 with basic framework - Create MAEA.mq5 with basic framework
- Define all input parameters - Define all input parameters
- Set up indicator buffers - Set up indicator buffers
- Initialize global variables - Initialize global variables
### Phase 3: Indicator Calculations (4 tasks) ### Phase 3: Indicator Calculations (4 tasks)
- Implement EMA calculations (High, Medium, Low) - Implement EMA calculations (High and Low only)
- Implement Border Line calculations - Implement zone fill between EMA High and EMA Low
- Add visual indicators with colors - Add visual indicators with colors (Light Blue, Orange, Light Yellow fill)
- Implement Volume average calculation - Implement Volume average calculation
### Phase 4: Signal Detection (4 tasks) ### Phase 4: Signal Detection (3 tasks)
- Implement breakthrough signal detection - Implement breakthrough signal detection
- Implement pullback signal detection - Check if previous close inside zone
- Implement separate pullback tracking - Check if current close broke above EMA High or below EMA Low
- Implement pullback flag reset logic - Implement opposite signal detection and position closing
- Close buy position when sell signal occurs
- Close sell position when buy signal occurs
- Implement minimum zone width check (100 points)
### Phase 5: Multiple Timeframe Filter (3 tasks) ### Phase 5: Multiple Timeframe Filter (3 tasks)
- Implement D1 EMA calculations - Implement D1 EMA calculations
@@ -106,31 +113,37 @@
- Add enable/disable toggle for news filter - Add enable/disable toggle for news filter
### Phase 7: Order Management (7 tasks) ### Phase 7: Order Management (7 tasks)
- Implement order opening with all filters - Implement position opening with all filters
- Implement dynamic lot sizing - Implement fixed lot sizing (0.01 lot)
- Implement Stop Loss placement - Implement Stop Loss placement at opposite EMA
- Implement Take Profit calculation - Implement Take Profit calculation
- Implement Breakeven logic - Implement Breakeven logic
- Implement Trailing Stop logic - Implement Trailing Stop logic
- Implement single order restriction - Implement single position restriction
### Phase 8: Risk Management (3 tasks) ### Phase 8: Risk Management (3 tasks)
- Implement max drawdown calculation - Implement max drawdown calculation
- Implement drawdown protection - Implement drawdown protection
- Implement trading resume logic - Implement trading resume logic
### Phase 9: Order Monitoring & Management (5 tasks) ### Phase 9: Order Monitoring & Management (6 tasks)
- Implement opposite signal checking on each tick
- Close position when opposite signal detected
- Implement Take Profit checking - Implement Take Profit checking
- Implement Breakeven checking and SL modification - Implement Breakeven checking and SL modification
- Implement Trailing Stop checking and SL modification - Implement Trailing Stop checking and SL modification
- Implement Stop Loss checking - Implement Stop Loss checking
- Implement order closure logic - Implement position closure logic
### Phase 10: Testing & Validation (7 tasks) ### Phase 10: Testing & Validation (8 tasks)
- Test all EMA and Border Line calculations - Test EMA High and Low calculations
- Test breakthrough and pullback signals - Test zone fill visualization
- Test zone width calculation
- Test minimum zone width filter (100 points)
- Test breakthrough signal detection (with zone check)
- Test opposite signal detection and position closing
- Test all filters - Test all filters
- Test order opening with correct lot sizes - Test position opening with fixed 0.01 lot
- Test TP, SL, breakeven, and trailing stop - Test TP, SL, breakeven, and trailing stop
- Test drawdown protection - Test drawdown protection
- Test visual indicators display - Test visual indicators display
@@ -142,44 +155,46 @@
- Commit initial code to Git - Commit initial code to Git
- Push to Gitea repository and verify - Push to Gitea repository and verify
## Total Tasks: 50 ## Total Tasks: 51
## Key Features Summary ## Key Features Summary
**Advanced Trend Following:** EMA-based with dynamic border lines **Simple Trend Following:** EMA-based with visual zone fill
**Smart Signal Detection:** Breakthrough and pullback signals with separate tracking **Clear Breakthrough Signals:** Zone breakout with previous bar confirmation
**Dynamic Lot Sizing:** 0.01 or 0.02 based on market behavior **Reverse Protection:** Positions close when opposite signal occurs
**Minimum Zone Width:** 100 points requirement for meaningful setups
**Fixed Lot Size:** Consistent 0.01 lot position sizing
**Comprehensive Filters:** Volume, spread, MTF, news, and drawdown protection **Comprehensive Filters:** Volume, spread, MTF, news, and drawdown protection
**Risk Management:** TP in USD, SL at borders, breakeven, trailing stop **Risk Management:** TP in USD, SL at opposite EMA, breakeven, trailing stop
**Visual Indicators:** 5 colored lines for easy analysis **Visual Indicators:** 2 EMAs with light yellow zone fill
**Flexible Configuration:** All features can be enabled/disabled **Flexible Configuration:** All features can be enabled/disabled
**Single Order Management:** Prevents over-trading **Single Position Management:** Prevents over-trading
**Timezone Aware:** Thailand timezone (UTC+7) for all time-based features **Timezone Aware:** Thailand timezone (UTC+7) for all time-based features
## Default Parameters ## Default Parameters
| Parameter | Value | Description | | Parameter | Value | Description |
|-----------|-------|-------------| |-----------|-------|-------------|
| EMA Period | 30 | Period for all EMAs | | EMA Period | 30 | Period for EMA High and EMA Low |
| Lot Size (Normal) | 0.01 | Lot without pullback | | Lot Size | 0.01 | Fixed lot size for all trades |
| Lot Size (Pullback) | 0.02 | Lot with pullback |
| Take Profit | $5 | Target profit in USD | | Take Profit | $5 | Target profit in USD |
| Breakeven Points | 100 | Points to trigger breakeven | | Breakeven Points | 100 | Points to trigger breakeven |
| Trailing Stop Points | 100 | Trail distance after breakeven | | Trailing Stop Points | 100 | Trail distance after breakeven |
| Max Spread | 30 points | Maximum allowed spread | | Max Spread | 30 points | Maximum allowed spread |
| Volume Period | 20 | Bars for volume average | | Volume Period | 20 | Bars for volume average |
| Min Zone Width | 100 points | Minimum zone width to trade |
| Max Drawdown | 10% | Maximum drawdown percentage | | Max Drawdown | 10% | Maximum drawdown percentage |
| MTF Filter | true | Enable/disable MTF filter | | MTF Filter | true | Enable/disable MTF filter |
| News Filter | true | Enable/disable news filter | | News Filter | true | Enable/disable news filter |
## Technical Specifications ## Technical Specifications
- **Platform:** MetaTrader 4 - **Platform:** MetaTrader 5
- **Language:** MQL4 - **Language:** MQL5
- **Trading Timeframe:** H1 (recommended) - **Trading Timeframe:** H1 (recommended)
- **Filter Timeframe:** D1 (for MTF) - **Filter Timeframe:** D1 (for MTF)
- **Currency Pairs:** All pairs (user-selectable) - **Currency Pairs:** All pairs (user-selectable)
- **Account Types:** Any MT4 account - **Account Types:** Any MT5 account
- **Server Timezone:** Thailand (UTC+7) - **Server Timezone:** Thailand (UTC+7)
## Next Steps ## Next Steps