LSMA_Daily_EA_v1.1

Author: Robert Hill
Profit factor:
0.97

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:

  1. Waits for the right moment (the daily bar) to analyze the market.
  2. Looks at two trend lines (LSMAs) and sees if they've crossed, indicating a potential change in direction.
  3. Based on the direction, it either buys or sells a currency.
  4. While the trade is open, it watches the trend lines and closes the trade when they cross again, signaling a potential reversal.
  5. 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.

Price Data Components
Series array that contains close prices for each bar
Orders Execution
It automatically opens orders when conditions are reachedChecks for the total of open ordersIt Closes Orders by itself
5 Views
0 Downloads
0 Favorites
LSMA_Daily_EA_v1.1
//+------------------------------------------------------------------+
//|                                                                  |
//|                                          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);
   }
}


//+------------------------------------------------------------------+




Profitability Reports

GBP/AUD Jan 2025 - Jul 2025
1.18
Total Trades 16
Won Trades 8
Lost trades 8
Win Rate 50.00 %
Expected payoff 171.13
Gross Profit 17585.48
Gross Loss -14847.38
Total Net Profit 2738.10
-100%
-50%
0%
50%
100%
EUR/USD Jan 2025 - Jul 2025
1.36
Total Trades 20
Won Trades 9
Lost trades 11
Win Rate 45.00 %
Expected payoff 262.67
Gross Profit 19947.70
Gross Loss -14694.20
Total Net Profit 5253.50
-100%
-50%
0%
50%
100%
AUD/USD Jan 2025 - Jul 2025
0.26
Total Trades 20
Won Trades 8
Lost trades 12
Win Rate 40.00 %
Expected payoff -291.29
Gross Profit 2054.00
Gross Loss -7879.80
Total Net Profit -5825.80
-100%
-50%
0%
50%
100%
USD/CAD Oct 2024 - Jan 2025
1.15
Total Trades 9
Won Trades 3
Lost trades 6
Win Rate 33.33 %
Expected payoff 35.02
Gross Profit 2352.94
Gross Loss -2037.77
Total Net Profit 315.17
-100%
-50%
0%
50%
100%
NZD/USD Oct 2024 - Jan 2025
1.66
Total Trades 7
Won Trades 5
Lost trades 2
Win Rate 71.43 %
Expected payoff 150.51
Gross Profit 2649.20
Gross Loss -1595.60
Total Net Profit 1053.60
-100%
-50%
0%
50%
100%
GBP/USD Oct 2024 - Jan 2025
0.43
Total Trades 11
Won Trades 3
Lost trades 8
Win Rate 27.27 %
Expected payoff -352.74
Gross Profit 2888.80
Gross Loss -6768.90
Total Net Profit -3880.10
-100%
-50%
0%
50%
100%

Comments