//+------------------------------------------------------------------+
//| InstantMomentumBot.mq5 |
//| Copyright 2026, AI Collaborator |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, AI Collaborator"
#property link "https://www.mql5.com"
#property version "1.10"
#property strict
#include <Trade\Trade.mqh>
CTrade trade;
//--- FIXED CONVERSION CONSTANT --------------------------------------
// The bot's SL / TP / Trailing inputs are expressed in "points" where
// 100 points always equals exactly a $1.00 move in price, regardless
// of the symbol's real tick size (_Point) or digits (_Digits).
// So: 1 "point" (as used by the inputs below) = $0.01 of price move.
#define FIXED_POINT_VALUE 0.01 // price movement represented by 1 point
//--- Input Parameters ---
input group "---- Risk Management (Points, 100 points = $1 move) ----"
input double InpStopLoss = 300.00; // Stop Loss in points (300 = $3.00)
input double InpTakeProfit = 200.00; // Take Profit in points (200 = $2.00)
input double InpTrailingStop = 50.00; // Trailing Stop in points (50 = $0.50)
input double InpLotSize = 0.1; // Lot Size
input group "---- Bot Settings ----"
input int InpMaxTrades = 1; // Maximum Number of Trades Allowed
input string InpTradeComment = "InstantBot"; // Custom Trade Comment
input ulong InpMagicNumber = 123456; // Magic Number
//--- Global Variables ---
double lastTickPrice = 0.0;
//+------------------------------------------------------------------+
//| Convert a "points" input (100 points = $1) into a price offset |
//+------------------------------------------------------------------+
double PointsToPriceOffset(double points)
{
// e.g. 300 points * 0.01 = 3.00 price units ($3.00 move)
return(points * FIXED_POINT_VALUE);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(InpMagicNumber);
// Set initial execution baseline price
lastTickPrice = SymbolInfoDouble(_Symbol, SYMBOL_LAST);
if(lastTickPrice == 0.0) lastTickPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
Print("Two-Step Execution Bot Initialized. Max trades: ", InpMaxTrades,
" | Point convention: 100 points = $1.00 move");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. First, apply SL/TP to positions that don't have them yet, and handle Trailing Stops
ManageStopsAndTrailing();
// 2. Get current real-time prices
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_LAST);
if(currentPrice == 0.0) currentPrice = bid;
if(lastTickPrice == 0.0)
{
lastTickPrice = currentPrice;
return;
}
// 3. Determine trade direction based on live velocity shift
bool priceIsMovingUp = (currentPrice > lastTickPrice);
bool priceIsMovingDown = (currentPrice < lastTickPrice);
// Update tracker variable immediately for the next tick
lastTickPrice = currentPrice;
// 4. CHECK MAXIMUM TRADES LIMIT
if(CountOpenPositions() >= InpMaxTrades)
{
return;
}
// 5. INSTANT EXECUTION (Two-Step Method: Open with 0 SL/TP first to comply with Market Execution)
if(priceIsMovingUp)
{
Print("Momentum UP detected. Executing Market BUY.");
if(!trade.Buy(InpLotSize, _Symbol, ask, 0, 0, InpTradeComment))
{
Print("BUY Order Rejected! Code: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
}
}
else if(priceIsMovingDown)
{
Print("Momentum DOWN detected. Executing Market SELL.");
if(!trade.Sell(InpLotSize, _Symbol, bid, 0, 0, InpTradeComment))
{
Print("SELL Order Rejected! Code: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
}
}
}
//+------------------------------------------------------------------+
//| Function to count active positions with our Magic Number |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol)
{
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Handles Step 2 (setting initial SL/TP) and Step 3 (Trailing) |
//+------------------------------------------------------------------+
void ManageStopsAndTrailing()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
ulong ticket = PositionGetTicket(i);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
// --- STEP A: SET INITIAL SL AND TP IF THEY ARE ZERO ---
if(currentSL == 0 && currentTP == 0)
{
if(type == POSITION_TYPE_BUY)
{
double targetSL = (InpStopLoss > 0) ? (openPrice - PointsToPriceOffset(InpStopLoss)) : 0;
double targetTP = (InpTakeProfit > 0) ? (openPrice + PointsToPriceOffset(InpTakeProfit)) : 0;
trade.PositionModify(ticket, NormalizeDouble(targetSL, _Digits), NormalizeDouble(targetTP, _Digits));
}
else if(type == POSITION_TYPE_SELL)
{
double targetSL = (InpStopLoss > 0) ? (openPrice + PointsToPriceOffset(InpStopLoss)) : 0;
double targetTP = (InpTakeProfit > 0) ? (openPrice - PointsToPriceOffset(InpTakeProfit)) : 0;
trade.PositionModify(ticket, NormalizeDouble(targetSL, _Digits), NormalizeDouble(targetTP, _Digits));
}
continue; // Move to next position, let it trail on subsequent ticks
}
// --- STEP B: TRAILING STOP MANAGEMENT ---
if(InpTrailingStop <= 0) continue;
double trailOffset = PointsToPriceOffset(InpTrailingStop);
if(type == POSITION_TYPE_BUY)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double newSL = bid - trailOffset;
if(bid > openPrice + trailOffset)
{
if(newSL > currentSL || currentSL == 0)
{
trade.PositionModify(ticket, NormalizeDouble(newSL, _Digits), NormalizeDouble(currentTP, _Digits));
}
}
}
else if(type == POSITION_TYPE_SELL)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double newSL = ask + trailOffset;
if(ask < openPrice - trailOffset)
{
if(newSL < currentSL || currentSL == 0)
{
trade.PositionModify(ticket, NormalizeDouble(newSL, _Digits), NormalizeDouble(currentTP, _Digits));
}
}
}
}
}
}