IndianTrailingStopLoss/IndianTrailingStopLoss.mq5
super.admin 88be02cad4 convert
2025-05-30 15:00:53 +02:00

360 lines
14 KiB
MQL5

//+------------------------------------------------------------------+
//| IndianTrailingStopLoss.mq5 |
//| Jay Davis |
//| 512jay.github.io |
//+------------------------------------------------------------------+
#property copyright "Jay Davis"
#property link "512jay.github.io"
#property version "3.18"
// Add the first trade details on ITSL like BUY, PRICE and STOP LOSS
enum TradeDirection
{
Buy,
Sell,
BuyLimit, // BuyLimit Pending buy with entry below current price
SellLimit, // SellLimit Pending sell with entry above current price
BuyStop, // BuyStop Pending buy with entry above current price
SellStop // SellStop Pending sell with entry below current price
};
enum EA_MODE
{
Normal, // Normal
Reverse_Entries, // Reverse Entries
Reverse_Signal // Reverse Signal (Fool's Gold)
};
input group "|---------- General Settings -----------|"
input EA_MODE Mode = Normal;
#include "../GrayMatrixLibraries/Virtualization.mqh"
#include "../GrayMatrixLibraries/Trade.mqh"
input string DatabaseName = "DATABASE"; //\AppData\Roaming\MetaQuotes\Terminal\Common\DATABASE
input long MagicNumber = 7775; // Magic Number
input TradeDirection InitialDirection = Buy; // Initial Direction to Trade
input double Price = 0; // At Price
input double Stoploss = 0; // Inital StopLoss
extern ENUM_ORDER_TYPE DirectionToTrade = (ENUM_ORDER_TYPE) InitialDirection;
input string InpSym = NULL; // Charting Symbol
input double BuyInitialLotSize = 0.01; // BUY Initial Lot Size
input double SellInitialLotSize = 0.01; // SELL Initial Lot Size
#include "SLM.mqh"
#include "AddOnOrdersManagement.mqh"
#include "../GrayMatrixLibraries/WhatsAppAPI.mqh"
GrayMatrixTrade trade;
Virtual Virt[];
double MostRecentOpenedPrice;
int IdleMovements = 1, SeriesOrderNumber = 0;
datetime TimeStopLossWasLastModified;
double MinMovement = MinimumPointsForStopLossMove * _Point;
string Sym;
bool InitialOrderTaken;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
InitialOrderTaken = false;
Print("********* Starting... ", __FILE__, " ********************************* ");
Print("Virt Size = ", ArraySize(Virt));
if(ErrorsWithInputs())
return(INIT_PARAMETERS_INCORRECT);
CreateDataBase(DatabaseName, false);
InitializeVirtualObjectArray(Virt);
Sym = _Symbol;
string symbols[];
ArrayResize(symbols, 1);
symbols[0] = Sym;
FillVirtualOrderArray(Virt, symbols);
trade.SetExpertMagicNumber(MagicNumber);
trade.LogLevel(LOG_LEVEL_ALL);
if(MQLInfoInteger(MQL_TESTER))
trade.LogLevel(LOG_LEVEL_NO);
CheckForInitialOrder();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0);
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!CheckForInitialOrder())
return;
int size = ArraySize(Virt);
//Print("Virt Size = ", size);
if(NoOpenVirtualOrders(Virt))
{
PlaceOrder(Opposite(Virt[size - 1].request.type));
}
//Dir = Opposite(Dir);
ModifyStopLoss();
CheckStops();
DisplayLines(Virt[FirstActive(Virt, Sym)]);
Comment(CurrentTradeTradeTypeStopLoss(Virt),
" Cur Dir: ", EnumToString(Virt[size - 1].request.type));
}
//+------------------------------------------------------------------+
//| True if initial order has been taken if not it tries to take it |
//+------------------------------------------------------------------+
bool CheckForInitialOrder()
{
if(InitialOrderTaken || UpdateFromResumeTableAtStart)
return true;
ENUM_ORDER_TYPE direction = (ENUM_ORDER_TYPE) InitialDirection;
if(Price == 0 && Stoploss == 0)
if(PlaceOrder(direction))
InitialOrderTaken = true;
if(direction == ORDER_TYPE_BUY_LIMIT && SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= Price)
if(PlaceOrder(ORDER_TYPE_BUY))
InitialOrderTaken = true;
if(direction == ORDER_TYPE_SELL_LIMIT && SymbolInfoDouble(_Symbol, SYMBOL_BID) >= Price)
if(PlaceOrder(ORDER_TYPE_SELL))
InitialOrderTaken = true;
if(direction == ORDER_TYPE_BUY_STOP && SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= Price)
if(PlaceOrder(ORDER_TYPE_BUY))
InitialOrderTaken = true;
if(direction == ORDER_TYPE_SELL_STOP && SymbolInfoDouble(_Symbol, SYMBOL_BID) <= Price)
if(PlaceOrder(ORDER_TYPE_SELL))
InitialOrderTaken = true;
return InitialOrderTaken;
}
//+------------------------------------------------------------------+
//| Takes the trade in the direction indicated |
//+------------------------------------------------------------------+
bool PlaceOrder(ENUM_ORDER_TYPE dir)
{
ENUM_ORDER_TYPE direction = dir;
if(Mode == Reverse_Signal)
direction = Opposite(dir);
if(dir == ORDER_TYPE_BUY)
return PlaceABuyOrder();
if(dir == ORDER_TYPE_SELL)
return PlaceASellOrder();
return false;
}
//+------------------------------------------------------------------+
//| Returns the opposite order type |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE Opposite(ENUM_ORDER_TYPE dir)
{
if(dir == ORDER_TYPE_BUY)
return ORDER_TYPE_SELL;
else // dir = ORDER_TYPE_SELL
return ORDER_TYPE_BUY;
}
//+------------------------------------------------------------------+
//| Prints new trade message to journal |
//+------------------------------------------------------------------+
void PrintNewTradeMessage(ENUM_ORDER_TYPE dir, double sl)
{
Print(" |||---->>> Dir = ", EnumToString(dir),
" ATR = ", AverageTrueRange(Sym, TimeframeOfATR, PeriodsInATR),
" Sell% = ", GetPercentage(Sym, dir, SellStopLossPercentage),
" StopLoss = ", sl);
}
//+------------------------------------------------------------------+
//| Places a sell market order |
//+------------------------------------------------------------------+
bool PlaceASellOrder()
{
//Print(__FUNCTION__);
double sl = GetStopLoss(Sym, ORDER_TYPE_SELL, false);
if(InitialOrderTaken == false && Stoploss != 0)
sl = Stoploss;
double bid = SymbolInfoDouble(Sym, SYMBOL_BID);
double size = LotSizer(Sell);
string comment = "Sell #1";
VirtualSell(Virt, size, Sym, bid, sl, 0, comment);
int arraySize = ArraySize(Virt);
NoticeMessage("ITSL", Virt[arraySize - 1], 2);
DisplayLines(Virt[arraySize - 1]);
if(Mode == Reverse_Entries)
{
if(trade.Buy(size, Sym, 0, 0, 0, comment))
return true;
}
if(trade.Sell(size, Sym, bid, useVirtualStops ? 0 : sl, 0, comment))
return true;
return false;
}
//+------------------------------------------------------------------+
//| Set stoploss lines |
//+------------------------------------------------------------------+
void DisplayLines(Virtual & virt)
{
//Print(__FUNCTION__);
if(virt.request.type == ORDER_TYPE_BUY)
{
HLineCreate(0, "StopLoss", 0, virt.request.sl, clrLawnGreen, STYLE_DASHDOTDOT, 5);
HLineCreate(0, "Opened", 0, 0, clrMediumBlue, STYLE_SOLID, 3);
ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrBlack);
}
else
{
HLineCreate(0, "StopLoss", 0, virt.request.sl, clrHotPink, STYLE_DASHDOTDOT, 5);
HLineCreate(0, "Opened", 0, 0, clrFuchsia, STYLE_SOLID, 3);
ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrBlack);
}
}
//+------------------------------------------------------------------+
//| Places a buy market order |
//+------------------------------------------------------------------+
bool PlaceABuyOrder()
{
//Print(__FUNCTION__);
double sl = GetStopLoss(Sym, ORDER_TYPE_BUY, false);
if(InitialOrderTaken == false && Stoploss != 0)
sl = Stoploss;
double ask = SymbolInfoDouble(Sym, SYMBOL_ASK);
double size = LotSizer(Buy);
string comment = "Buy #1";
VirtualBuy(Virt, size, Sym, ask, sl, 0, comment);
int arraySize = ArraySize(Virt);
NoticeMessage("ITSL", Virt[arraySize - 1], 2);
DisplayLines(Virt[arraySize - 1]);
if(Mode == Reverse_Entries)
{
if(trade.Sell(size, Sym, 0, 0, 0, comment))
return true;
}
if(trade.Buy(size, Sym, ask, useVirtualStops ? 0 : sl, 0, comment))
return true;
return false;
}
//+------------------------------------------------------------------+
//| Cycles through the virtual orders and checks if any have hit the |
//| stoploss if so it issues a close order |
//+------------------------------------------------------------------+
void CheckStops()
{
//Print(__FUNCTION__);
int size = ArraySize(Virt);
for(int i = 0; i < size; i++)
{
if(Virt[i].active)
{
if(Virt[i].request.type == ORDER_TYPE_BUY)
if(SymbolInfoDouble(Sym, SYMBOL_BID) <= Virt[i].request.sl && Virt[i].request.sl != 0)
{
Print(Sym, " Bid = ", SymbolInfoDouble(Sym, SYMBOL_BID), " <= Stoploss ", Virt[i].request.sl);
if(VirtualOrderClose(Virt, i))
{
NoticeMessage("ITSL", Virt[i], 4, " switching Direction");
trade.PositionClose(Virt[i].request.symbol);
}
}
if(Virt[i].request.type == ORDER_TYPE_SELL)
if(SymbolInfoDouble(Sym, SYMBOL_ASK) >= Virt[i].request.sl && Virt[i].request.sl != 0)
{
Print(Sym, " Ask = ", SymbolInfoDouble(Sym, SYMBOL_BID), " <= Stoploss ", Virt[i].request.sl);
if(VirtualOrderClose(Virt, i))
{
NoticeMessage("ITSL", Virt[i], 4, " switching Direction");
trade.PositionClose(Virt[i].request.symbol);
}
}
}
}
}
//+------------------------------------------------------------------+
//| Calculates the virtual profits that occured after a back test |
//+------------------------------------------------------------------+
double OnTester()
{
double profit = 0;
int size = ArraySize(Virt);
for(int i = 0; i < size; i++)
{
profit += Virt[i].profit;
if(verb)
printf("Virt[%d] profit %.2f ticket #%d : Balance $%.2f Entry %.2f : Exit %.2f",
i, Virt[i].profit, Virt[i].request.order, profit, Virt[i].request.price, Virt[i].close);
}
printf("Profit %.2f on %d orders", profit, size);
return (profit);
}
//+------------------------------------------------------------------+
//| Returns the proper lots size for the order being placed |
//+------------------------------------------------------------------+
double LotSizer(TradeDirection dir, double multiplier = 1)
{
Print(__FUNCTION__);
double size = SellInitialLotSize,
volumeMin = SymbolInfoDouble(Sym, SYMBOL_VOLUME_MIN),
volumeMax = SymbolInfoDouble(Sym, SYMBOL_VOLUME_MAX);
if(dir == Buy)
size = BuyInitialLotSize;
for(int i = 0; i < SeriesOrderNumber; i++)
size = size + size * multiplier;
//if(size > volumeMax)
// return volumeMax;
//else
if(size < volumeMin)
return volumeMin;
else
return NormalizeDouble
(size, 2);
}
//+------------------------------------------------------------------+
//| Checks if the account has enough money for the trade |
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb, double lots, ENUM_ORDER_TYPE type)
{
Print(__FUNCTION__);
//--- Getting the opening price
MqlTick mqltick;
SymbolInfoTick(symb, mqltick);
double price = mqltick.ask;
if(type == ORDER_TYPE_SELL)
price = mqltick.bid;
//--- values of the required and free margin
double margin, free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
if(!OrderCalcMargin(type, symb, lots, price, margin))
{
//--- something went wrong, report and return false
Print("Error in ", __FUNCTION__, " code=", GetLastError());
Print(__FUNCSIG__, symb, " ", lots, " ", type);
return(false);
}
//--- if there are insufficient funds to perform the operation
if(margin > free_margin)
return(false);
//--- checking successful
return(true);
}
//+------------------------------------------------------------------+
//| Checks for errors with inputs |
//+------------------------------------------------------------------+
bool ErrorsWithInputs()
{
bool inputError = false;
if(Price == 0 && (InitialDirection > Sell))
{
Print("A Price must be specified for ", EnumToString(InitialDirection), " order type!");
Alert("A Price must be specified for ", EnumToString(InitialDirection), " order type!");
inputError = true;
}
if(!UpdateFromResumeTableAtStart) // If not resuming
{
if((BuyStopLossPercentage <= 0 || SellStopLossPercentage <= 0)
|| (BuyIdleMinutesRequiringAMove <= 0 && BuyMoveStopLossIfIdle)
|| (SellIdleMinutesRequiringAMove <= 0 && SellMoveStopLossIfIdle))
{
Print("Inputs Error Check: Stop Loss Percentage and Idle Minutes Settings");
inputError = true;
}
if(inputError)
Alert("Error with inputs! EA Stopping");
}
return inputError;
}
//+------------------------------------------------------------------+