This script is designed to automatically trade on the Forex market using the MetaTrader platform. It follows a set of rules to decide when to buy (go long) or sell (go short) a particular currency pair. Here?s a breakdown of its logic:
1. Initialization:
- When the script starts, it sets up some key information, like a unique "Magic Number" to identify its trades and a comment to track the EA.
2. Core Trading Logic (The start()
Function):
- One Trade Per Bar: It checks if it has already run its calculations for the current day's trading bar. If so, it waits until the next day.
- Check for Open Positions: Looks for any existing trades that the script opened earlier and decides whether it's time to close any open trades according to the indicator exit logic described after.
- Monthly Trading Restriction: Checks if the current month is within the user-defined allowed trading months. If not, it will not trade in these months.
- Maximum One Trade at a Time: It makes sure there aren't any other open trades for the same currency pair before considering a new trade.
- Lot Size Calculation: It determines the size of the trade (how much of the currency to buy or sell). This can be a fixed amount or calculated based on the account size and risk percentage, always respecting the broker's requirements of minilot, microlot or fractional lots.
- Entry Condition Check: The script checks if the conditions are right to enter a trade. This involves calculating two Least Squares Moving Averages (LSMAs), a fast one and a slow one, using historical price data.
- Buy Condition: If the fast LSMA is above the slow LSMA, it considers buying. It can be set to only consider buying at the 'fresh cross' or it can buy if the fast LSMA is above the slow LSMA at all times.
- Sell Condition: If the fast LSMA is below the slow LSMA, it considers selling. It can be set to only consider selling at the 'fresh cross' or it can sell if the fast LSMA is below the slow LSMA at all times.
- Opening Orders: If the buy or sell conditions are met, it sends an order to the broker to open a trade, including details like the currency pair, trade size, stop loss (the price at which to automatically close the trade if it goes against you), and take profit (the price at which to automatically close the trade to secure a profit).
3. LSMA Calculation:
- The script uses a Least Squares Moving Average (LSMA) indicator. Essentially, this indicator draws a line that best fits the price data over a certain period (Short and Long Periods). It uses a linear regression model. This helps to identify the trend direction.
4. Exit Conditions:
- The script constantly monitors open trades. It determines when to close a trade based on the following:
- Buy Trade Exit: If, while a buy trade is open, the fast LSMA goes below the slow LSMA, it closes the buy trade.
- Sell Trade Exit: If, while a sell trade is open, the fast LSMA goes above the slow LSMA, it closes the sell trade.
5. Money Management:
- The script includes money management features, allowing you to specify a fixed lot size or calculate it based on a percentage of your account balance or free margin, thus controlling the amount of risk on each trade.
6. Utility Functions:
- The script uses utility functions to convert constants or symbols into a number.
In Simple Terms:
Imagine the script as a robot trader that:
- Waits for the right moment (the daily bar) to analyze the market.
- Looks at two trend lines (LSMAs) and sees if they've crossed, indicating a potential change in direction.
- Based on the direction, it either buys or sells a currency.
- While the trade is open, it watches the trend lines and closes the trade when they cross again, signaling a potential reversal.
- It carefully manages the size of each trade to limit risk.
This process continues automatically, aiming to profit from currency fluctuations while adhering to pre-defined rules and risk parameters.
//+------------------------------------------------------------------+
//| |
//| LSMA_Daily_wLog |
//| |
//| Written by Robert Hill aka MrPip for StrategyBuilder FX group |
//| |
//| 7/15/2007 Updated code and added log file |
//+------------------------------------------------------------------+
#property copyright "Robert Hill"
#property link "None"
#include <stdlib.mqh>
extern string Expert_Name = "LSMA_Daily";
extern int MagicNumberBase = 200000;
extern string UserComment = "LSMA_EA";
extern string in="---Indicator settings---";
extern int LSMAShortPeriod=7;
extern int LSMALongPeriod=16;
extern int MonthStart = 1;
extern int MonthEnd = 12;
extern bool UseFreshCross = true;
//+---------------------------------------------------+
//|Money Management |
//+---------------------------------------------------+
extern string mm = "---Money Management---";
extern double Lots=1.0;
extern double MaxLots = 100;
extern bool UseMoneyManagement = true; // Change to false to shutdown money management controls.
extern bool BrokerIsIBFX = false;
extern string m1="Set mini and micro to false for standard account";
extern bool AccountIsMini = false;
extern bool AccountIsMicro = false;
extern string fm="UseFreeMargin = false to use Account Balance";
extern bool UseFreeMargin = false;
extern double TradeSizePercent = 10; // Change to whatever percent of equity you wish to risk.
extern bool BrokerPermitsFractionalLots = true;
//+---------------------------------------------------+
//|Profit controls |
//+---------------------------------------------------+
extern string st6 = "--Profit Controls--";
extern double StopLoss=0;
extern double TakeProfit=0;
extern int Slippage=3;
extern string db0="---Flag to run start once per bar---";
extern string db1=" Set to false when using stoploss";
extern string db2=" takeprofit or trailing stop";
extern bool UseOncePerDailyBar = true;
//+---------------------------------------------------+
//|General controls |
//+---------------------------------------------------+
int MagicNumber=0;
string setup;
int TradesInThisSymbol = 0;
double mLots=0;
datetime timeprev = 0;
//+---------------------------------------------------+
//| Indicator values for signals and filters |
//| Add or Change to test your system |
//+---------------------------------------------------+
//+------------------------------------------------------------------+
//| Calculate MagicNumber, setup comment and assign RSI Period |
//| |
//+------------------------------------------------------------------+
int init()
{
MagicNumber = MagicNumberBase + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period());
setup=Expert_Name + Symbol() + "_" + func_TimeFrame_Val2String(func_TimeFrame_Const2Val(Period()));
setup = UserComment;
return(0);
}
int deinit()
{
return(0);
}
//+------------------------------------------------------------------------+
//| LSMA - Least Squares Moving Average function calculation |
//| LSMA_In_Color Indicator plots the end of the linear regression line |
//+------------------------------------------------------------------------+
double LSMADaily(int Rperiod, int shift)
{
int i;
double sum;
int length;
double lengthvar;
double tmp;
double wt;
length = Rperiod;
sum = 0;
for(i = length; i >= 1 ; i--)
{
lengthvar = length + 1;
lengthvar /= 3;
tmp = 0;
tmp = ( i - lengthvar)*iClose(NULL,1440,length-i+shift);
sum+=tmp;
}
wt = sum*6/(length*(length+1));
return(wt);
}
//+------------------------------------------------------------------+
//| CheckExitCondition |
//| Check if AngleSep cross 0 line |
//+------------------------------------------------------------------+
bool CheckExitCondition(int TradeType)
{
bool YesClose;
double L_Fast,L_Slow;
YesClose = false;
L_Fast=LSMADaily(LSMAShortPeriod,1);
L_Slow=LSMADaily(LSMALongPeriod,1);
if (TradeType == OP_BUY)
{
if (L_Fast < L_Slow) YesClose = true;
}
if (TradeType == OP_SELL)
{
if (L_Fast > L_Slow) YesClose = true;
}
return (YesClose);
}
//+------------------------------------------------------------------+
//| CheckEntryCondition |
//| Check if separation on LSMA pair |
//+------------------------------------------------------------------+
bool CheckEntryCondition(int TradeType)
{
bool YesTrade;
double L_Fast,L_Slow;
double L_FastPrev,L_SlowPrev;
L_Fast=LSMADaily(LSMAShortPeriod,1);
L_Slow=LSMADaily(LSMALongPeriod,1);
YesTrade = false;
if (TradeType == OP_BUY)
{
if ( L_Fast > L_Slow)
{
if (UseFreshCross == true)
{
L_FastPrev=LSMADaily(LSMAShortPeriod,2);
L_SlowPrev=LSMADaily(LSMALongPeriod,2);
if (L_FastPrev < L_SlowPrev) YesTrade = true; else YesTrade = false;
}
else
YesTrade = true;
}
}
if (TradeType == OP_SELL)
{
if ( L_Fast < L_Slow)
{
if (UseFreshCross == true)
{
L_FastPrev=LSMADaily(LSMAShortPeriod,2);
L_SlowPrev=LSMADaily(LSMALongPeriod,2);
if (L_FastPrev > L_SlowPrev) YesTrade = true; else YesTrade = false;
}
else
YesTrade = true;
}
}
return (YesTrade);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Start |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int start()
{
// Only run once per completed bar
if (UseOncePerDailyBar == true)
{
if(timeprev==Time[0]) return(0);
timeprev = Time[0];
}
//+------------------------------------------------------------------+
//| Check for Open Position |
//+------------------------------------------------------------------+
HandleOpenPositions();
if (Month() < MonthStart) return(0);
if (Month() > MonthEnd) return(0);
// Check if any open positions were not closed
TradesInThisSymbol = CheckOpenPositions();
// Only allow 1 trade per Symbol
if(TradesInThisSymbol > 0) {
return(0);}
mLots = GetLots();
if(CheckEntryCondition(OP_BUY) == true)
{
OpenBuyOrder(mLots, StopLoss,TakeProfit, Slippage, setup, MagicNumber, Green);
return(0);
}
if(CheckEntryCondition(OP_SELL) == true)
{
OpenSellOrder(mLots, StopLoss,TakeProfit, Slippage, setup, MagicNumber, Red);
}
return(0);
}
//+------------------------------------------------------------------+
//| Get number of lots for this trade |
//+------------------------------------------------------------------+
double GetLots()
{
double lot;
if(UseMoneyManagement == true)
{
lot = LotsOptimized();
}
else
{
lot = Lots;
}
// Use at least 1 micro lot
if (AccountIsMicro == true)
{
if (lot < 0.01) lot = 0.01;
if (lot > MaxLots) lot = MaxLots * 100;
if (BrokerIsIBFX == true) lot = lot * 10;
return(lot);
}
// Use at least 1 mini lot
if(AccountIsMini == true)
{
if (lot < 0.1) lot = 0.1;
if (lot > MaxLots) lot = MaxLots;
if (BrokerIsIBFX == true) lot = lot * 10;
return(lot);
}
// Standard account
if( BrokerPermitsFractionalLots == false)
{
if (lot >= 1.0) lot = MathFloor(lot); else lot = 1.0;
}
if (lot > MaxLots) lot = MaxLots;
return(lot);
}
//+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double LotsOptimized()
{
double lot=Lots;
//---- select lot size
if (UseFreeMargin == true)
lot=NormalizeDouble(MathFloor(AccountFreeMargin()*TradeSizePercent/10000)/10,1);
else
lot=NormalizeDouble(MathFloor(AccountBalance()*TradeSizePercent/10000)/10,1);
// Check if mini or standard Account
if(AccountIsMini == true)
{
lot = MathFloor(lot*10)/10;
}
return(lot);
}
//+------------------------------------------------------------------+
//| OpenBuyOrder |
//| If Stop Loss or TakeProfit are used the values are calculated |
//| for each trade |
//+------------------------------------------------------------------+
int OpenBuyOrder(double mLots, double mStopLoss, double mTakeProfit, int mSlippage, string mComment, int mMagic, color mColor)
{
int err,ticket;
double myPrice, myStopLoss = 0, myTakeProfit = 0;
RefreshRates();
myStopLoss = StopLong(Bid,mStopLoss);
myTakeProfit = TakeLong(Bid,mTakeProfit);
// Normalize all price / stoploss / takeprofit to the proper # of digits.
if (Digits > 0)
{
myPrice = NormalizeDouble( Ask, Digits);
myStopLoss = NormalizeDouble( myStopLoss, Digits);
myTakeProfit = NormalizeDouble( myTakeProfit, Digits);
}
ticket=OrderSend(Symbol(),OP_BUY,mLots,myPrice,mSlippage,myStopLoss,myTakeProfit,mComment,mMagic,0,mColor);
if (ticket > 0)
{
if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) )
{
Print("BUY order opened : ", OrderOpenPrice( ));
// ModifyOrder(ticket,OrderOpenPrice( ), OrderStopLoss(), myTakeProfit);
}
}
else
{
err = GetLastError();
if(err==0)
{
return(ticket);
}
else
{
if(err==4 || err==137 ||err==146 || err==136) //Busy errors
{
Sleep(5000);
}
else //normal error
{
Print("Error opening BUY order [" + setup + "]: (" + err + ") " + ErrorDescription(err));
}
}
}
return(ticket);
}
//+------------------------------------------------------------------+
//| OpenSellOrder |
//| If Stop Loss or TakeProfit are used the values are calculated |
//| for each trade |
//+------------------------------------------------------------------+
void OpenSellOrder(double mLots, double mStopLoss, double mTakeProfit, int mSlippage, string mComment, int mMagic, color mColor)
{
int err, ticket;
double myPrice, myStopLoss = 0, myTakeProfit = 0;
RefreshRates();
myStopLoss = StopShort(Ask,mStopLoss);
myTakeProfit = TakeShort(Ask,mTakeProfit);
// Normalize all price / stoploss / takeprofit to the proper # of digits.
if (Digits > 0)
{
myPrice = NormalizeDouble( Bid, Digits);
myStopLoss = NormalizeDouble( myStopLoss, Digits);
myTakeProfit = NormalizeDouble( myTakeProfit, Digits);
}
ticket=OrderSend(Symbol(),OP_SELL,mLots,myPrice,mSlippage,myStopLoss,myTakeProfit,mComment,mMagic,0,mColor);
if (ticket > 0)
{
if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) )
{
Print("Sell order opened : ", OrderOpenPrice());
// ModifyOrder(ticket,OrderOpenPrice( ), OrderStopLoss(), myTakeProfit);
}
}
else
{
err = GetLastError();
if(err==0)
{
return(ticket);
}
else
{
if(err==4 || err==137 ||err==146 || err==136) //Busy errors
{
Sleep(5000);
}
else //normal error
{
Print("Error opening Sell order [" + mComment + "]: (" + err + ") " + ErrorDescription(err));
}
}
}
return(ticket);
}
double StopLong(double price,int stop)
{
if(stop==0)
return(0);
else
return(price-(stop*Point));
}
double StopShort(double price,int stop)
{
if(stop==0)
return(0);
else
return(price+(stop*Point));
}
double TakeLong(double price,int take)
{
if(take==0)
return(0);
else
return(price+(take*Point));
}
double TakeShort(double price,int take)
{
if(take==0)
return(0);
else
return(price-(take*Point));
}
//+------------------------------------------------------------------+
//| Handle Open Positions |
//| Check if any open positions need to be closed or modified |
//+------------------------------------------------------------------+
int HandleOpenPositions()
{
int cnt;
for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
{
OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
if ( OrderSymbol() != Symbol()) continue;
if ( OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == OP_BUY)
{
if (CheckExitCondition(OP_BUY) == true)
{
CloseOrder(OrderTicket(),OrderOpenPrice(),OrderLots(),OP_BUY);
}
}
if(OrderType() == OP_SELL)
{
if (CheckExitCondition(OP_SELL) == true)
{
CloseOrder(OrderTicket(),OrderOpenPrice(), OrderLots(),OP_SELL);
}
}
}
}
//+------------------------------------------------------------------+
//| Check Open Position Controls |
//+------------------------------------------------------------------+
int CheckOpenPositions()
{
int cnt, total;
int NumTrades;
NumTrades = 0;
total=OrdersTotal();
for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
{
OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES);
if ( OrderSymbol() != Symbol()) continue;
if ( OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == OP_BUY ) NumTrades++;
if(OrderType() == OP_SELL ) NumTrades++;
}
return (NumTrades);
}
int CloseOrder(int ticket, double op, double numLots,int cmd)
{
int CloseCnt, err, digits;
double myPrice;
string olStr, bidStr, askStr;
RefreshRates();
if (cmd == OP_BUY) myPrice = Bid;
if (cmd == OP_SELL) myPrice = Ask;
if (Digits > 0) myPrice = NormalizeDouble( myPrice, Digits);
olStr = DoubleToStr(numLots,2);
bidStr = DoubleToStr(Bid, Digits);
askStr = DoubleToStr(Ask, Digits);
// try to close 3 Times
CloseCnt = 0;
while (CloseCnt < 3)
{
if (OrderClose(ticket,numLots,myPrice,Slippage,Violet) == false)
{
err=GetLastError();
Print(CloseCnt," Error closing order : (", err , ") " + ErrorDescription(err));
if (err > 0) CloseCnt++;
}
else
{
CloseCnt = 3;
}
}
}
int func_Symbol2Val(string symbol)
{
string mySymbol = StringSubstr(symbol,0,6);
if(mySymbol=="AUDCAD") return(1);
if(mySymbol=="AUDJPY") return(2);
if(mySymbol=="AUDNZD") return(3);
if(mySymbol=="AUDUSD") return(4);
if(mySymbol=="CHFJPY") return(5);
if(mySymbol=="EURAUD") return(6);
if(mySymbol=="EURCAD") return(7);
if(mySymbol=="EURCHF") return(8);
if(mySymbol=="EURGBP") return(9);
if(mySymbol=="EURJPY") return(10);
if(mySymbol=="EURUSD") return(11);
if(mySymbol=="GBPCHF") return(12);
if(mySymbol=="GBPJPY") return(13);
if(mySymbol=="GBPUSD") return(14);
if(mySymbol=="NZDJPY") return(15);
if(mySymbol=="NZDUSD") return(16);
if(mySymbol=="USDCAD") return(17);
if(mySymbol=="USDCHF") return(18);
if(mySymbol=="USDJPY") return(19);
Comment("unexpected Symbol");
return(999);
}
//+------------------------------------------------------------------+
//| Time frame interval appropriation function |
//+------------------------------------------------------------------+
int func_TimeFrame_Const2Val(int Constant ) {
switch(Constant) {
case 1: // M1
return(1);
case 5: // M5
return(2);
case 15:
return(3);
case 30:
return(4);
case 60:
return(5);
case 240:
return(6);
case 1440:
return(7);
case 10080:
return(8);
case 43200:
return(9);
}
}
//+------------------------------------------------------------------+
//| Time frame string appropriation function |
//+------------------------------------------------------------------+
string func_TimeFrame_Val2String(int Value ) {
switch(Value) {
case 1: // M1
return("PERIOD_M1");
case 2: // M1
return("PERIOD_M5");
case 3:
return("PERIOD_M15");
case 4:
return("PERIOD_M30");
case 5:
return("PERIOD_H1");
case 6:
return("PERIOD_H4");
case 7:
return("PERIOD_D1");
case 8:
return("PERIOD_W1");
case 9:
return("PERIOD_MN1");
default:
return("undefined " + Value);
}
}
//+------------------------------------------------------------------+
Comments