Technical Logic Overview: Envelope 2.mq4
This document provides a non-technical explanation of the logic used by the "Envelope 2" trading script. The script is designed to automate trade entries, manage risk via dynamic lot sizing, and handle profit targets and trailing stops based on moving average envelopes.
1. Core Indicators
The script relies on three primary technical components to make decisions:
- Moving Average (MA): A base line used to determine the general trend of the market.
- Upper Envelope: A calculated boundary line above the moving average.
- Lower Envelope: A calculated boundary line below the moving average.
2. Trade Entry Logic
The script looks for specific price action relative to the Envelopes to place "Pending Orders" (orders that are only activated if the price hits a specific level).
Buy Opportunities
If the current market price is currently between the Upper and Lower Envelopes, the script places three separate Buy Stop orders:
- Order 1: Set to trigger at the Upper Envelope with a primary profit target.
- Order 2: Set to trigger at the Upper Envelope with a secondary profit target.
- Order 3: Set to trigger at the Upper Envelope with a third profit target.
Sell Opportunities
Similarly, if the price is between the Envelopes, the script places three Sell Stop orders:
- Order 1: Set to trigger at the Lower Envelope with a primary profit target.
- Order 2: Set to trigger at the Lower Envelope with a secondary profit target.
- Order 3: Set to trigger at the Lower Envelope with a third profit target.
3. Smart Risk Management
The script includes a sophisticated system for determining how much money to risk on each trade:
- Dynamic Lot Sizing: Instead of using a fixed amount, the script calculates the position size based on your account's available margin and a user-defined risk percentage.
- Loss Adjustment (Decrease Factor): If the script detects a string of recent losing trades in its history, it automatically reduces the size of subsequent trades. This is intended to protect the account balance during periods of poor market performance.
4. Trade Management & Trailing Stops
Once a trade is activated, the script manages it actively:
- Trailing Stop Loss: The script monitors the price as it moves in your favor. It can "trail" the stop-loss order to lock in profits by moving it along the Moving Average or the opposite Envelope (depending on user settings). This ensures that if a winning trade suddenly reverses, you keep a portion of the gains.
- Time Filters: The script only opens new trades during specific hours defined by the user.
- Auto-Cleanup: At the end of the trading day (based on the user's "Time Close" setting), any pending orders that were not triggered are automatically deleted to keep the workspace clean for the next session.
5. Summary of Operation Flow
- Analyze: Check current market price against Envelopes and check account history for losses.
- Calculate: Determine the safest trade size based on risk and recent performance.
- Execute: Place up to six pending orders (3 Buy, 3 Sell) at the Envelopes during allowed hours.
- Monitor: Move stop-losses automatically as price moves in favor of the trade.
- Cleanup: Delete unactivated orders and reset for the next cycle.
//+------------------------------------------------------------------+
//| Envelope 2.mq4 |
//| tageiger |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "tageiger"
#property link "http://www.metaquotes.net"
//---- input parameters
extern int Magic = 12000;
extern int EnvelopePeriod =144;
extern int EnvTimeFrame =0; //envelope time frame: 0=chart,60=1hr,240=4hr, etc.
extern int EnvMaMethod =1; //0=sma,1=ema,2=smma,3=lwma.
extern double EnvelopeDeviation =1;
extern int TimeOpen =0;
extern int TimeClose =23;
extern double FirstTP =89.0;
extern double SecondTP =144.0;
extern double ThirdTP =233.0;
extern double Lots =1;
extern double MaximumRisk =0.03;
extern double DecreaseFactor =3;
extern int MaElineTSL =0;//0=iMA trailing stoploss 1=Opposite Envelope TSL
int b1,b2,b3,s1,s2,s3;
double TSL =0;
//+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double LotsOptimized()
{
double lot=Lots;
int orders=HistoryTotal(); // history orders total
int losses=0; // number of losses orders without a break
//---- select lot size
lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//---- calcuulate number of losses orders without a break
if(DecreaseFactor>0)
{
for(int i=orders-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }
if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue;
//----
if(OrderProfit()>0) break;
if(OrderProfit()<0) losses++;
}
if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
}
//---- return lot size
if(lot<0.1) lot=0.1;
return(lot);
}
int start()
{
int p=0;p=EnvelopePeriod;
int etf=0;etf=EnvTimeFrame;
int mam=0;mam=EnvMaMethod;
double d=0;d=EnvelopeDeviation;
double btp1,btp2,btp3,stp1,stp2,stp3;
double bline=0,sline=0,ma=0;
int cnt, ticket, total;
int digit = MarketInfo(Symbol(),MODE_DIGITS);
ma=iMA(NULL,etf,p,0,mam,PRICE_CLOSE,0);
bline=iEnvelopes(NULL,etf,p,mam,0,PRICE_CLOSE,d,MODE_UPPER,0);
sline=iEnvelopes(NULL,etf,p,mam,0,PRICE_CLOSE,d,MODE_LOWER,0);
total=OrdersTotal();
if(OrdersTotal()==0)
{b1=0;b2=0;b3=0;s1=0;s2=0;s3=0;}
if(OrdersTotal()>0)
{
//Print("Total Orders:",OrdersTotal());
//Print(b1," ",b2," ",b3," ",s1," ",s2," ",s3);
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if(OrderMagicNumber()==Magic+2)
{b1=OrderTicket(); }
if(OrderMagicNumber()==Magic+4)
{b2=OrderTicket(); }
if(OrderMagicNumber()==Magic+6)
{b3=OrderTicket(); }
if(OrderMagicNumber()==Magic+1)
{s1=OrderTicket(); }
if(OrderMagicNumber()==Magic+3)
{s2=OrderTicket(); }
if(OrderMagicNumber()==Magic+5)
{s3=OrderTicket(); }
}
//Print ("magic=",OrderMagicNumber());
}
if(b1==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
btp1=(NormalizeDouble(bline,digit))+(FirstTP*Point);
ticket=OrderSend(Symbol(),
OP_BUYSTOP,
LotsOptimized(),
(NormalizeDouble(bline,digit)),
0,
(NormalizeDouble(sline,digit)),
btp1,
"",
Magic+2,
TimeClose,
Aqua);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
b1=ticket;
Print(ticket);
}
else Print("Error Opening BuyStop Order: ",GetLastError());
return(0);
}
}
}
}
if(b2==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
btp2=(NormalizeDouble(bline,digit))+(SecondTP*Point);
ticket=OrderSend(Symbol(),
OP_BUYSTOP,
LotsOptimized(),
(NormalizeDouble(bline,digit)),
0,
(NormalizeDouble(sline,digit)),
btp2,
"",
Magic+4,
TimeClose,
Aqua);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
b2=ticket;
Print(ticket);
}
else Print("Error Opening BuyStop Order: ",GetLastError());
return(0);
}
}
}
}
if(b3==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
btp3=(NormalizeDouble(bline,digit))+(ThirdTP*Point);
ticket=OrderSend(Symbol(),
OP_BUYSTOP,
LotsOptimized(),
(NormalizeDouble(bline,digit)),
0,
(NormalizeDouble(sline,digit)),
btp3,
"",
Magic+6,
TimeClose,
Aqua);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
b3=ticket;
Print(ticket);
}
else Print("Error Opening BuyStop Order: ",GetLastError());
return(0);
}
}
}
}
if(s1==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
stp1=NormalizeDouble(sline,digit)-(FirstTP*Point);
ticket=OrderSend(Symbol(),
OP_SELLSTOP,
LotsOptimized(),
(NormalizeDouble(sline,digit)),
0,
(NormalizeDouble(bline,digit)),
stp1,
"",
Magic+1,
TimeClose,
HotPink);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
s1=ticket;
Print(ticket);
}
else Print("Error Opening SellStop Order: ",GetLastError());
return(0);
}
}
}
}
if(s2==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
stp2=NormalizeDouble(sline,digit)-(SecondTP*Point);
ticket=OrderSend(Symbol(),
OP_SELLSTOP,
LotsOptimized(),
(NormalizeDouble(sline,digit)),
0,
(NormalizeDouble(bline,digit)),
stp2,
"",
Magic+3,
TimeClose,
HotPink);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
s2=ticket;
Print(ticket);
}
else Print("Error Opening SellStop Order: ",GetLastError());
return(0);
}
}
}
}
if(s3==0)
{
if(Hour()>TimeOpen && Hour()<TimeClose)
{
if(bline>Close[0] && sline<Close[0])
{
stp3=NormalizeDouble(sline,digit)-(ThirdTP*Point);
ticket=OrderSend(Symbol(),
OP_SELLSTOP,
LotsOptimized(),
(NormalizeDouble(sline,digit)),
0,
(NormalizeDouble(bline,digit)),
stp3,
"",
Magic+5,
TimeClose,
HotPink);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
s3=ticket;
Print(ticket);
}
else Print("Error Opening SellStop Order: ",GetLastError());
return(0);
}
}
}
}
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()==OP_BUY)
{
if(MaElineTSL==0) {TSL=NormalizeDouble(ma,digit); }
if(MaElineTSL==1) {TSL=NormalizeDouble(sline,digit); }
if(Close[0]>OrderOpenPrice())
{
if((Close[0]>sline) && (TSL>OrderStopLoss()))
{
double bsl;bsl=TSL;
OrderModify(OrderTicket(),
OrderOpenPrice(),
bsl,
OrderTakeProfit(),
0,//Order expiration server date/time
Green);
Sleep(10000);
}
}
}
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()==OP_SELL)
{
if(MaElineTSL==0) {TSL=NormalizeDouble(ma,digit); }
if(MaElineTSL==1) {TSL=NormalizeDouble(bline,digit); }
if(Close[0]<OrderOpenPrice())
{
if((Close[0]<bline) && (TSL<OrderStopLoss()))
{
double ssl;ssl=TSL;
OrderModify(OrderTicket(),
OrderOpenPrice(),
ssl,
OrderTakeProfit(),
0,//Order expiration server date/time
Red);
Sleep(10000);
}
}
}
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(Hour()==TimeClose && OrderType()==OP_BUYSTOP)
{
OrderDelete(OrderTicket());
if(OrderTicket()==b1) {b1=0; return;}
if(OrderTicket()==b2) {b2=0; return;}
if(OrderTicket()==b3) {b3=0; return;}
}
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(Hour()==TimeClose && OrderType()==OP_SELLSTOP)
{
OrderDelete(OrderTicket());
if(OrderTicket()==s1) {s1=0; return;}
if(OrderTicket()==s2) {s2=0; return;}
if(OrderTicket()==s3) {s3=0; return;}
}
OrderSelect(b1,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {b1=0;}
OrderSelect(b2,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {b2=0;}
OrderSelect(b3,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {b3=0;}
OrderSelect(s1,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {s1=0;}
OrderSelect(s2,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {s2=0;}
OrderSelect(s3,SELECT_BY_TICKET);
if(OrderClosePrice()>0) {s3=0;}
}
}
Comments