This script is designed to automate trading on the Forex market using the MetaTrader platform. Here's a breakdown of its logic, avoiding technical jargon:
Overall Goal:
The script aims to automatically open and close buy (long) and sell (short) positions based on a combination of technical indicators. It attempts to identify potentially profitable trading opportunities based on these indicators and manage risk by adjusting trade sizes and setting stop-loss levels.
Key Components & Logic:
-
Initialization (
init()
):- When the script starts, it prepares a file ("StarterDebug.csv") to record the decisions it makes. This is like a trading diary, noting the time, whether it bought or sold, and the values of the different indicators it used.
-
Deinitialization (
deinit()
):- When the script stops, it closes the trading diary file.
-
Lot Size Optimization (
LotsOptimized()
):- This part determines the size of each trade. It starts with a base lot size (defined by the user as "Lots").
- Risk Management: It adjusts the lot size based on the account's available funds ("AccountFreeMargin") and a risk percentage ("MaximumRisk"). It aims to risk only a small portion of the account on any single trade.
- Loss Recovery (Optional): If the script has experienced a series of losing trades, it can reduce the lot size even further to minimize potential future losses. This reduction is controlled by "DecreaseFactor".
- It ensures the lot size stays within reasonable limits (1 to 1000).
-
Laguerre Filter Calculation (
LaGuerre()
):- This is a special indicator that smooths out price data to better identify trends. It's similar to calculating a moving average, but uses a more advanced formula based on a "Gamma" parameter.
- It calculates a "Relative Strength Index (RSI)" based on the smoothed price data, which helps determine if the market is overbought or oversold.
-
Main Trading Logic (
start()
):- Indicator Values:
- It gathers the current values of several technical indicators:
- Laguerre Filter: A smoothed price indicator, calculated with the "LaGuerre()" function.
- CCI (Commodity Channel Index): An indicator that measures the current price level relative to an average price level over a period of time. It helps identify overbought or oversold conditions. Two CCI values are used, one from the current bar and one from the previous bar, to determine if the CCI is rising or falling.
- MA (Moving Average): An indicator that calculates the average price over a specific period. Two MA values from two consecutive bars determine if the price is trending upwards or downwards.
- It gathers the current values of several technical indicators:
- Order Management:
- It checks how many trades the script has currently opened on the trading pair.
- Trading Conditions (Opening New Trades):
- Before opening a new trade, it checks if there are enough funds in the account to cover the potential trade.
- The script uses a set of rules based on the indicators to decide whether to buy or sell:
- Buy (Long) Conditions: It looks for a combination of:
- Laguerre filter reading of 0
- A rising Moving Average (MA).
- A rising CCI.
- CCI crossing a defined negative level from below.
- A rate of CCI change that is higher than a defined percentage.
- Sell (Short) Conditions: It looks for a combination of:
- Laguerre filter reading of 1
- A falling Moving Average (MA).
- A falling CCI.
- CCI crossing a defined positive level from above.
- A rate of CCI change that is higher than a defined percentage.
- Buy (Long) Conditions: It looks for a combination of:
- If all conditions are met for a buy or sell, it places an order:
- It calculates the lot size using the "LotsOptimized()" function.
- It uses the
OrderSend()
function to send the order to the trading platform. - It sets a stop-loss order (optional) to limit potential losses.
- Trade Management (Closing Existing Trades):
- The script then scans through all currently open trades that it opened itself (identified by a "MagicNumber").
- Closing Conditions:
- If the trade is a buy (long) position, it checks:
- If the Laguerre filter rises above a specific level, it closes the buy position.
- If the price has moved in the wrong direction by a certain amount ("Stop"), it closes the buy position (stop-loss).
- If the trade is a sell (short) position, it checks:
- If the Laguerre filter falls below a specific level, it closes the sell position.
- If the price has moved in the wrong direction by a certain amount ("Stop"), it closes the sell position (stop-loss).
- If the trade is a buy (long) position, it checks:
- Indicator Values:
In simpler terms: The script is like a robot trader that watches price charts and indicators. When it sees certain patterns that it thinks are favorable, it automatically buys or sells. It also has rules to protect itself from losing too much money, and it will close trades when it thinks the opportunity is over. The Laguerre filter is used to smooth the price and help define better buying and selling times.
//+------------------------------------------------------------------+
//| Starter.mq4 |
//| Copyright © 2005, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
//#include <Tracert.mqh>
extern double Lots = 0.1;
extern double MaximumRisk = 0.03;
extern double DecreaseFactor = 3;
extern int Stop = 10;
extern int SL = 0; //Äëÿ "ýñòåòîâ" èç ôîðóìó StopLoss
//extern double Lots = 4;
//Ïàðàìåòðû Laguerre
extern double GammaP = 0.7; //Íåêàÿ "Ãàììà" èç ïàðàìåòðîâ "Laguerre"
extern double StopL = 0.1; //"Ïîðîã" "Laguerre" äëÿ çàêðûòèÿ ïîçèöèè
extern int ShftL = 0; //Áàð, íà êîòîðîì ðàññ÷èòûâàåòñÿ "Laguerre"
//Ïàðàìåòðû CCI
extern int CCIperiod = 14; //Ñîáñòâåííî ïåðèîä CCI
extern int TypeCCI = 0; //"Öåíîâûå êîíñòàíòû" äëÿ ðàñ÷òåèà CCI 0-Close, 1-Open, 2-High, 3-Low, 4-Median, 5-Typical, 6-WEIGHTED
extern int DAlpha = 0; //Äåëüòà CCI - "ïîðîã èçìåíåíèÿ ñêîðîñòè CCI" â ïðîöåíòàõ
extern int CCILevel = 100; //Êëàññè÷åñêè - óðîâåíü, êîòîðûé äîëæíà ïåðåñå÷ü CCI, ÷òîáû äàòü ñèãíàë. Êëàññèêà +/-100, 0, â îðèãèíàëáíîì starter'å +/-5. ß çàêîììåíòèðîâàë, ò.ê.....
extern int ShftA1 = 0; //Áàð äëÿ ðàñ÷åòà "òåêóùåé" CCI
extern int ShftA2 = 1; //Áàð äëÿ ðàñ÷åòà "ïðåäûäóùåé" CCI
//Ïàðàìåòðû MA
extern double MAPeriod = 120; //Ñîáñòâåííî ïåðèîä MA
extern int TypeMA = 0; //"Öåíîâûå êîíñòàíòû" äëÿ ðàñ÷òåèà MA 0-Close, 1-Open, 2-High, 3-Low, 4-Median, 5-Typical, 6-WEIGHTED
extern int ShftMA = 0; //Áàð äëÿ ðàñ÷åòà "òåêóùåé" MA (Áàð äëÿ "ïðåäûäóùåé" MA = ShftMA+1 (â îòëè÷èè îò CCI))
extern double DeltaMA = 0.1; //Äåëüòà MA ("òåêóùåãî" è "ïðåäûäóùåãî" áàðà) â "ïèïñàõ" :)
//MagicNubber
extern int MagicNumber = 20051016; //ß âñåãäà âûíîøó âñåãäà, ÷òîáû ìîæíî áûëî, ÍÀÏÐÈÌÅÐ, òîðãîâàòü íà îäíîé ïàðå ñ ðàçíûìè ïàðàìåòðàìè :)
int handle;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
handle = FileOpen("StarterDebug.csv", FILE_CSV | FILE_WRITE);
FileWrite(handle, "Time[0]", "TradeType", "Laguerre", "MA", "MA1", "DMA", "Alpha1", "Alpha2", "DAlpha");
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
FileClose(handle);
//----
return(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/500,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<1) lot=1;
if(lot>1000) lot=1000;
return(lot);
}
double LaGuerre(double gamma, int shift)
{
double RSI;
double L0[100];
double L1[100];
double L2[100];
double L3[100];
double CU, CD;
for (int i=shift+99; i>=shift; i--)
{
L0[i] = (1.0 - gamma)*Close[i] + gamma*L0[i+1];
L1[i] = -gamma*L0[i] + L0[i+1] + gamma*L1[i+1];
L2[i] = -gamma*L1[i] + L1[i+1] + gamma*L2[i+1];
L3[i] = -gamma*L2[i] + L2[i+1] + gamma*L3[i+1];
CU = 0;
CD = 0;
if (L0[i] >= L1[i]) CU = L0[i] - L1[i];
else CD = L1[i] - L0[i];
if (L1[i] >= L2[i]) CU = CU + L1[i] - L2[i];
else CD = CD + L2[i] - L1[i];
if (L2[i] >= L3[i]) CU = CU + L2[i] - L3[i];
else CD = CD + L3[i] - L2[i];
if (CU + CD != 0) RSI = CU / (CU + CD);
}
return(RSI);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
double Laguerre;
double SLstop;
double Alpha1, Alpha2;
double MA, MA1;
//+-- double Juice;
int cnt, ticket, RealTotal, total;
// Laguerre=iCustom(NULL, 0, "Laguerre", 0, 0);
Laguerre=LaGuerre(GammaP, 0);
Alpha1=iCCI(NULL, 0, CCIperiod, TypeCCI, ShftA1);
Alpha2=iCCI(NULL, 0, CCIperiod, TypeCCI, ShftA2);
MA=iMA(NULL,0,MAPeriod,0,MODE_EMA,TypeMA,ShftMA);
MA1=iMA(NULL,0,MAPeriod,0,MODE_EMA,TypeMA,ShftMA+1);
//+-- Juice=iCustom(NULL,0,"Juice",0,0);
total=OrdersTotal();
//Èùåì ðåàëüíîå ÷èëî òðãîâûõ îðäåðîâ äëÿ íàøåãî MagicNumber íà íàøåé ïàðå (÷òîáû äàòü òîðãîâàòü ñåáå è äðóãèì ñîâåòíèêàì)
for (cnt = 0; cnt < total; cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
RealTotal = RealTotal + 1;
}
if(RealTotal<1)
{
// no opened orders identified
if(AccountFreeMargin()<(1000*Lots))
{
Print("We have no money. Free Margin = ", AccountFreeMargin());
return(0);
}
// check for long position (BUY) possibility
if(
//Èç "îðèãèíàëà"
(Laguerre==0)
&& //Íå ïðîñòî ðîñò MA, íî è ìèíèìóì íåêîòîðóþ äåëüòó
(MA-MA1 > DeltaMA * Point)
&& //Ðîñò CCI
(Alpha2 < Alpha1)
&& //Ïåðåñå÷åíèå íåêîòîðîãî óðîâíÿ +/-100, 0 "Ñíèçó-ââåðõ"
(Alpha1 > -1 * CCILevel && Alpha2 < -1 * CCILevel)
// && // îðèãèíàëå (åñëè ÷åñòíî - íå ïîíÿë. ÈÌÕÎ èìåëîñü ââèäó ïåðåñå÷åíèå (èëè "ïîäõîä" ê) 0, íî, åñëè ñìîòðåòü îòëàäî÷íûé ôàéë, òî òàì ....
// (Alpha1 < -5)
&& //Ðîñò CCI â % áîëüøå ïîðîãà
(MathAbs(Alpha1 - Alpha2)/MathMax(MathAbs(Alpha1),MathAbs(Alpha2))*100 > DAlpha)
) //+-- && Juice>JuiceLevel)
{
FileWrite(handle, "Buy", Time[0], Laguerre, MA, MA1, MA-MA1, Alpha1, Alpha2, MathAbs(Alpha1 - Alpha2)/MathMax(MathAbs(Alpha1),MathAbs(Alpha2))*100 );
FileFlush(handle);
//Äëÿ "ýñòåòîâ" StopLoss
if (SL == 0)
SLstop = 0;
else
SLstop = Ask - SL * Point;
ticket=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,SLstop,0,"starter",MagicNumber,0,Green);
}
// check for short position (SELL) possibility
if(
//Èç "îðèãèíàëà"
(Laguerre==1)
&& //Íå ïðîñòî ïàäåíèå MA, íî è ìèíèìóì íåêîòîðóþ äåëüòó
(MA-MA1 < -1 * DeltaMA * Point)
&& //Ïàäåíèå CCI
(Alpha2 > Alpha1)
&& //Ïåðåñå÷åíèå íåêîòîðîãî óðîâíÿ +/-100, 0 "Ñâåðõó-âíèç"
(Alpha1 < CCILevel && Alpha2 > CCILevel)
// && // îðèãèíàëå (åñëè ÷åñòíî - íå ïîíÿë. ÈÌÕÎ èìåëîñü ââèäó ïåðåñå÷åíèå (èëè "ïîäõîä" ê) 0, íî, åñëè ñìîòðåòü îòëàäî÷íûé ôàéë, òî òàì ....
// (Alpha1 > 5)
&& //Ðîñò CCI â % áîëüøå ïîðîãà
(MathAbs(Alpha1 - Alpha2)/MathMax(MathAbs(Alpha1),MathAbs(Alpha2))*100 > DAlpha)
) //+-- && Juice>JuiceLevel)
{
FileWrite(handle, "Sell", Time[0], Laguerre, MA, MA1, MA-MA1, Alpha1, Alpha2, MathAbs(Alpha1 - Alpha2)/MathMax(MathAbs(Alpha1),MathAbs(Alpha2))*100 );
FileFlush(handle);
//Äëÿ "ýñòåòîâ" StopLoss
if (SL == 0)
SLstop = 0;
else
SLstop = Bid + SL * Point;
ticket=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,SLstop,0,"starter",MagicNumber,0,Red);
}
}
// it is important to enter the market correctly,
// but it is more important to exit it correctly...
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL && // check for opened position
OrderSymbol()==Symbol() && // check for symbol
OrderMagicNumber() == MagicNumber) // check for MagicNumber (×òîáû ðóëèòü òîëüêî ñâîèìè ñäåëêàìè ñâîåãî ñîâåòíèêà)
{
if(OrderType()==OP_BUY) // long position is opened
{
// should it be closed?
if(Laguerre>1-StopL)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
return(0); // exit
}
// check for stop
if(Stop>0)
{
if(Bid-OrderOpenPrice()>Point*Stop)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
return(0);
}
}
}
else // go to short position
{
// should it be closed?
if(Laguerre<StopL)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
return(0); // exit
}
// check for stop
if(Stop>0)
{
if(OrderOpenPrice()-Ask>Point*Stop)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
return(0);
}
}
}
}
}
return(0);
}
// the end.
Comments