Problem Description
Solution
Here is a complete, fully commented MQL4 Expert Advisor (bot) that implements a Straddle Strategy.
Strategy Logic
- Time Calculation: The bot calculates the target time for the current day based on your inputs (Hour and Minute).
- Trigger: It subtracts 5 minutes (configurable) from that target time.
- Execution: When the server time reaches the trigger time, the bot places two pending orders:
- Buy Stop: Placed at
Ask + Distance. - Sell Stop: Placed at
Bid - Distance.
- Buy Stop: Placed at
- Safety: It includes a mechanism to ensure orders are placed only once per day to prevent duplicate trades.
MQL4 Code
//+------------------------------------------------------------------+
//| NewsStraddleBot.mq4 |
//| Copyright 2023, Quantitative Trading AI |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative Trading AI"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input string TimeSettings = "=== Time Settings ===";
input int TargetHour = 14; // Target Hour (Server Time, e.g., 14 for 14:30)
input int TargetMinute = 30; // Target Minute (e.g., 30 for 14:30)
input int MinutesBefore= 5; // How many minutes before target to place orders
input string TradeSettings = "=== Trade Settings ===";
input double DistancePips = 20; // Distance from current price in Pips
input double LotSize = 0.1; // Volume in Lots
input double StopLoss = 30; // Stop Loss in Pips (0 = No SL)
input double TakeProfit = 60; // Take Profit in Pips (0 = No TP)
input int ExpirationMin= 60; // Order expiration in minutes (0 = No expiration)
input int MagicNumber = 123456; // Unique ID for this EA's orders
input int Slippage = 3; // Max slippage allowed
//--- Global Variables
bool ordersPlacedToday = false;
int lastDayChecked = 0;
double pPoint; // Adjusted point value for 3/5 digit brokers
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust point value for 5-digit and 3-digit brokers
if(Digits == 5 || Digits == 3) pPoint = Point * 10;
else pPoint = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Reset the flag if it is a new day
if(Day() != lastDayChecked)
{
ordersPlacedToday = false;
lastDayChecked = Day();
}
// 2. If orders are already placed today, stop processing
if(ordersPlacedToday) return;
// 3. Calculate Target Time and Trigger Time for TODAY
datetime now = TimeCurrent();
// Construct the string for the target time (YYYY.MM.DD HH:MI)
string dateStr = StringFormat("%d.%02d.%02d", Year(), Month(), Day());
string timeStr = StringFormat("%02d:%02d", TargetHour, TargetMinute);
datetime targetTime = StrToTime(dateStr + " " + timeStr);
// Calculate the trigger time (Target - MinutesBefore)
datetime triggerTime = targetTime - (MinutesBefore * 60);
// 4. Check if current time is within the execution window
// We check if 'now' is past the trigger time AND 'now' is not too late (e.g., passed the news event)
if(now >= triggerTime && now < targetTime)
{
PlaceStraddleOrders();
ordersPlacedToday = true; // Mark as done for the day
}
}
//+------------------------------------------------------------------+
//| Helper function to place the orders |
//+------------------------------------------------------------------+
void PlaceStraddleOrders()
{
double buyStopPrice = Ask + (DistancePips * pPoint);
double sellStopPrice = Bid - (DistancePips * pPoint);
// Normalize prices to prevent errors
buyStopPrice = NormalizeDouble(buyStopPrice, Digits);
sellStopPrice = NormalizeDouble(sellStopPrice, Digits);
// Calculate SL and TP for Buy Stop
double buySL = (StopLoss > 0) ? buyStopPrice - (StopLoss * pPoint) : 0;
double buyTP = (TakeProfit > 0) ? buyStopPrice + (TakeProfit * pPoint) : 0;
// Calculate SL and TP for Sell Stop
double sellSL = (StopLoss > 0) ? sellStopPrice + (StopLoss * pPoint) : 0;
double sellTP = (TakeProfit > 0) ? sellStopPrice - (TakeProfit * pPoint) : 0;
// Normalize SL/TP
buySL = NormalizeDouble(buySL, Digits);
buyTP = NormalizeDouble(buyTP, Digits);
sellSL = NormalizeDouble(sellSL, Digits);
sellTP = NormalizeDouble(sellTP, Digits);
// Calculate Expiration Time
datetime expireTime = 0;
if(ExpirationMin > 0) expireTime = TimeCurrent() + (ExpirationMin * 60);
// --- Send Buy Stop ---
int ticketBuy = OrderSend(Symbol(), OP_BUYSTOP, LotSize, buyStopPrice, Slippage, buySL, buyTP, "Straddle Buy", MagicNumber, expireTime, clrGreen);
if(ticketBuy < 0)
{
Print("Error placing Buy Stop: ", GetLastError());
}
else
{
Print("Buy Stop placed at: ", buyStopPrice);
}
// --- Send Sell Stop ---
int ticketSell = OrderSend(Symbol(), OP_SELLSTOP, LotSize, sellStopPrice, Slippage, sellSL, sellTP, "Straddle Sell", MagicNumber, expireTime, clrRed);
if(ticketSell < 0)
{
Print("Error placing Sell Stop: ", GetLastError());
}
else
{
Print("Sell Stop placed at: ", sellStopPrice);
}
}
//+------------------------------------------------------------------+
How to Install and Use
- Open MetaEditor: In MT4, press
F4. - Create New File: Click "New" -> "Expert Advisor (template)" -> Name it "NewsStraddle" -> Finish.
- Paste Code: Delete everything in the new file and paste the code provided above.
- Compile: Press
F7or click the "Compile" button. Ensure there are no errors in the "Errors" tab at the bottom. - Setup in MT4:
- Go back to the main MT4 window.
- Find "NewsStraddle" in the Navigator pane under "Expert Advisors".
- Drag it onto the chart you want to trade (e.g., EURUSD).
- Configure Inputs:
- TargetHour/TargetMinute: Set this to the specific event time (e.g., if Non-Farm Payroll is at 15:30 Server Time, set Hour=15, Minute=30).
- MinutesBefore: Set to
5. - DistancePips: How far away from the current price the pending orders should be placed.
- Enable Trading: Make sure the "AutoTrading" button at the top of MT4 is green and the smiley face in the top-right corner of the chart is smiling.
Key Features of This Code
- Server Time Sync: It uses
TimeCurrent()(Broker Server Time), not your local computer time. This is crucial for accurate trading. Note: You must check your broker's time zone offset. - 5-Digit Broker Support: The variable
pPointautomatically adjusts calculations so that "20 pips" works correctly on both 4-digit and 5-digit brokers. - One-Shot Execution: The
ordersPlacedTodayflag ensures that once the orders are placed, the bot won't try to place them again until the next day. - Expiration: The
ExpirationMininput allows the pending orders to automatically delete themselves if the price doesn't move enough to trigger them within the specified time (e.g., 60 minutes).
Q&A
Q: Why does the bot use TimeCurrent() instead of TimeLocal()?
A: TimeCurrent() returns the time of the last known quote from the broker's server. This is the time displayed in the Market Watch window. Using local computer time (TimeLocal()) is dangerous because it may not match the broker's candle closing times or news event schedules.
Q: What happens if I restart the terminal after the orders are placed?
A: The global variable ordersPlacedToday is stored in memory. If you restart the terminal, this variable resets to false. However, the logic checks if(now >= triggerTime && now < targetTime). If you restart the terminal after the target time has passed, the bot will not place duplicate orders because the time condition will fail.
Q: Can I use this on multiple currency pairs simultaneously?
A: Yes, but you must change the MagicNumber input for each chart. The Magic Number allows the EA to identify which orders belong to which instance of the strategy. If they share the same number, they might interfere with each other's management logic (though this specific code only places orders and doesn't manage them after placement).
Q: Why did I get "Error 130" in the Journal?
A: Error 130 is ERR_INVALID_STOPS. This usually happens if your DistancePips is too small (inside the broker's "Freeze Level") or if the Stop Loss calculation places the SL on the wrong side of the price. The provided code calculates SL correctly relative to the pending order price, so ensure your DistancePips is at least 5-10 pips.