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:
-
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.
-
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").
-
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.
-
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.
-
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).
-
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
-
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.
-
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.
//+------------------------------------------------------------------+
//| |
//| 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 Formatting Guide
# H1
## H2
### H3
**bold text**
*italicized text*
[title](https://www.example.com)

`code`
```
code block
```
> blockquote
- Item 1
- Item 2
1. First item
2. Second item
---