LSMA_AnyTimeFrame_EA_v1.1

Author: Robert Hill

This script is designed to automatically trade currencies based on a specific strategy. Here's a breakdown of what it does:

Overall Purpose:

The script is an automated trading system (often called an "Expert Advisor" or EA) for the MetaTrader platform. It aims to automatically open and close trades based on the analysis of price data and a set of pre-defined rules.

Key Components and Logic:

  1. Initialization (init): When the script starts, it sets up its internal settings. This includes:

    • Calculating a unique "Magic Number" to identify its own trades and differentiate them from other scripts or manual trades. This number is based on the currency pair and the timeframe (e.g., 1-minute, 5-minute chart) the script is running on.
    • Defining a setup name for the expert advisor that can be used for reports and logging.
    • Setting other parameters based on user-defined settings.
  2. Least Squares Moving Average Calculation (LSMADaily):

    • This is the core of the trading strategy. It calculates a special kind of average price over a certain period (number of days). This average is "least squares," meaning it tries to fit a line to the price data and uses that line to determine the average.
    • The script uses two LSMAs with different periods: a shorter-period LSMA ("fast") and a longer-period LSMA ("slow").
  3. Entry Conditions (CheckEntryCondition):

    • This section determines when to open a new trade.
    • It compares the "fast" LSMA to the "slow" LSMA.
      • Buy Signal: If the "fast" LSMA crosses above the "slow" LSMA, it signals a potential buying opportunity. Optionally, this can be configured to only trigger a buy if the cross is "fresh" (i.e., the fast LSMA was below the slow LSMA on the previous bar).
      • Sell Signal: If the "fast" LSMA crosses below the "slow" LSMA, it signals a potential selling opportunity. The same "fresh cross" option is available.
  4. Exit Conditions (CheckExitCondition):

    • This section determines when to close an existing trade.
    • It again compares the "fast" LSMA to the "slow" LSMA.
      • Close Buy Order: If you have a buy order open, the script will close it if the "fast" LSMA falls below the "slow" LSMA.
      • Close Sell Order: If you have a sell order open, the script will close it if the "fast" LSMA rises above the "slow" LSMA.
  5. Money Management (GetLots, LotsOptimized):

    • This part determines how many "lots" (a standard unit of trading volume) to trade.
    • It can use a fixed lot size, or it can dynamically calculate the lot size based on the account balance or free margin (available funds) and a risk percentage. It also takes into account the type of account (micro, mini, or standard).
  6. Order Execution (OpenBuyOrder, OpenSellOrder):

    • If the entry conditions are met, this section opens a buy or sell order.
    • It sets the stop-loss (the price at which the trade will automatically close if it goes against you), take-profit (the price at which the trade will automatically close to lock in profit), and slippage (the maximum acceptable difference between the requested price and the actual price).
    • The script also normalizes the prices, stoploss and takeprofit to the proper number of decimal digits defined for the instrument you are trading
  7. Order Management (HandleOpenPositions, CheckOpenPositions):

    • HandleOpenPositions: The script checks all open trades that it initiated (identified by the "Magic Number"). If the exit conditions are met for any of these trades, it closes them.
    • CheckOpenPositions: The script counts how many trades it has open for the current currency pair to prevent opening multiple trades when the user has set the expert advisor to only allow one trade at a time.
  8. Main Loop (start):

    • This is the main function that runs repeatedly.
    • It first checks if it's a new bar (price movement period) to avoid running the same calculations multiple times on the same data.
    • Then, it checks for open positions and potentially closes them.
    • It then checks if the current month is within the allowed trading months.
    • Finally, it checks if there are already open trades for the current currency pair and, if not, checks the entry conditions to open a new trade.

In simpler terms:

Imagine this script as a robot trader that watches a currency chart. It calculates two different moving averages of the price. When the shorter-term average crosses the longer-term average in a certain direction, the robot either buys or sells the currency. It then waits for the averages to cross again in the opposite direction to close the trade. The robot also manages the risk by adjusting the size of the trades based on the account balance.

Important Considerations:

  • Customization: The script has many input parameters that can be adjusted to change the trading strategy and risk management settings.
  • Risk: Trading currencies involves significant risk, and this script is not a guaranteed way to make profits. It's essential to understand the strategy and risk management settings before using it.
  • Backtesting and Optimization: It's recommended to test the script on historical data ("backtesting") to see how it would have performed in the past and to optimize the settings for different currency pairs and market conditions.
  • Market Conditions: The effectiveness of the strategy may vary depending on market conditions.
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
4 Views
0 Downloads
0 Favorites
LSMA_AnyTimeFrame_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_AnyTF";
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    UseOncePerBar = 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,0,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 (UseOncePerBar == 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

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---