From db575179ae34fef61f0bfcbbe64a10da20f98480 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Sat, 3 Jan 2026 14:25:25 +0700 Subject: [PATCH] feat(maea): migrate from MQL4 to MQL5 and simplify strategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- AGENTS.md | 162 +++++++ MAEA.mq4 | 698 ------------------------------ MAEA.mq5 | 509 ++++++++++++++++++++++ MAEA_Indicator.mq5 | 109 +++++ README.md | 345 --------------- opencode.jsonc | 13 + plans/MAEA-implementation-plan.md | 299 +++++++------ plans/MAEA-summary.md | 127 +++--- 8 files changed, 1019 insertions(+), 1243 deletions(-) create mode 100644 AGENTS.md delete mode 100644 MAEA.mq4 create mode 100644 MAEA.mq5 create mode 100644 MAEA_Indicator.mq5 delete mode 100644 README.md create mode 100644 opencode.jsonc diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ff01cc6 --- /dev/null +++ b/AGENTS.md @@ -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 + #include + #include + ``` + (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 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 \ No newline at end of file diff --git a/MAEA.mq4 b/MAEA.mq4 deleted file mode 100644 index be2e6ab..0000000 --- a/MAEA.mq4 +++ /dev/null @@ -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()); - } - } -} -//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/MAEA.mq5 b/MAEA.mq5 new file mode 100644 index 0000000..4949ff3 --- /dev/null +++ b/MAEA.mq5 @@ -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 +#include + +// === 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; +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/MAEA_Indicator.mq5 b/MAEA_Indicator.mq5 new file mode 100644 index 0000000..4183928 --- /dev/null +++ b/MAEA_Indicator.mq5 @@ -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; +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index e17d200..0000000 --- a/README.md +++ /dev/null @@ -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) \ No newline at end of file diff --git a/opencode.jsonc b/opencode.jsonc new file mode 100644 index 0000000..9c2f7d0 --- /dev/null +++ b/opencode.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "mql5_help": { + "type": "local", + "command": [ + "npx", + "-y", + "github:caoshuo594/mql5-help-mcp" + ] + } + } +} diff --git a/plans/MAEA-implementation-plan.md b/plans/MAEA-implementation-plan.md index b054508..59bebed 100644 --- a/plans/MAEA-implementation-plan.md +++ b/plans/MAEA-implementation-plan.md @@ -2,58 +2,44 @@ ## Project Overview - **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 - **Repository**: https://git.moreminimore.com/kunthawat/MAEA - **Timezone**: Thailand (UTC+7) ## Strategy Details -### 1. EMA Lines (3 Base Lines) +### 1. EMA Lines (2 Base Lines) All EMAs use period 30 with different price sources: - **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 -### 2. Border Lines (2 Dynamic Lines) -Calculated based on the range between EMAs: -- **High Border Line**: EMA High + (EMA Medium - EMA Low) - Purple color -- **Low Border Line**: EMA Low - (EMA Medium - EMA Low) - Purple color +### 2. EMA Zone (Visual Area) +- **Zone Definition**: The area between EMA High and EMA Low +- **Visual**: Light yellow transparent fill between EMA High and 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 -``` - -### 3. Signal Types +### 3. Signal Type #### 3.1 Breakthrough Signal -- **Buy Signal**: Close price breaks above EMA High -- **Sell Signal**: Close price breaks below EMA Low -- **Purpose**: Triggers order opening +- **Buy Signal**: Close price breaks above EMA High (zone breakout upward) +- **Sell Signal**: Close price breaks below EMA Low (zone breakout downward) +- **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 -- **Definition**: Price hits a line and closes on the opposite side -- **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 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 +#### 3.2 Opposite Signal Close +- **Close Buy Position**: When sell signal occurs (price breaks below EMA Low) +- **Close Sell Position**: When buy signal occurs (price breaks above EMA High) +- **Priority**: Opposite signal closes existing position immediately before opening new one ### 4. Order Opening Logic -- **Only one order at a time** -- **Lot Size**: - - 0.01 lot if no pullback occurred before breakthrough - - 0.02 lot if at least one pullback occurred before breakthrough in the same direction +- **Only one position at a time** +- **Lot Size**: Fixed 0.01 lot for all trades - **Trigger**: Breakthrough signal only +- **Minimum Zone Width**: Zone must be at least 100 points before trading - **Filters Applied**: - Volume filter must pass - Spread filter must pass @@ -67,8 +53,8 @@ Low Border = 3300 - 100 = 3200 - Closes order when profit reaches target amount #### 5.2 Stop Loss -- **Buy Orders**: SL at Low Border Line -- **Sell Orders**: SL at High Border Line +- **Buy Orders**: SL at EMA Low +- **Sell Orders**: SL at EMA High #### 5.3 Breakeven - 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) - **Status**: Optional feature (can be turned on/off) - **D1 Filter Logic**: - - If D1 close > D1 EMA High: Only buy orders allowed - - If D1 close < D1 EMA Low: Only sell orders allowed - - If D1 close between D1 EMA High and D1 EMA Low: No orders allowed -- **Behavior**: Order opens immediately when filter condition is met + - If D1 close > D1 EMA High: Only buy positions allowed (bullish trend) + - If D1 close < D1 EMA Low: Only sell positions allowed (bearish trend) + - If D1 close between D1 EMA High and D1 EMA Low: No positions allowed (no clear trend) +- **Behavior**: Position opens immediately when filter condition is met ### 8. Spread Filter - **Purpose**: Avoid trading during high spread periods @@ -115,80 +101,83 @@ Low Border = 3300 - 100 = 3200 ```mermaid graph TD - A[Start New Bar] --> B[Calculate EMAs] - B --> C[Calculate Border Lines] - C --> D[Check for Open Orders] - D -->|Has Open Order| E[Manage Open Order] - D -->|No Open Order| F[Check Pullback Signals] + A[Start New Bar] --> B[Calculate EMA High/Low] + B --> C[Fill Zone Between EMAs] + C --> D[Check for Open Positions] + D -->|Has Open Position| E[Check Opposite Signal] + D -->|No Open Position| F[Check Breakthrough Signals] - E --> E1[Check Take Profit] - E1 -->|TP Reached| E2[Close Order] - E1 -->|TP Not Reached| E3[Check Breakeven] - E3 -->|Breakeven Reached| E4[Move SL to Entry] - E3 -->|Breakeven Not Reached| E5[Check Stop Loss] - E5 -->|SL Hit| E2 - E5 -->|SL Not Hit| A + E --> E1{Opposite Signal?} + E1 -->|Buy open, Sell signal| E2[Close Buy Position] + E1 -->|Sell open, Buy signal| E3[Close Sell Position] + E1 -->|No opposite signal| E4[Manage Position Risks] + E2 --> A + E3 --> A - F --> F1[Close Below EMA High] - F1 -->|Yes| F2[Set Pullback Flag] - F1 -->|No| F3[Close Below EMA Medium] - F3 -->|Yes| F2 - F3 -->|No| F4[Close Below EMA Low] - F4 -->|Yes| F2 - F4 -->|No| F5[Check Breakthrough Signals] + E4 --> E5[Check Take Profit] + E5 -->|TP Reached| E6[Close Position] + E5 -->|TP Not Reached| E7[Check Breakeven] + E7 -->|Breakeven Reached| E8[Move SL to Entry] + E7 -->|Breakeven Not Reached| E9[Check SL Hit] + E9 -->|SL Hit| E6 + E9 -->|SL Not Hit| A + E6 --> A - F2 --> F5 - F5 --> F6[Close Above EMA High] - F6 -->|Yes| F7[Open Buy Order] - F6 -->|No| F8[Close Below EMA Low] - F8 -->|Yes| F9[Open Sell Order] - F8 -->|No| A + F --> F1{Previous Close Inside Zone?} + F1 -->|No| A + F1 -->|Yes| F2{Zone Width >= 100 points?} + F2 -->|No| A + F2 -->|Yes| F3{Current Close Direction} + F3 -->|Close > EMA High| F4[Check Filters] + F3 -->|Close < EMA Low| F5[Check Filters] + F3 -->|Still Inside| A - F7 --> F10[Set Lot Size] - F10 -->|Pullback| F11[0.02 Lot] - F10 -->|No Pullback| F12[0.01 Lot] - F11 --> F13[Set SL at Low Border] - F12 --> F13 - F13 --> F14[Set TP based on USD Target] - F14 --> F15[Reset Pullback Flag] - F15 --> A + F4 --> F6{Volume OK? Spread OK? MTF OK? News OK?} + F5 --> F6 + F6 -->|All Pass| F7[Open Buy Position] + F6 -->|Any Fail| A - F9 --> F16[Set Lot Size] - F16 -->|Pullback| F17[0.02 Lot] - F16 -->|No Pullback| F18[0.01 Lot] - F17 --> F19[Set SL at High Border] - F18 --> F19 - F19 --> F20[Set TP based on USD Target] - F20 --> F21[Reset Pullback Flag] - F21 --> A + F7 --> F8[Set SL at EMA Low] + F8 --> F9[Set TP based on USD Target] + F9 --> 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 ### Phase 1: Project Setup & Git Configuration -1. Create MQL4 project structure +1. Create MQL5 project structure 2. Initialize Git repository 3. Configure remote to Gitea server (https://git.moreminimore.com/kunthawat/MAEA) ### Phase 2: Core EA Structure -4. Create [`MAEA.mq4`](MAEA.mq4) with basic EA framework -5. Define all input parameters (EMA period, lot sizes, TP, breakeven, trailing stop, filters, etc.) -6. Set up indicator buffers for 5 visual lines +4. Create [`MAEA.mq5`](MAEA.mq5) with basic EA framework +5. Define all input parameters (EMA period, lot size, TP, breakeven, trailing stop, filters, etc.) +6. Set up indicator buffers for 2 EMA lines + zone fill (3 buffers total) 7. Initialize global variables for state tracking ### Phase 3: Indicator Calculations -8. Implement EMA calculations for High, Medium, Low (period 30) -9. Implement Border Line calculations (High Border = High + Range, Low Border = Low - Range) -10. Add visual indicators with correct colors (Light Blue, Yellow, Orange, Purple) +8. Implement EMA calculations for High and Low (period 30) +9. Implement zone fill between EMA High and EMA Low (transparent light yellow) +10. Add visual indicators with correct colors (Light Blue for EMA High, Orange for EMA Low) 11. Implement Volume average calculation (20-bar average) ### Phase 4: Signal Detection -12. Implement breakthrough signal detection (price breaks High/Low EMA) -13. Implement pullback signal detection (price hits line and closes on opposite side) -14. Implement separate pullback tracking for buy and sell directions -15. Implement pullback flag reset logic after order opens +12. Implement breakthrough signal detection + - Check if previous close was inside zone + - Check if current close broke above EMA High or below EMA Low +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 16. Implement D1 EMA calculations for MTF filter @@ -202,13 +191,15 @@ graph TD 22. Add enable/disable toggles for news filter ### Phase 7: Order Management -23. Implement order opening logic with all filter checks -24. Implement dynamic lot sizing (0.01 no pullback, 0.02 with pullback) -25. Implement Stop Loss placement at Border Lines +23. Implement position opening logic with all filter checks +24. Implement fixed lot sizing (0.01 lot) +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) 27. Implement Breakeven logic (move SL to entry at X points) 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 30. Implement max drawdown calculation @@ -216,20 +207,24 @@ graph TD 32. Implement trading resume logic when drawdown is below limit ### Phase 9: Order Monitoring & Management -33. Implement Take Profit checking on each tick -34. Implement Breakeven checking and SL modification -35. Implement Trailing Stop checking and SL modification -36. Implement Stop Loss checking -37. Implement order closure logic +33. Implement opposite signal checking on each tick +34. If opposite signal detected, close existing position immediately +35. Implement Take Profit checking on each tick +36. Implement Breakeven checking and SL modification +37. Implement Trailing Stop checking and SL modification +38. Implement Stop Loss checking +39. Implement position closure logic ### Phase 10: Testing & Validation -38. Test all EMA and Border Line calculations -39. Test breakthrough and pullback signal detection -40. Test all filters (volume, spread, MTF, news) -41. Test order opening with correct lot sizes -42. Test TP, SL, breakeven, and trailing stop -43. Test drawdown protection -44. Test visual indicators display +38. Test EMA High and Low calculations +39. Test zone fill visualization (transparent yellow) +40. Test breakthrough signal detection + - Verify breakout requires previous close inside zone +41. Test all filters (volume, spread, MTF, news) +42. Test position opening with fixed 0.01 lot +43. Test TP, SL (at opposite EMA), breakeven, and trailing stop +44. Test drawdown protection +45. Test visual indicators display ### Phase 11: Documentation & Deployment 45. Create comprehensive [`README.md`](README.md) with strategy documentation @@ -243,15 +238,15 @@ graph TD | Parameter | Description | Default Value | |-----------|-------------|---------------| -| `EMAPeriod` | EMA period for all lines | 30 | -| `LotSizeNormal` | Lot size without pullback | 0.01 | -| `LotSizePullback` | Lot size with pullback | 0.02 | +| `EMAPeriod` | EMA period for both lines | 30 | +| `LotSize` | Fixed lot size | 0.01 | | `TakeProfitUSD` | Take profit target in USD | 5.0 | | `BreakevenPoints` | Points to trigger breakeven | 100 | | `TrailingStopPoints` | Points for trailing stop distance | 100 | | `MagicNumber` | EA unique identifier | 12345 | | `MaxSpread` | Maximum allowed spread in points | 30 | | `VolumePeriod` | Period for volume average calculation | 20 | +| `MinZoneWidthPoints` | Minimum zone width to trade (points) | 100 | | `MaxDrawdownPercent` | Maximum drawdown percentage | 10.0 | | `UseMTFFilter` | Enable/disable MTF filter | true | | `UseNewsFilter` | Enable/disable news filter | true | @@ -263,61 +258,73 @@ graph TD | Line | Color | Description | |------|-------|-------------| | 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 | -| High Border | Purple (clrPurple) | Upper dynamic border | -| Low Border | Purple (clrPurple) | Lower dynamic border | +| Zone Fill | Light Yellow (transparent) | Area between EMA High and EMA Low | ## Key Considerations -1. **Pullback Detection**: Track price hitting lines and closing on opposite side separately for buy/sell -2. **Pullback Reset**: Reset pullback flag immediately after opening an order -3. **Single Order**: Only one order open at any time -4. **Dynamic SL**: Stop Loss moves with Border Lines as they update -5. **Breakeven**: Only moves SL to entry price, not to profit -6. **TP Calculation**: Convert USD target to pips based on lot size and symbol -7. **Volume Filter**: Only trade when current volume exceeds 20-bar average -8. **MTF Filter**: D1 timeframe acts as trend filter, H1 for entry signals -9. **Spread Filter**: Avoid high spread periods -10. **Timezone**: All time-based filters use Thailand timezone (UTC+7) -11. **Trailing Stop**: Activates after breakeven, trails by specified points -12. **Drawdown Protection**: Stops trading if max drawdown exceeded +1. **Breakthrough Detection**: Previous close must be inside zone, current close outside zone +2. **Opposite Signal Close**: Close existing position when opposite breakthrough signal occurs +3. **Minimum Zone Width**: Zone must be at least 100 points wide before trading +4. **Single Position**: Only one position open at any time (MT5 uses positions, not orders) +5. **SL at Opposite EMA**: Buy SL at EMA Low, Sell SL at EMA High +6. **Fixed Lot Size**: Always 0.01 lot regardless of market conditions +7. **Breakeven**: Only moves SL to entry price, not to profit +8. **TP Calculation**: Convert USD target to pips based on lot size and symbol +9. **Volume Filter**: Only trade when current volume exceeds 20-bar average +10. **MTF Filter**: D1 price position relative to zone determines allowed direction +11. **Spread Filter**: Avoid high spread periods +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 -- **Platform**: MetaTrader 4 -- **Language**: MQL4 +- **Platform**: MetaTrader 5 +- **Language**: MQL5 - **Trading Timeframe**: H1 (recommended) - **Filter Timeframe**: D1 (for MTF filter) - **Currency Pairs**: All pairs (user-selectable) -- **Account Types**: Any MT4 account type +- **Account Types**: Any MT5 account type - **Server Timezone**: Thailand (UTC+7) ## Testing Checklist ### Core Strategy -- [ ] EMA calculations verify correctly (High, Medium, Low) -- [ ] Border Line calculations verify correctly +- [ ] EMA calculations verify correctly (High and Low) +- [ ] 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 -- [ ] Pullback signals detect correctly (buy and sell separately) -- [ ] Pullback flag resets after order opens -- [ ] Lot sizes apply correctly (0.01 vs 0.02) + - [ ] Previous close inside zone check + - [ ] Buy signal: close > EMA High + - [ ] Sell signal: close < EMA Low +- [ ] Opposite signal detection works + - [ ] Buy position closes when sell signal occurs + - [ ] Sell position closes when buy signal occurs ### Filters - [ ] Volume filter works (20-bar average, current > average) - [ ] 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 +- [ ] Min zone width filter works (100 points minimum) - [ ] News filter avoids specified times (Thailand timezone) - [ ] News filter can be enabled/disabled ### 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 - [ ] Breakeven triggers at correct points - [ ] Trailing stop activates after breakeven - [ ] 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 - [ ] Max drawdown protection works @@ -332,11 +339,15 @@ graph TD ## Notes -- The strategy uses 5 visual lines on the chart -- Pullback tracking is separate for buy and sell directions -- Border Lines expand the range beyond the EMAs for wider stops +- The strategy uses 2 EMA lines with a filled zone between them +- No pullback tracking or dynamic lot sizing - simplified approach +- 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 +- Breakthrough signals require price to be inside zone before breaking out - Multiple filters ensure quality trade entries - All time-based calculations use Thailand timezone (UTC+7) -- MTF filter provides higher timeframe trend confirmation -- Risk management features protect account from excessive losses \ No newline at end of file +- MTF filter matches price position relative to D1 zone +- Risk management features protect account from excessive losses +- Zone fill uses light yellow color with transparency for better visibility \ No newline at end of file diff --git a/plans/MAEA-summary.md b/plans/MAEA-summary.md index 45a0525..75b7ecd 100644 --- a/plans/MAEA-summary.md +++ b/plans/MAEA-summary.md @@ -1,39 +1,37 @@ # MAEA Project Summary ## 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 **Timezone:** Thailand (UTC+7) ## Core Strategy -### Indicator System (5 Visual Lines) +### Indicator System (2 EMA Lines + Zone) 1. **EMA High** (Light Blue) - EMA of High prices, period 30 -2. **EMA Medium** (Yellow) - EMA of Close prices, period 30 -3. **EMA Low** (Orange) - EMA of Low prices, period 30 -4. **High Border** (Purple) - EMA High + (EMA Medium - EMA Low) -5. **Low Border** (Purple) - EMA Low - (EMA Medium - EMA Low) +2. **EMA Low** (Orange) - EMA of Low prices, period 30 +3. **Zone Fill** (Light Yellow, transparent) - Area between EMA High and EMA Low ### Signal Types #### 1. Breakthrough Signal -- **Buy:** Close price breaks above EMA High -- **Sell:** Close price breaks below EMA Low -- **Purpose:** Triggers order opening +- **Buy:** Close price breaks above EMA High (must have previous close inside zone) +- **Sell:** Close price breaks below EMA Low (must have previous close inside zone) +- **Purpose:** Triggers position opening +- **Verification:** Previous bar close must be inside zone between EMA High and EMA Low -#### 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 +#### 2. Opposite Signal Close +- **Close Buy:** When sell signal occurs (price breaks below EMA Low) +- **Close Sell:** When buy signal occurs (price breaks above EMA High) +- **Immediate Action:** Position closes before checking for new trade ### 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) +- **Single Position:** Only one position open at a time (MT5 uses positions, not orders) +- **Fixed Lot Size:** 0.01 lot for all trades +- **Stop Loss:** At opposite EMA (Buy: EMA Low, Sell: EMA High) +- **Reverse Protection:** Close position when opposite signal occurs +- **Min Zone Width:** Zone must be at least 100 points to trade - **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) @@ -42,8 +40,9 @@ ### 1. Volume Filter - Calculate 20-bar volume average -- Trade only when current volume > average -- Ensures sufficient market activity + - Trade only when current volume > average + - Ensures sufficient market activity + - Note: MT5 uses tick volume by default (similar to MT4) ### 2. Spread Filter - Maximum allowed spread: 30 points @@ -53,9 +52,9 @@ - **Trading Timeframe:** H1 - **Filter Timeframe:** D1 - **Logic:** - - D1 close > D1 EMA High: Only buy orders allowed - - D1 close < D1 EMA Low: Only sell orders allowed - - D1 close between: No orders allowed + - D1 close > D1 EMA High: Only buy positions allowed (bullish) + - D1 close < D1 EMA Low: Only sell positions allowed (bearish) + - D1 close between: No positions allowed (no trend) - Can be enabled/disabled ### 4. News Filter (Optional) @@ -69,30 +68,38 @@ - Stops trading if drawdown exceeds 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 ### Phase 1: Project Setup & Git Configuration (3 tasks) -- Create MQL4 project structure +- Create MQL5 project structure - Initialize Git repository - Configure remote to Gitea server ### Phase 2: Core EA Structure (4 tasks) -- Create MAEA.mq4 with basic framework +- Create MAEA.mq5 with basic framework - Define all input parameters - Set up indicator buffers - Initialize global variables ### Phase 3: Indicator Calculations (4 tasks) -- Implement EMA calculations (High, Medium, Low) -- Implement Border Line calculations -- Add visual indicators with colors +- Implement EMA calculations (High and Low only) +- Implement zone fill between EMA High and EMA Low +- Add visual indicators with colors (Light Blue, Orange, Light Yellow fill) - Implement Volume average calculation -### Phase 4: Signal Detection (4 tasks) +### Phase 4: Signal Detection (3 tasks) - Implement breakthrough signal detection -- Implement pullback signal detection -- Implement separate pullback tracking -- Implement pullback flag reset logic + - Check if previous close inside zone + - Check if current close broke above EMA High or below EMA Low +- 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) - Implement D1 EMA calculations @@ -106,31 +113,37 @@ - Add enable/disable toggle for news filter ### Phase 7: Order Management (7 tasks) -- Implement order opening with all filters -- Implement dynamic lot sizing -- Implement Stop Loss placement +- Implement position opening with all filters +- Implement fixed lot sizing (0.01 lot) +- Implement Stop Loss placement at opposite EMA - Implement Take Profit calculation - Implement Breakeven logic - Implement Trailing Stop logic -- Implement single order restriction +- Implement single position restriction ### Phase 8: Risk Management (3 tasks) - Implement max drawdown calculation - Implement drawdown protection - 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 Breakeven checking and SL modification - Implement Trailing Stop checking and SL modification - Implement Stop Loss checking -- Implement order closure logic +- Implement position closure logic -### Phase 10: Testing & Validation (7 tasks) -- Test all EMA and Border Line calculations -- Test breakthrough and pullback signals +### Phase 10: Testing & Validation (8 tasks) +- Test EMA High and Low calculations +- 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 order opening with correct lot sizes +- Test position opening with fixed 0.01 lot - Test TP, SL, breakeven, and trailing stop - Test drawdown protection - Test visual indicators display @@ -142,44 +155,46 @@ - Commit initial code to Git - Push to Gitea repository and verify -## Total Tasks: 50 +## Total Tasks: 51 ## Key Features Summary -✅ **Advanced Trend Following:** EMA-based with dynamic border lines -✅ **Smart Signal Detection:** Breakthrough and pullback signals with separate tracking -✅ **Dynamic Lot Sizing:** 0.01 or 0.02 based on market behavior +✅ **Simple Trend Following:** EMA-based with visual zone fill +✅ **Clear Breakthrough Signals:** Zone breakout with previous bar confirmation +✅ **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 -✅ **Risk Management:** TP in USD, SL at borders, breakeven, trailing stop -✅ **Visual Indicators:** 5 colored lines for easy analysis +✅ **Risk Management:** TP in USD, SL at opposite EMA, breakeven, trailing stop +✅ **Visual Indicators:** 2 EMAs with light yellow zone fill ✅ **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 ## Default Parameters | Parameter | Value | Description | |-----------|-------|-------------| -| EMA Period | 30 | Period for all EMAs | -| Lot Size (Normal) | 0.01 | Lot without pullback | -| Lot Size (Pullback) | 0.02 | Lot with pullback | +| EMA Period | 30 | Period for EMA High and EMA Low | +| Lot Size | 0.01 | Fixed lot size for all trades | | Take Profit | $5 | Target profit in USD | | Breakeven Points | 100 | Points to trigger breakeven | | Trailing Stop Points | 100 | Trail distance after breakeven | | Max Spread | 30 points | Maximum allowed spread | | Volume Period | 20 | Bars for volume average | +| Min Zone Width | 100 points | Minimum zone width to trade | | Max Drawdown | 10% | Maximum drawdown percentage | | MTF Filter | true | Enable/disable MTF filter | | News Filter | true | Enable/disable news filter | ## Technical Specifications -- **Platform:** MetaTrader 4 -- **Language:** MQL4 +- **Platform:** MetaTrader 5 +- **Language:** MQL5 - **Trading Timeframe:** H1 (recommended) - **Filter Timeframe:** D1 (for MTF) - **Currency Pairs:** All pairs (user-selectable) -- **Account Types:** Any MT4 account +- **Account Types:** Any MT5 account - **Server Timezone:** Thailand (UTC+7) ## Next Steps