Generate code in 3 minutes
Enter your idea and AI generates runnable code.
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 that implements a Standard Deviation Channel (Linear Regression Channel) strategy.
This is a Mean Reversion strategy. It assumes that price moves within a statistical channel and tends to return to the center (Linear Regression Line).
//+------------------------------------------------------------------+
//| StdDevChannel_Strategy.mq4 |
//| Copyright 2023, MetaQuotes |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input string Strategy_Settings = "=== Strategy Settings ===";
input int ChannelPeriod = 50; // Linear Regression Period
input double ChannelDeviations = 2.0; // Standard Deviations for Bands
input int AppliedPrice = PRICE_CLOSE; // Applied Price (0=Close)
input string Risk_Settings = "=== Risk Management ===";
input double LotSize = 0.1; // Fixed Lot Size
input int StopLoss = 500; // Stop Loss in points (0 = disabled)
input int TakeProfit = 0; // Hard Take Profit in points (0 = disabled)
input int Slippage = 3; // Max Slippage in pips
input int MagicNumber = 123456; // Magic Number to identify trades
//--- Global Variables
double g_middleLine, g_upperLine, g_lowerLine;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(ChannelPeriod < 2)
{
Alert("Channel Period must be greater than 1");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Calculate Channel Data for the previous completed bar (Shift 1)
// We use Shift 1 to ensure the bar is closed and values are fixed (no repainting)
CalculateRegChannel(1);
// 2. Check for Exits (Mean Reversion)
ManageOpenTrades();
// 3. Check for Entries
// Only open if we have no open trades for this symbol/magic number
if(CountOpenTrades() == 0)
{
CheckEntryConditions();
}
}
//+------------------------------------------------------------------+
//| Calculate Linear Regression Channel Values |
//+------------------------------------------------------------------+
void CalculateRegChannel(int shift)
{
double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
// Linear Regression Calculation (Least Squares Method)
// X = Time index (0 to Period-1), Y = Price
for(int i = 0; i < ChannelPeriod; i++)
{
double price = iMA(NULL, 0, 1, 0, MODE_SMA, AppliedPrice, shift + i);
double x = i;
sumX += x;
sumY += price;
sumXY += x * price;
sumX2 += x * x;
}
double slope = (ChannelPeriod * sumXY - sumX * sumY) / (ChannelPeriod * sumX2 - sumX * sumX);
double intercept = (sumY - slope * sumX) / ChannelPeriod;
// The Regression value at the requested shift (x=0 in our local calculation loop relative to start)
g_middleLine = intercept + slope * 0;
// Calculate Standard Deviation relative to the Regression Line
double sumSqDiff = 0;
for(int i = 0; i < ChannelPeriod; i++)
{
double price = iMA(NULL, 0, 1, 0, MODE_SMA, AppliedPrice, shift + i);
double regValue = intercept + slope * i;
sumSqDiff += MathPow(price - regValue, 2);
}
double stdDev = MathSqrt(sumSqDiff / ChannelPeriod);
// Set Bands
g_upperLine = g_middleLine + (stdDev * ChannelDeviations);
g_lowerLine = g_middleLine - (stdDev * ChannelDeviations);
}
//+------------------------------------------------------------------+
//| Check Entry Conditions |
//+------------------------------------------------------------------+
void CheckEntryConditions()
{
double closePrice = iClose(NULL, 0, 1); // Close of previous bar
// Buy Signal: Price closed below the Lower Channel Line
if(closePrice < g_lowerLine)
{
double sl = (StopLoss > 0) ? Ask - StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? Ask + TakeProfit * Point : 0;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, sl, tp, "StdDev Buy", MagicNumber, 0, clrBlue);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
// Sell Signal: Price closed above the Upper Channel Line
if(closePrice > g_upperLine)
{
double sl = (StopLoss > 0) ? Bid + StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? Bid - TakeProfit * Point : 0;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, sl, tp, "StdDev Sell", MagicNumber, 0, clrRed);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Manage Open Trades (Exit Logic) |
//+------------------------------------------------------------------+
void ManageOpenTrades()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double closePrice = iClose(NULL, 0, 1);
bool closeOrder = false;
// Logic: Close Buy if price crosses back above Middle Line
if(OrderType() == OP_BUY)
{
if(closePrice >= g_middleLine) closeOrder = true;
}
// Logic: Close Sell if price crosses back below Middle Line
if(OrderType() == OP_SELL)
{
if(closePrice <= g_middleLine) closeOrder = true;
}
if(closeOrder)
{
bool result = false;
if(OrderType() == OP_BUY)
result = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrNONE);
else
result = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrNONE);
if(!result) Print("OrderClose failed with error #", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
//| Count Open Trades for this EA |
//+------------------------------------------------------------------+
int CountOpenTrades()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
Installation:
F4 to open the MetaEditor.New -> Expert Advisor (template) -> Name it StdDevChannel.F7 to Compile. Ensure there are no errors.Configuration (Inputs):
Logic Explanation:
CalculateRegChannel). It does not rely on drawing objects on the chart, making it faster and suitable for the Strategy Tester.Shift 1). If the previous bar closed outside the bands, it enters immediately on the new tick.Q: Why does the strategy use Shift 1 instead of Shift 0?
A: Shift 0 represents the current, forming bar. The price moves up and down constantly. If we use Shift 0, the signal might appear and disappear within the same candle (repainting), causing the EA to open trades that look invalid once the bar closes. Using Shift 1 ensures the price is locked in.
Q: Can I use this for Trend Following instead of Mean Reversion?
A: Yes, but you would need to invert the logic in the code. For trend following (breakouts), you would Buy when price > Upper Line and Sell when price < Lower Line. The current code is set up for Mean Reversion (Buy Low, Sell High).
Q: How is this different from Bollinger Bands?
A: Bollinger Bands use a Simple Moving Average (SMA) as the center line. This strategy uses a Linear Regression Line. Linear Regression attempts to fit a straight line through the data points to minimize error, often providing a better representation of the current "fair value" trend than a lagging SMA.