//+------------------------------------------------------------------+ //| Robot.mq5 | //| Copyright 2026, MasterOfPuppets | //| https://forge.mql5.io/masterofpuppets/mql5 | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Includes | //+------------------------------------------------------------------+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Action.mqh" //+------------------------------------------------------------------+ //| Properties | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MasterOfPuppets" #property description "Advanced Position Builder, Pyramider && Scalper Terminal" #property link "https://forge.mql5.io/masterofpuppets/mql5" #property version "1.00" //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input bool ASYNC_MODE_ENABLED = false; input double CONTRACTS = 0.01; input int INDENT_SIZE = 134; input int LAST_PROFITS_SIZE = 10; input bool SOUND_ENABLED = true; input string SOUND_FILE_NAME = "ok.wav"; input double STOP_LOSS = 1.0; input double TAKE_PROFIT = 0.0; input group "Action keys" MASTER_OF_PUPPETS_ACTION_KEY_MAPPINGS(MASTER_OF_PUPPETS_LIB_GENERATE_INPUT) //+------------------------------------------------------------------+ //| Constants | //+------------------------------------------------------------------+ const string INDENT_FORMAT = StringFormat("%%%is\n", INDENT_SIZE); const ulong MAGIC = 202603110245; //+------------------------------------------------------------------+ //| Variables | //+------------------------------------------------------------------+ Actions actions; string actionsUsage; bool buyPyramid = false; CDealInfo dealInfo; string lastProfitInfo; COrderInfo orderInfo; CPositionInfo positionInfo; Reporter reporter; bool sellPyramid = false; CSymbolInfo symbolInfo; CTrade trade; TradeContext tradeContext; Trader trader; TraderContext traderContext; ClosePositionModifier closeAllPositionModifier; ClosePositionModifier closeExpertPositionModifier; DefendModifier defendAllModifier; DefendModifier defendExpertModifier; ProtectModifier protectModifier; datetime lastBarTime; //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int32_t id, const long &lparam, const double &dparam, const string &sparam) { if(id != CHARTEVENT_KEYDOWN) { return; } Action action = (Action) actions.GetAction(lparam); switch(action) { MASTER_OF_PUPPETS_ACTION_KEY_MAPPINGS(MASTER_OF_PUPPETS_LIB_GENERATE_CASE) } } //+------------------------------------------------------------------+ //| On buy function | //+------------------------------------------------------------------+ void OnBUY(const Action action) { trader.PositionOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_BUY); } //+------------------------------------------------------------------+ //| On buy limit function | //+------------------------------------------------------------------+ void OnBUY_LIMIT(const Action action) { trader.OrderOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_BUY_LIMIT); } //+------------------------------------------------------------------+ //| On buy protect function | //+------------------------------------------------------------------+ void OnBUY_PROTECT(const Action action) { trader.Modify(actions.GetActionName(action), &protectModifier); OnBUY(action); } //+------------------------------------------------------------------+ //| On buy pyramid function | //+------------------------------------------------------------------+ void OnBUY_PYRAMID(const Action action) { buyPyramid = true; OnBUY(action); } //+------------------------------------------------------------------+ //| On buy stop function | //+------------------------------------------------------------------+ void OnBUY_STOP(const Action action) { trader.OrderOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_BUY_STOP); } //+------------------------------------------------------------------+ //| On close all positions function | //+------------------------------------------------------------------+ void OnCLOSE_ALL_POSITIONS(const Action action) { trader.Modify(actions.GetActionName(action), &closeAllPositionModifier); } //+------------------------------------------------------------------+ //| On close expert positions function | //+------------------------------------------------------------------+ void OnCLOSE_EXPERT_POSITIONS(const Action action) { trader.Modify(actions.GetActionName(action), &closeExpertPositionModifier); } //+------------------------------------------------------------------+ //| On defend all positions function | //+------------------------------------------------------------------+ void OnDEFEND_ALL_POSITIONS(const Action action) { trader.Modify(actions.GetActionName(action), &defendAllModifier); } //+------------------------------------------------------------------+ //| On defend expert positions function | //+------------------------------------------------------------------+ void OnDEFEND_EXPERT_POSITIONS(const Action action) { trader.Modify(actions.GetActionName(action), &defendExpertModifier); } //+------------------------------------------------------------------+ //| On delete all orders function | //+------------------------------------------------------------------+ void OnDELETE_ALL_ORDERS(const Action action) { trader.DeleteOrders(actions.GetActionName(action), true); } //+------------------------------------------------------------------+ //| On delete expert orders function | //+------------------------------------------------------------------+ void OnDELETE_EXPERT_ORDERS(const Action action) { trader.DeleteOrders(actions.GetActionName(action), false); } //+------------------------------------------------------------------+ //| On exit master of puppets function | //+------------------------------------------------------------------+ void OnEXIT_MASTER_OF_PUPPETS(const Action action) { Print(actions.GetActionName(action)); PlaySoundFile(SOUND_ENABLED, SOUND_FILE_NAME); ExpertRemove(); } //+------------------------------------------------------------------+ //| On lock function | //+------------------------------------------------------------------+ void OnLOCK(const Action action) { OnBUY(action); OnSELL(action); } //+------------------------------------------------------------------+ //| On reverse all positions function | //+------------------------------------------------------------------+ void OnREVERSE_ALL_POSITIONS(const Action action) { ReversePositions(true); } //+------------------------------------------------------------------+ //| On reverse expert positions function | //+------------------------------------------------------------------+ void OnREVERSE_EXPERT_POSITIONS(const Action action) { ReversePositions(false); } //+------------------------------------------------------------------+ //| Reverse positions function | //+------------------------------------------------------------------+ void ReversePositions(const bool allPositions) { Action action; if(allPositions) { action = Action::DO_REVERSE_ALL_POSITIONS; } else { action = Action::DO_REVERSE_EXPERT_POSITIONS; } Print(actions.GetActionName(action)); if(positionInfo.SelectByIndex(0)) { switch(positionInfo.PositionType()) { case ENUM_POSITION_TYPE::POSITION_TYPE_BUY: action = Action::DO_SELL; break; case ENUM_POSITION_TYPE::POSITION_TYPE_SELL: action = Action::DO_BUY; break; } } else { PlaySoundFile(SOUND_ENABLED, SOUND_FILE_NAME); return; } if(allPositions) { OnCLOSE_ALL_POSITIONS(Action::DO_CLOSE_ALL_POSITIONS); } else { OnCLOSE_EXPERT_POSITIONS(Action::DO_CLOSE_EXPERT_POSITIONS); } switch(action) { case Action::DO_BUY: trader.PositionOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_BUY); break; case Action::DO_SELL: trader.PositionOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_SELL); break; } } //+------------------------------------------------------------------+ //| On sell function | //+------------------------------------------------------------------+ void OnSELL(const Action action) { trader.PositionOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_SELL); } //+------------------------------------------------------------------+ //| On sell limit function | //+------------------------------------------------------------------+ void OnSELL_LIMIT(const Action action) { trader.OrderOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_SELL_LIMIT); } //+------------------------------------------------------------------+ //| On sell protect function | //+------------------------------------------------------------------+ void OnSELL_PROTECT(const Action action) { trader.Modify(actions.GetActionName(action), &protectModifier); OnSELL(action); } //+------------------------------------------------------------------+ //| On sell pyramid function | //+------------------------------------------------------------------+ void OnSELL_PYRAMID(const Action action) { sellPyramid = true; OnSELL(action); } //+------------------------------------------------------------------+ //| On sell stop function | //+------------------------------------------------------------------+ void OnSELL_STOP(const Action action) { trader.OrderOpen(actions.GetActionName(action), TradeAction::TRADE_ACTION_SELL_STOP); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if(!symbolInfo.Name(_Symbol)) { PlaySoundFile(SOUND_ENABLED, SOUND_FILE_NAME); return(INIT_FAILED); } InitActions(); if(!IsKeyMappingCorrect(actions)) { PlaySoundFile(SOUND_ENABLED, SOUND_FILE_NAME); return(INIT_PARAMETERS_INCORRECT); } EventSetTimer(1); trade.SetAsyncMode(ASYNC_MODE_ENABLED); trade.SetExpertMagicNumber(MAGIC); tradeContext.Init(GetPointer(orderInfo), GetPointer(positionInfo), GetPointer(symbolInfo), GetPointer(trade)); traderContext.Init(CONTRACTS, SOUND_ENABLED, SOUND_FILE_NAME, STOP_LOSS, TAKE_PROFIT, MAGIC); trader.Init(GetPointer(tradeContext), GetPointer(traderContext)); closeAllPositionModifier.Init(GetPointer(tradeContext), GetPointer(traderContext)); closeExpertPositionModifier.Init(GetPointer(tradeContext), GetPointer(traderContext), true); defendAllModifier.Init(GetPointer(tradeContext), GetPointer(traderContext)); defendExpertModifier.Init(GetPointer(tradeContext), GetPointer(traderContext), true); protectModifier.Init(GetPointer(tradeContext), GetPointer(traderContext)); reporter.Init(GetPointer(dealInfo), LAST_PROFITS_SIZE); InitLastProfits(); actionsUsage = actions.Usage(); Print(actionsUsage); lastBarTime = iTime(_Symbol, _Period, 0); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Actions initialization function | //+------------------------------------------------------------------+ void InitActions() { actions.Clear(); MASTER_OF_PUPPETS_ACTION_KEY_MAPPINGS(MASTER_OF_PUPPETS_LIB_GENERATE_ADD_ACTION) } //+------------------------------------------------------------------+ //| Last profits initialization function | //+------------------------------------------------------------------+ void InitLastProfits() { reporter.InitLastProfits(); SetLastProfit(); } //+------------------------------------------------------------------+ //| Set last profit function | //+------------------------------------------------------------------+ void SetLastProfit() { lastProfitInfo = "\n"; const CArrayObj *lastProfits = reporter.GetLastProfits(); for(int i = lastProfits.Total() - 1; i >= 0; i--) { LastProfit *lastProfit = lastProfits.At(i); lastProfitInfo += StringFormat(INDENT_FORMAT, lastProfit.message + lastProfit.suffix + StringFormat("%-7.2f", lastProfit.profit)); } lastProfitInfo += StringFormat(INDENT_FORMAT, DoubleToString(reporter.GetTotalLastProfit(), 2)); } //+------------------------------------------------------------------+ //| Tick function | //+------------------------------------------------------------------+ void OnTick() { BuildPyramid(); Robot(); } //+------------------------------------------------------------------+ //| Build pyramid function | //+------------------------------------------------------------------+ void BuildPyramid() { if(!(buyPyramid || sellPyramid)) { return; } symbolInfo.RefreshRates(); if(buyPyramid && (symbolInfo.Ask() > trader.GetBuyPyramidPriceOpen() + STOP_LOSS)) { OnDEFEND_ALL_POSITIONS(Action::UNKNOWN); OnBUY(Action::DO_BUY); } if(sellPyramid && (symbolInfo.Bid() < trader.GetSellPyramidPriceOpen() - STOP_LOSS)) { OnDEFEND_ALL_POSITIONS(Action::UNKNOWN); OnSELL(Action::DO_SELL); } } //+------------------------------------------------------------------+ //| Robot lock function | //+------------------------------------------------------------------+ void RobotLock() { datetime currentBarTime = iTime(_Symbol, _Period, 0); if(currentBarTime != lastBarTime) { OnCLOSE_EXPERT_POSITIONS(Action::DO_CLOSE_EXPERT_POSITIONS); OnLOCK(Action::DO_LOCK); lastBarTime = currentBarTime; } } input int WaitSeconds = 10; // Сколько секунд ждем после открытия бара input double MinReflected = 10.0; // Минимальный откат (в пунктах), чтобы считать сигнал валидным bool signalProcessed = false; double initialOpen = 0; double extremePoint = 0; // Самая дальняя точка за первые 10 сек input int InpWaitSeconds = 10; // Сколько секунд ждать от начала свечи input double InpMinSize = 10.0; // Минимальный размер свечи в пунктах для входа //+------------------------------------------------------------------+ //| Robot function | //+------------------------------------------------------------------+ void Robot() { //static datetime lastBarTime = 0; static bool isAnalyzed = false; datetime currentTime = TimeCurrent(); datetime barStartTime = iTime(_Symbol, PERIOD_M1, 0); // Если началась новая минута — сбрасываем флаг анализа if(barStartTime != lastBarTime) { OnCLOSE_EXPERT_POSITIONS(Action::DO_CLOSE_EXPERT_POSITIONS); lastBarTime = barStartTime; isAnalyzed = false; } // Проверяем, прошло ли нужное количество секунд int secondsPassed = (int)(currentTime - barStartTime); if(!isAnalyzed && secondsPassed >= InpWaitSeconds) { double high = iHigh(_Symbol, PERIOD_M1, 0); double low = iLow(_Symbol, PERIOD_M1, 0); double current = SymbolInfoDouble(_Symbol, SYMBOL_BID); double distToLow = current - low; double distToHigh = high - current; // Проверка на минимальную волатильность (чтобы не торговать на доджи) if((high - low) / _Point < InpMinSize) { isAnalyzed = true; return; } double prevOpen = iOpen(_Symbol, PERIOD_M1, 1); double prevClose = iClose(_Symbol, PERIOD_M1, 1); Print("prevOpen: ", NormalizeDouble(prevOpen, _Digits), " prevClose: ", NormalizeDouble(prevClose, _Digits), " prevClose - prevOpen: ", NormalizeDouble(prevClose - prevOpen, _Digits)); Print("\nlow: ", NormalizeDouble(low, _Digits), " current: ", NormalizeDouble(current, _Digits), " high: ", NormalizeDouble(high, _Digits)); if(distToLow > distToHigh) { OnBUY(Action::DO_BUY); Print("Прогноз: ВВЕРХ. (Отрезок снизу ", NormalizeDouble(distToLow / _Point, _Digits), " пт > сверху ", NormalizeDouble(distToHigh / _Point, _Digits), " пт)"); } else if(distToHigh > distToLow) { OnSELL(Action::DO_SELL); Print("Прогноз: ВНИЗ. (Отрезок сверху ", NormalizeDouble(distToHigh / _Point, _Digits), " пт > снизу ", NormalizeDouble(distToLow / _Point, _Digits), " пт)"); } isAnalyzed = true; // Чтобы не частить в рамках одной минуты } } //+------------------------------------------------------------------+ //| Robot1 function | //+------------------------------------------------------------------+ void Robot1() { datetime currentBarTime = iTime(_Symbol, PERIOD_M1, 0); // Проверка начала нового бара if(currentBarTime != lastBarTime) { lastBarTime = currentBarTime; signalProcessed = false; initialOpen = iOpen(_Symbol, PERIOD_M1, 0); extremePoint = initialOpen; } if(signalProcessed) return; int secondsElapsed = (int)(TimeCurrent() - currentBarTime); // Фаза 1: Собираем экстремумы в первые 10 секунд if(secondsElapsed < WaitSeconds) { double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(currentBid > extremePoint) extremePoint = currentBid; if(currentBid < extremePoint) extremePoint = currentBid; } // Фаза 2: После 10 секунд ищем пересечение цены открытия else { double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double pointsShift = MathAbs(extremePoint - initialOpen) / _Point; // Условие: цена была НИЖЕ открытия, а теперь пробила его ВВЕРХ if(extremePoint < initialOpen && currentBid > initialOpen && pointsShift >= MinReflected) { Print("Сигнал ВВЕРХ: Цена откатилась от минимума на ", pointsShift, " пт."); signalProcessed = true; // Здесь код для открытия сделки Buy } // Условие: цена была ВЫШЕ открытия, а теперь пробила его ВНИЗ if(extremePoint > initialOpen && currentBid < initialOpen && pointsShift >= MinReflected) { Print("Сигнал ВНИЗ: Цена откатилась от максимума на ", pointsShift, " пт."); signalProcessed = true; // Здесь код для открытия сделки Sell } } } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { string comment = StringFormat(INDENT_FORMAT, TimeToString(TimeLocal(), TIME_MINUTES | TIME_SECONDS)); comment += lastProfitInfo; comment += actionsUsage; Comment(comment); } //+------------------------------------------------------------------+ //| Trade transaction function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { if(trans.type != TRADE_TRANSACTION_DEAL_ADD) { return; } InitLastProfits(); PlaySoundFile(SOUND_ENABLED, SOUND_FILE_NAME); } #include #undef MASTER_OF_PUPPETS_ACTION_KEY_MAPPINGS //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| ToDo | //| - error processing | //| - objects | //+------------------------------------------------------------------+