Dellan
-
Posts
3 -
Joined
-
Last visited
Content Type
Profiles
Forums
Blogs
Events
Community Tutorials
Store
Posts posted by Dellan
-
-
Deal all,
I'm new to forex and EA, trying to execute the EA to run a backtesting, but it show error unable to load file, need help regarding this issue.
Due to unable upload EA file, hence I upload the file My First EA to google share drive (is an EA i create by using AlgoWizard "Simple").
-
Deal all,
I'm new to forex and EA, trying to execute the EA to run a backtesting, but it show error unable to load file, need help regarding this issue.
Due to unable upload EA file, hence I paste the code bellow (is an EA i create by using AlgoWizard "Simple").
//+------------------------------------------------------------------+
//| New strategy EA
//|
//| Generated by StrategyQuant 3.9.132 at 12/30/2022 14:11
//|
//| Backtested on EURUSD / D1, 2021.12.28 - 2022.12.28
//|
//| This EA uses 3rd party library OrderReliable for industry-strength
//| order handling. OrderReliable library is normally distributed under
//| GPL license. Its author provided it under MIT license limited to
//| usage only within strategies generated by StrategyQuant.
//|
//| This means that this library doesn't restrict you to use your EA
//| generated by SQ comercially in any way you want.
//| But if you'll use any method from OrderReliable library outside
//| of this EA in your own EAs or projects, its use will be governed
//| by its standard GPL license.
//|
//| Scroll to the very bottom of this source code for the full text
//| of OrderReliable license.
//+------------------------------------------------------------------+#property copyright "StrategyQuant.com"
#property link "http://www.StrategyQuant.com"
#property strict#include <stdlib.mqh>
#include <stderror.mqh>const int SLPTTYPE_RANGE = 0;
const int SLPTTYPE_LEVEL = 1;//+------------------------------------------------------------------+
// -- Variables
//+------------------------------------------------------------------+extern string CustomComment = "New strategy";
extern int MagicNumber = 11111;
bool LongEntrySignal = false;
bool ShortEntrySignal = false;
bool LongExitSignal = false;
bool ShortExitSignal = false;
extern int MABarOpensPeriod = 10;//+------------------------------------------------------------------+
// Money Management variables
//+------------------------------------------------------------------+extern string smm = "----------- Money Management - Fixed size -----------";
extern double mmLots = 0.1;//+------------------------------------------------------------------+
// Trading Options variables
//+------------------------------------------------------------------+extern string sdtw = "----------- Dont Trade On Weekends -----------";
extern bool DontTradeOnWeekends = false;
extern string FridayCloseTime = "23:00";
extern string SundayOpenTime = "23:00";
extern string seod = "----------- Exit At End Of Day -----------";
extern bool ExitAtEndOfDay = false;
extern string EODExitTime = "23:55";extern string seof = "----------- Exit On Friday -----------";
extern bool ExitOnFriday = false;
extern string FridayExitTime = "23:00";extern string sltr = "----------- Limit Time Range -----------";
extern bool LimitTimeRange = false;
extern string SignalTimeRangeFrom = "08:00";
extern string SignalTimeRangeTo = "16:00";
extern bool ExitAtEndOfRange = false;
extern int OrderTypeToExit = 0;extern string smmmdfmp = "----------- Max distance from market price -----------";
extern bool LimitMaxDistanceFromMarketPrice = false; //Limit max distance
extern double MaxDistanceFromMarketPct = 6; //Max distance %extern string smtpd = "----------- Max Trades Per Day -----------";
extern int MaxTradesPerDay = 0;
extern string smmslpt = "----------- Min/Max SL/PT -----------";
extern int MinimumSL = 0; //Minimum SL in pips
extern int MinimumPT = 0; //Minimum PT in pips
extern int MaximumSL = 0; //Maximum SL in pips
extern int MaximumPT = 0; //Maximum PT in pips
extern string slts = "----------- Use Tick size from SQ (for CFDs) -----------";
// For exotic pairs (usually non forex CFDs) the default method of computing
// tick size in EA might not work correctly.
// By turning this on and specifying MainChartTickSizeSQ value you can let EA
// use the correct tick size
extern bool UseSQTickSize = false;
extern double MainChartTickSizeSQ = 1.0E-4;//+------------------------------------------------------------------+
// OrderReliable library variables
//+------------------------------------------------------------------+
string OrderReliableVersion = "v36";
string OrderReliable_Fname = "OrderReliable (Function Name Not Set)";int retry_attempts = 100; // general retry attempts
int retry_attempts_bad_price = 3; // retry attempts if the error is bad price
double sleep_time = 2.0;
double sleep_maximum = 20.0;
int ErrorLevel = 3;bool UseLimitToMarket = false;
bool UseForTesting = false;
bool AddSpreadToComment = false;//+------------------------------------------------------------------+
// -- SQ internal variables
// add word "extern" in front of the variable you want
// to make configurable
//+------------------------------------------------------------------+
int sqMaxEntrySlippage = 5; //Max tolerated entry slippage in pips. Zero means unlimited slippage
int sqMaxCloseSlippage = 0; //Max tolerated close slippage in pips. Zero means unlimited slippage
bool autoCorrectMaxSlippage = true; //If set to true, it will automatically adjust max slippage according to symbol digits (*10 for 3 and 5 digit symbols)//Some brokers have problems with updating position counts. Set this timeout to non-zero value if you experience this.
//For example EnterReverseAtMarket doesn't work well for Admiral Markets, because OrdersTotal() returns 1 even after the order has been closed.
uint orderSelectTimeout = 0; //in msdouble sqMinDistance = 0.0;
//+------------------------------------------------------------------+
// Verbose mode values:
// 0 - don't print messages to log at all
// 1 - print messages to log only when trading (not when backtesting)
// 2 - print messages to log always
//+------------------------------------------------------------------+
int sqVerboseMode = 2;extern bool sqDisplayInfoPanel = true;
extern bool ModifyInsteadOfReplacing = true;extern int OpenBarDelay = 0; // open bar delay in minutes
// it can be used for Daily strategies to trigger trading a few minutes later -
// because brokers sometimes have technical delay after midnight and we have to postpone order executionint sqLabelCorner = 1;
int sqOffsetHorizontal = 5;
int sqOffsetVertical = 20;
color sqLabelColor = White;datetime _sqLastOpenBarTime = 0;
bool _sqIsBarOpen = false;
double gPointCoef = 0;
int _ticket;
bool cond[100];double initialBalance = 0;
bool openingOrdersAllowed = true;
bool firstCall = true;
bool strategyUsesATM = false;//////////
//+------------------------------------------------------------------+
// -- Functions
//+------------------------------------------------------------------+void OnTick() {
sqInitStart();
sqManageOrders(MagicNumber);
openingOrdersAllowed = sqHandleTradingOptions();//------------------------
// Rule: Trading signals
//------------------------
if (sqIsBarOpen()) {
// init signals only on bar open
LongEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));ShortEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));
LongExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));
ShortExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));
}
//------------------------
// Rule: Long entry
//------------------------
if (sqIsBarOpen()
&& ((LongEntrySignal
&& (!(ShortEntrySignal)))
&& (!(LongExitSignal))))
{
// Action #1
_ticket = sqOpenOrder(OP_BUY, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE);if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) {
// set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.)
// StopLoss & ProfitTarget}
}
//------------------------
// Rule: Short entry
//------------------------
if (sqIsBarOpen()
&& ((ShortEntrySignal
&& (!(LongEntrySignal)))
&& (!(ShortExitSignal))))
{
// Action #1
_ticket = sqOpenOrder(OP_SELL, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE);if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) {
// set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.)
// StopLoss & ProfitTarget}
}
//------------------------
// Rule: Long exit
//------------------------
if (sqIsBarOpen()
&& (LongExitSignal
&& sqMarketPositionIsLong(MagicNumber, "Any", "")))
{
// Action #1
sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition
MagicNumber, // magic number
"Any", // symbol
1, // direction
"" // comment
);}
//------------------------
// Rule: Short exit
//------------------------
if (sqIsBarOpen()
&& (ShortExitSignal
&& sqMarketPositionIsShort(MagicNumber, "Any", "")))
{
// Action #1
sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition
MagicNumber, // magic number
"Any", // symbol
-1, // direction
"" // comment
);}
return;
}//+------------------------------------------------------------------+
int OnInit() {
VerboseLog("--------------------------------------------------------");
VerboseLog("Starting the EA");if(!checkComments()){
return(INIT_FAILED);
}gPointCoef = calculatePointCoef(Symbol());
VerboseLog("--------------------------------------------------------");
if(sqDisplayInfoPanel) {
sqInitInfoPanel();
}SQTime = new CSQTime();
if(!IsTesting() && !IsOptimization()) {
initTimer();
}
initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
objDontTradeOnWeekends = new CDontTradeOnWeekends();
objExitAtEndOfDay = new CExitAtEndOfDay();
objExitOnFriday = new CExitOnFriday();
objLimitTimeRange = new CLimitTimeRange();
objMaxDistanceFromMarket = new CMaxDistanceFromMarket();
objMaxTradesPerDay = new CMaxTradesPerDay();
objMinMaxSLPT = new CMinMaxSLPT();
double minDistanceMT = NormalizeDouble(MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT), Digits);
double minDistanceSQ = NormalizeDouble(sqMinDistance * sqGetPointCoef(Symbol()), Digits);
if(minDistanceSQ < minDistanceMT){
VerboseLog("--------------------------------------------------------");
VerboseLog("Warning! Min distance of this symbol is greater than min distance set in SQ! The backtest results may differ");
VerboseLog("MT min distance: ", DoubleToStr(minDistanceMT), ", SQ min distance: ", DoubleToStr(minDistanceSQ));
VerboseLog("--------------------------------------------------------");
}//Show all subchart symbols in market watch
return(0);
}//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
sqDeinitInfoPanel();
delete SQTime;
delete objDontTradeOnWeekends;
delete objExitAtEndOfDay;
delete objExitOnFriday;
delete objLimitTimeRange;
delete objMaxDistanceFromMarket;
delete objMaxTradesPerDay;
delete objMinMaxSLPT;
return;
}
//+------------------------------------------------------------------+bool checkComments(){
if(StringLen(CustomComment) > 30){
Alert("Strategy initialization error - Comment CustomComment is longer than 30 characters");
return false;
}
return true;
}//+------------------------------------------------------------------+
void initTimer(){
int period = 20 * 3600; //20 hours
period += MathRand() % (10 * 3600); //add another 0-10 hours randomlyif(!EventSetTimer(period)){
VerboseLog("Cannot set timer. Error code: ", IntegerToString(GetLastError()));
}
}//+------------------------------------------------------------------+
void OnTimer(){
//clear unused variables
int deletedCount = 0;
VerboseLog("Clearing variables...");
for(int a=GlobalVariablesTotal() - 1; a>=0; a--){
string variableName = GlobalVariableName(a);if(GlobalVariableCheck(variableName)){
string variableNameParts[];
int parts = StringSplit(variableName, '_', variableNameParts);
if(parts != 3 || variableNameParts[0] != getVariablePrefix()) continue;
int ticketNo = StrToInteger(variableNameParts[1]);
bool variableUsed = false;
for(int i=0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS) == true) {
if(OrderTicket() == ticketNo){
variableUsed = true;
break;
}
}
}
ResetLastError();
if(!variableUsed){
if(GlobalVariableDel(variableName)){
deletedCount++;
}
else {
VerboseLog("Cannot delete variable. Error code: ", IntegerToString(GetLastError()));
}
}
}
}
VerboseLog(IntegerToString(deletedCount), " variables cleared");
}//+------------------------------------------------------------------+
bool sqHandleTradingOptions() {
bool continueWithBarUpdate = true;if(!objDontTradeOnWeekends.onBarUpdate()) continueWithBarUpdate = false;
if(!objExitAtEndOfDay.onBarUpdate()) continueWithBarUpdate = false;
if(!objExitOnFriday.onBarUpdate()) continueWithBarUpdate = false;
if(!objLimitTimeRange.onBarUpdate()) continueWithBarUpdate = false;
if(!objMaxDistanceFromMarket.onBarUpdate()) continueWithBarUpdate = false;
if(!objMaxTradesPerDay.onBarUpdate()) continueWithBarUpdate = false;
if(!objMinMaxSLPT.onBarUpdate()) continueWithBarUpdate = false;return(continueWithBarUpdate);
}//+------------------------------------------------------------------+
bool checkMagicNumber(int magicNo){
if(magicNo == MagicNumber){
return true;
}
return false;
}//+------------------------------------------------------------------+
double sqGetMarketTickSize(string symbol){
symbol = correctSymbol(symbol);
if(symbol == Symbol()){
return MainChartTickSizeSQ;
}
return -1;
}//+------------------------------------------------------------------+
double sqGetGlobalSL(string symbol, int orderType, double price) {
return(sqGetSLLevel(symbol, orderType, price, 1, 0));
}//+------------------------------------------------------------------+
double sqGetGlobalPT(string symbol, int orderType, double price) {
return(sqGetPTLevel(symbol, orderType, price, 1, 0));
}//+------------------------------------------------------------------+
double sqGetIndicatorByIdentification(string idHash, int shift) {
return(0);
}
//+------------------------------------------------------------------+double sqGetValueByIdentification(string idHash) {
if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}if(idHash == (string) sqStringHash("0")) {
return (0);
}return(0);
}//----------------------------------------------------------------------------
void sqManageOrders(int magicNumber) {
if(_sqIsBarOpen) {
for(int i=OrdersTotal()-1; i>=0; i--) {
if (OrderSelect(i,SELECT_BY_POS)==true) {
if(OrderMagicNumber() != magicNumber || isMarketClosed(OrderSymbol())) {
continue;
}
int ticket = OrderTicket();if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
// handle Exit Methods only for live orderssqManageSL2BE(ticket);
sqManageTrailingStop(ticket);
sqManageExitAfterXBars(ticket);
}sqManageOrderExpiration(ticket);
}if(OrdersTotal() <= 0) return;
}
}
}//----------------------------------------------------------------------------
void sqResetGlobalVariablesForTicket(int ticket) {
sqSetGlobalVariable(ticket, "sqOrderExpiration", 0);
sqSetGlobalVariable(ticket, "sqOrderOpenTime", Time[0]);sqSetGlobalVariable(ticket, "MoveSL2BE", 0);
sqSetGlobalVariable(ticket, "SL2BEAddPips", 0);
sqSetGlobalVariable(ticket, "TrailingStop", 0);
sqSetGlobalVariable(ticket, "TrailingActivation", 0);
sqSetGlobalVariable(ticket, "ExitAfterBars", 0);
}//+------------------------------------------------------------------+
void sqInitStart() {
// changed recognition of bar open to support also range/renko charts
if(_sqLastOpenBarTime == 0) {
_sqLastOpenBarTime = Time[0];
_sqIsBarOpen = true;
}
else {
if(_sqLastOpenBarTime != Time[0]) {
bool processBarOpen = true;if(OpenBarDelay > 0) {
// set bar to open after X minutes from real open
processBarOpen = false;
long diffInSeconds = TimeCurrent() - Time[0];
if(diffInSeconds >= OpenBarDelay * 60) {
processBarOpen = true;
}
}
if(processBarOpen) {
_sqIsBarOpen = true;
_sqLastOpenBarTime = Time[0];
}
}
else {
_sqIsBarOpen = false;
}
}if(_sqIsBarOpen && Bars<30) {
Print("NOT ENOUGH DATA: Less Bars than 30");
return;
}if(!IsTesting() && !IsOptimization()) {
sqTextFillOpens();
if(_sqIsBarOpen) {
sqTextFillTotals();
}
}
}//+------------------------------------------------------------------+
bool sqIsBarOpen() {
return(_sqIsBarOpen);
}//+------------------------------------------------------------------+
int sqGetOrderExpiration(int ticket) {
return (int) sqGetGlobalVariable(ticket, "sqOrderExpiration");
}//+------------------------------------------------------------------+
void sqSetOrderExpiration(int ticket, int bars) {
sqSetGlobalVariable(ticket, "sqOrderExpiration", bars);
}//+------------------------------------------------------------------+
void sqManageOrderExpiration(int ticket) {
int tempValue = 0;
int barsOpen = 0;// Stop/Limit Order Expiration
if(OrderType() != OP_BUY && OrderType() != OP_SELL) {
// handle only pending orders
tempValue = sqGetOrderExpiration(ticket);
if(tempValue > 0) {
barsOpen = sqGetOpenBarsForOrder(ticket, tempValue+10);
if(barsOpen >= tempValue) {
Verbose("Order with ticket: ", IntegerToString(ticket), " expired");
sqDeletePendingOrder(ticket);
}
}
}
}//----------------------------------------------------------------------------
double sqIndicatorHighest(int period, int nthValue, string indicatorIdentification) {
if(period > 1000) {
Alert("Period used for sqIndicatorHighest function is too high. Max value is 1000");
period = 1000;
}
if(nthValue < 0 || nthValue >= period) {
return(-1);
}
double indicatorValues[1000];
int i;for(i=0; i<1000; i++) {
indicatorValues[i] = -2147483647;
}for(i=0; i<period; i++) {
indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
}ArraySort(indicatorValues, WHOLE_ARRAY,0,MODE_DESCEND);
if(nthValue < 0 || nthValue >= period) {
return(-1);
}return(indicatorValues[nthValue]);
}//----------------------------------------------------------------------------
double sqIndicatorLowest(int period, int nthValue, string indicatorIdentification) {
if(period > 1000) {
Alert("Period used for sqIndicatorLowest function is too high. Max value is 1000");
period = 1000;
}
if(nthValue < 0 || nthValue >= period) {
return(-1);
}
double indicatorValues[1000];
int i;for(i=0; i<1000; i++) {
indicatorValues[i] = 2147483647;
}for(i=0; i<period; i++) {
indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
}ArraySort(indicatorValues,WHOLE_ARRAY,0,MODE_ASCEND);
if(nthValue < 0 || nthValue >= period) {
return(-1);
}return(indicatorValues[nthValue]);
}//----------------------------------------------------------------------------
double sqIndicatorAverage(int period, int maMethod, string indicatorIdentification) {
double indicatorValues[10000];for(int i=0; i<period; i++) {
indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
}double maValue = iMAOnArray(indicatorValues, period, period, 0, maMethod, 0);
return(maValue);
}
//----------------------------------------------------------------------------double sqIndicatorRecent(int barsBack, string indicatorIdentification) {
return(sqGetIndicatorByIdentification(indicatorIdentification, barsBack));
}//----------------------------------------------------------------------------
bool sqIsRising(string indicatorIdentification, int bars, bool allowSameValues, int shift) {
bool atLeastOnce = false;double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6);
for(int i=1; i<bars; i++) {
double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6);if(currentValue < previousValue) {
// indicator was falling
return(false);
}
if(currentValue == previousValue && allowSameValues == false) {
// indicator was the same, not allowed
return(false);
}
if(currentValue > previousValue) {
atLeastOnce = true;
}previousValue = currentValue;
}if(atLeastOnce) {
return(true);
}// indicator was not rising once
return(false);
}//----------------------------------------------------------------------------
bool sqIsFalling(string indicatorIdentification, int bars, bool allowSameValues, int shift) {
bool atLeastOnce = false;double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6);
for(int i=1; i<bars; i++) {
double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6);if(currentValue > previousValue) {
// indicator was rising
return(false);
}
if(currentValue == previousValue && allowSameValues == false) {
// indicator was the same, not allowed
return(false);
}
if(currentValue < previousValue) {
atLeastOnce = true;
}previousValue = currentValue;
}if(atLeastOnce) {
return(true);
}// indicator was not falling once
return(false);
}//+------------------------------------------------------------------+
string getVariablePrefix(){
return IsTesting() ? "SQX(Test)" : "SQX";
}//+------------------------------------------------------------------+
void sqSetGlobalVariable(int ticket, string name, double value) {
GlobalVariableSet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name, value);
}//+------------------------------------------------------------------+
double sqGetGlobalVariable(int ticket, string name) {
return (GlobalVariableGet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name));
}//+------------------------------------------------------------------+
int sqStringHash(string str){
int i, h=0, k;
for (i=0; i<StringLen(str); i++){
k = StringGetChar(str, i);
h = (h << 5) + h + k;
}
return(h);
}//+------------------------------------------------------------------+
void sqClosePosition(double size, int magicNumber, string symbol, int direction, string comment) {
Verbose("Closing order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
Verbose("Order cannot be found");
} else {
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
sqClosePositionAtMarket(size);
} else {
sqDeletePendingOrder(OrderTicket());
}
}Verbose("Closing order finished ----------------");
}//+------------------------------------------------------------------+
void sqClosePendingOrder(int magicNumber, string symbol, int direction, string comment) {
Verbose("Closing pending order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) {
Verbose("Order cannot be found");
} else {
sqDeletePendingOrder(OrderTicket());
}Verbose("Closing pending order finished ----------------");
}//+------------------------------------------------------------------+
void sqCloseAllPendingOrders(int magicNumber, string symbol, int direction, string comment) {
Verbose("Closing pending orders with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);while(sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) {
sqDeletePendingOrder(OrderTicket());
}Verbose("Closing pending orders finished ----------------");
}//+------------------------------------------------------------------+
int sqGetOpenBarsForOrder(int ticket, int expBarsPeriod) {
datetime opTime;if (OrderType() == OP_BUY || OrderType() == OP_SELL) { //live order
opTime = OrderOpenTime();
}
else { //pending order
opTime = (datetime) sqGetGlobalVariable(ticket, "sqOrderOpenTime");
}int numberOfBars = 0;
int limit = MathMin(expBarsPeriod + 10, Bars);for(int i=0; i<limit; i++) {
if(opTime < Time[i]) {
numberOfBars++;
}
}return(numberOfBars);
}//+------------------------------------------------------------------+
void Verbose(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="", string s13="", string s14="" ) {
if(sqVerboseMode == 0) {
return;
}
if(sqVerboseMode == 1 && (IsTesting() || IsOptimization())) {
return;
}
Print("- SQ LOG ", TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14);
}
//+------------------------------------------------------------------+void VerboseLog(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
if(sqVerboseMode != 1) {
Log(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}Verbose(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}//+------------------------------------------------------------------+
void Log(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
Print(TimeToStr(TimeCurrent()), " ", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}//+------------------------------------------------------------------+
void sqLog(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
Print(TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}
//+------------------------------------------------------------------+void sqLogToFile(string fileName, string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
int handle = FileOpen(fileName, FILE_READ | FILE_WRITE, ";");
if(handle>0) {
FileSeek(handle,0,SEEK_END);
FileWrite(handle, TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
FileClose(handle);
}
}//+------------------------------------------------------------------+
bool sqSelectOrder(int magicNumber, string symbol, int direction, string comment, bool goFromNewest=true, bool skipPending=true, bool skipFilled=false) {
int cc = 0;
if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
if(goFromNewest){
for (cc = OrdersTotal() - 1; cc >= 0; cc--) {
if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){
return true;
}
}
}
else {
for (cc = 0; cc < OrdersTotal(); cc++) {
if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){
return true;
}
}
}
return(false);
}//+------------------------------------------------------------------+
bool orderFits(int index, int magicNumber, string symbol, int direction, string comment, bool skipPending=true, bool skipFilled=false){
if (OrderSelect(index, SELECT_BY_POS)) {
// skip pending orders
if(skipPending && (OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT)) {
return false;
}
// skip filled orders
if(skipFilled && (OrderType() == OP_BUY || OrderType() == OP_SELL)) {
return false;
}if(direction != 0) {
if(direction > 0 && (OrderType() != OP_BUY && OrderType() != OP_BUYSTOP && OrderType() != OP_BUYLIMIT)) return false;
if(direction < 0 && (OrderType() != OP_SELL && OrderType() != OP_SELLSTOP && OrderType() != OP_SELLLIMIT)) return false;
}if(magicNumber != 0) {
if(!checkMagicNumber(OrderMagicNumber()) || OrderMagicNumber() != magicNumber) return false;
}if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) return false;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) return false;
}// otherwise we found the order
return(true);
}
else return false;
}//+------------------------------------------------------------------+
void sqCloseAllPositions(string symbol, int magicNumber, int direction, string comment) {
int count = 100; // maximum number of positions to close
int lastTicket = -1;while(count > 0) {
count--;
if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
// no position found
break;
}if(lastTicket == OrderTicket()) {
// trying to close the same position one more time, there must be some error
break;
}
lastTicket = OrderTicket();if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
sqClosePositionAtMarket(OrderLots());
} else {
sqDeletePendingOrder(OrderTicket());
}
}
}//+------------------------------------------------------------------+
void sqCloseBestPosition(string symbol, int magicNumber, int direction, string comment) {
double maxPL = -100000000;
int ticket = 0;
if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;
if(OrderProfit() > maxPL) {
// found order with better profit
maxPL = OrderProfit();
ticket = OrderTicket();
Verbose("Better position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(maxPL));
}
}
}if(ticket > 0) {
if(OrderSelect(ticket, SELECT_BY_TICKET)) {
sqClosePositionAtMarket(OrderLots());
}
}
}//+------------------------------------------------------------------+
void sqCloseWorstPosition(string symbol, int magicNumber, int direction, string comment) {
double minPL = 100000000;
int ticket = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;
if(OrderProfit() < minPL) {
// found order with worse profit
minPL = OrderProfit();
ticket = OrderTicket();
Verbose("Worse position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(minPL));
}
}
}if(ticket > 0) {
if(OrderSelect(ticket, SELECT_BY_TICKET)) {
sqClosePositionAtMarket(OrderLots());
}
}
}//+------------------------------------------------------------------+
int sqGetMarketPosition(string symbol, int magicNumber, string comment) {
if(sqSelectOrder(magicNumber, symbol, 0, comment, false)) {
if(OrderType() == OP_BUY) {
return(1);
} else {
return(-1);
}
}
return(0);
}//+------------------------------------------------------------------+
bool sqMarketPositionIsShort(int magicNo, string symbol, string comment){
return sqSelectOrder(magicNo, symbol, -1, comment, false);
}//+------------------------------------------------------------------+
bool sqMarketPositionIsNotShort(int magicNo, string symbol, string comment){
if(sqSelectOrder(magicNo, symbol, -1, comment, false)) {
return false;
}
return true;
}//+------------------------------------------------------------------+
bool sqMarketPositionIsLong(int magicNo, string symbol, string comment){
return sqSelectOrder(magicNo, symbol, 1, comment, false);
}//+------------------------------------------------------------------+
bool sqMarketPositionIsNotLong(int magicNo, string symbol, string comment){
if(sqSelectOrder(magicNo, symbol, 1, comment, false)) {
return false;
}
return true;
}//+------------------------------------------------------------------+
bool sqMarketPositionIsFlat(int magicNo, string symbol, string comment){
return sqGetMarketPosition(symbol, magicNo, comment) == 0;
}//+------------------------------------------------------------------+
double sqGetOrderOpenPrice(string symbol, int magicNumber, int direction, string comment) {
if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
return(OrderOpenPrice());
}
return(-1);
}//+------------------------------------------------------------------+
double sqGetOrderStopLoss(string symbol, int magicNumber, int direction, string comment) {
if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
return(OrderStopLoss());
}
return(-1);
}//+------------------------------------------------------------------+
double sqGetOrderProfitTarget(string symbol, int magicNumber, int direction, string comment) {
if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
return(OrderTakeProfit());
}
return(-1);
}//+------------------------------------------------------------------+
double sqGetMarketPositionSize(string symbol, int magicNumber, int direction, string comment) {
double lots = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}lots += OrderLots();
}
}return(lots);
}//+------------------------------------------------------------------+
double sqGetOpenPL(string symbol, int magicNumber, int direction, string comment) {
double pl = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}pl += OrderProfit();
}
}return(pl);
}//+------------------------------------------------------------------+
double sqGetOpenPLInPips(string symbol, int magicNumber, int direction, string comment) {
double pl = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}if(OrderType() == OP_BUY) {
pl += sqGetBid(OrderSymbol()) - OrderOpenPrice();
} else {
pl += OrderOpenPrice() - sqGetAsk(OrderSymbol());
}
}
}return(sqConvertToPips(OrderSymbol(), pl));
}//+------------------------------------------------------------------+
double sqGetClosedPLInPips(string symbol, int magicNumber, int direction, string comment, int shift) {
int index = 0;for(int i=OrdersHistoryTotal(); i>=0; i--) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}if(index == shift) {
if(OrderType() == OP_BUY) {
return(sqConvertToPips(OrderSymbol(), OrderClosePrice() - OrderOpenPrice()));
} else {
return(sqConvertToPips(OrderSymbol(), OrderOpenPrice() - OrderClosePrice()));
}
}index++;
}
}return(0);
}//+------------------------------------------------------------------+
double sqGetClosedPLInMoney(string symbol, int magicNumber, int direction, string comment, int shift) {
int index = 0;for(int i=OrdersHistoryTotal(); i>=0; i--) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}if(index == shift) {
return(OrderProfit());
}index++;
}
}return(0);
}//+------------------------------------------------------------------+
int sqGetMarketPositionCount(string symbol, int magicNumber, int direction, string comment) {
int count = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}count++;
}
}return(count);
}//+------------------------------------------------------------------+
int sqGetBarsSinceOpen(string symbol, int magicNumber, int direction, string comment) {
if(sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
datetime opTime = OrderOpenTime();int numberOfBars = 0;
int limit = MathMin(10000, Bars);for(int i=0; i<limit; i++) {
if(opTime < Time[i]) {
numberOfBars++;
}
}return(numberOfBars);
}return(-1);
}//+------------------------------------------------------------------+
int sqGetBarsSinceClose(string symbol, int magicNumber, int direction, string comment) {
if(sqSelectOrderInHistory(magicNumber, symbol, direction, comment)) {
datetime clTime = OrderCloseTime();int numberOfBars = 0;
int limit = MathMin(10000, Bars);for(int i=0; i<limit; i++) {
if(clTime < Time[i]) {
numberOfBars++;
}
}return(numberOfBars);
}return(-1);
}
//+------------------------------------------------------------------+int sqGetLastOrderType(string symbol, int magicNumber, string comment) {
if(sqSelectOrderInHistory(magicNumber, symbol, 0, comment)) {
if(OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT) {
return(1);
} else {
return(-1);
}
}return(0);
}//+------------------------------------------------------------------+
bool sqSelectOrderInHistory(int magicNumber, string symbol, int direction, string comment) {
for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) {
continue;
}if(direction != 0) {
if(direction > 0 && OrderType() != OP_BUY) continue;
if(direction < 0 && OrderType() != OP_SELL) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}// otherwise we found the order
return(true);
}
}return(false);
}//+------------------------------------------------------------------+
bool sqSelectPendingOrderByType(int magicNumber, string symbol, int orderType, string comment) {
if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
continue;
}
if(orderType != 0) {
if(OrderType() != orderType) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}// otherwise we found the order
return(true);
}
}return(false);
}//+------------------------------------------------------------------+
bool sqSelectPendingOrderByDir(int magicNumber, string symbol, int direction, string comment) {
if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
continue;
}
if(direction != 0) {
int orderDirection = sqGetDirectionFromOrderType(OrderType());
if(orderDirection != direction) continue;
}if(magicNumber != 0) {
if(OrderMagicNumber() != magicNumber) continue;
}
else if(!checkMagicNumber(OrderMagicNumber())) continue;if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}if(comment != "") {
if(StringFind(OrderComment(), comment) == -1) continue;
}// otherwise we found the order
return(true);
}
}return(false);
}
//+------------------------------------------------------------------+bool sqClosePositionAtMarket(double size) {
int ticket = OrderTicket();Verbose("Closing order with ticket: ", IntegerToString(ticket));
int orderType = OrderType();
if(orderType != OP_BUY && orderType != OP_SELL) {
Verbose("Trying to close non-live order");
return(false);
}
if(!sqCheckConnected()) {
return(false);
}bool result;
double price = sqGetClosePrice(orderType, OrderSymbol(), 0);
result = OrderCloseReliable(ticket, size, price, correctSlippage(sqMaxCloseSlippage, OrderSymbol()));
if(result) {
Verbose("Order deleted successfuly");
return(true);
}return(false);
}//+------------------------------------------------------------------+
double sqGetAsk(string symbol) {
if(symbol == "NULL" || symbol == "Current") {
return(NormalizeDouble(Ask, Digits));
} else {
return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_ASK), Digits));
}
}//+------------------------------------------------------------------+
double sqGetBid(string symbol) {
if(symbol == "NULL" || symbol == "Current") {
return(NormalizeDouble(Bid, Digits));
} else {
return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_BID), Digits));
}
}//+------------------------------------------------------------------+
bool sqDeleteOrder(int ticket){
if(!OrderSelect(ticket, SELECT_BY_TICKET)){
Verbose("Warning! Cannot delete order - order with ticket ", IntegerToString(ticket), " can't be selected");
return false;
}if(sqIsPendingOrder(OrderType())){
return OrderDeleteReliable(ticket);
}
else {
return OrderCloseReliableMKT(ticket, OrderLots(), sqGetDirectionFromOrderType(OrderType()) == 1 ? Bid : Ask, correctSlippage(0, OrderSymbol()));
}
}//+------------------------------------------------------------------+
bool sqDeletePendingOrder(int ticket) {
Verbose(" Deleting pending order, ticket: " + IntegerToString(ticket));int orderType = OrderType();
if(orderType == OP_BUY || orderType == OP_SELL) {
Verbose("Trying to delete non-pending order");
return(false);
}
if(!sqCheckConnected()) {
return(false);
}
bool result = OrderDeleteReliable(ticket);
if(result) {
Verbose("Order deleted successfuly");
return(true);
}
return(false);
}//+------------------------------------------------------------------+
int sqOpenOrder(int orderType, string symbol, double size, double price, int magicNumber, string comment, datetime expirationInTime, bool replaceExisting, bool allowDuplicateTrades, color arrowColor, const bool isExitLevel = false) {
if(size <= 0) return (0);string correctedSymbol = correctSymbol(symbol);
if(isMarketClosed(correctedSymbol)){
return 0;
}double ask = sqGetAsk(correctedSymbol);
double bid = sqGetBid(correctedSymbol);
int direction = sqGetDirectionFromOrderType(orderType);
double marketPrice = direction == 1 ? ask : bid;price = (orderType == OP_BUY || orderType == OP_SELL) ? marketPrice : price;
price = sqFixMarketPrice(price, correctedSymbol);if(LimitMaxDistanceFromMarketPrice && (orderType != OP_BUY && orderType != OP_SELL)){
double pctDistance = NormalizeDouble(MathAbs(price-marketPrice) / marketPrice * 100, 2);
if(pctDistance > NormalizeDouble(MaxDistanceFromMarketPct, 2)){
Verbose("Order skipped - too far from market price. Open price: ", DoubleToStr(price), ", Market price: ", DoubleToStr(marketPrice), ", Max distance: ", DoubleToStr(MaxDistanceFromMarketPct), "%");
return(0);
}
}
openingOrdersAllowed = openingOrdersAllowed && sqHandleTradingOptions();
if(!openingOrdersAllowed) return(0);Verbose("Opening order type ", OrderTypeToString(orderType)," with price ", DoubleToString(price), ". Current market prices: ", DoubleToString(ask), " / ", DoubleToString(bid));
// check if live order exists
if(!isExitLevel && sqSelectOrder(magicNumber, correctedSymbol, 0, comment) && !allowDuplicateTrades) {
Verbose("Order with these parameters already exists and duplicate trades are not allowed. Canceling order...");
Verbose("----------------------------------");
return(0);
}// check if pending order exists
if(!isExitLevel){
while(sqSelectOrder(magicNumber, correctedSymbol, direction, comment, false, false, true)) {
if(replaceExisting) {
if(!strategyUsesATM && ModifyInsteadOfReplacing && size == OrderLots()) {
// modify existing pending order
if(OrderModifyReliable(OrderTicket(), price, 0, 0, expirationInTime)) {
// reset global variables for this order
sqResetGlobalVariablesForTicket(OrderTicket());
return ( OrderTicket() );
} else {
Verbose("Modifying order failed, deleting it");
sqDeletePendingOrder(OrderTicket());
return(0);
}
} else {
// delete existing pending order
sqDeletePendingOrder(OrderTicket());
}
} else {
Verbose("Pending Order with these parameters already exists, and replace is not allowed. Canceling order...", " ----------------");
return(0);
}
}
}if(!checkOrderPriceValid(orderType, correctedSymbol, price, marketPrice)){
return 0;
}//check free margin
if(AccountFreeMarginCheck(correctedSymbol, isLongOrder(orderType) ? OP_BUY : OP_SELL, size) <= 0 || GetLastError()==134) {
Alert("Balance too low for trading!");
return(0);
}string commentToUse = "";
if(comment != ""){
commentToUse = comment;
}
else {
commentToUse = CustomComment;
}int ticket = OrderSendReliable(correctedSymbol, orderType, size, price, correctSlippage(sqMaxEntrySlippage, correctedSymbol), 0, 0, commentToUse, magicNumber, expirationInTime, arrowColor);
if(ticket > 0) {
// reset global variables for this order
sqResetGlobalVariablesForTicket(ticket);
}return(ticket);
}//+------------------------------------------------------------------+
bool isLongOrder(int orderType){
return orderType == OP_BUY || orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP;
}//----------------------------------------------------------------------------
int correctSlippage(int slippage, string symbol = NULL){
if(slippage <= 0) return 100000;
if(autoCorrectMaxSlippage){
int realDigits = (int) MarketInfo(correctSymbol(symbol), MODE_DIGITS);
if(realDigits > 0 && realDigits != 2 && realDigits != 4) {
return slippage * 10;
}
}
return slippage;
}//----------------------------------------------------------------------------
bool checkOrderPriceValid(int orderType, string symbol, double price, double marketPrice){
if(orderType == OP_BUY || orderType == OP_SELL){
if(marketPrice == price){
return true;
}
else {
Verbose("Based on its logic, the strategy tried to place order a market order at incorrect price. Market price: ", DoubleToString(marketPrice), ", order price: ", DoubleToString(price), " (this is NOT an error)");
return false;
}
}
return checkStopPriceValid(orderType, symbol, price, marketPrice, "stop/limit order");
}//----------------------------------------------------------------------------
bool checkStopPriceValid(int orderType, string symbol, double price, double marketPrice, string name){
int stopLevel = (int) MarketInfo(symbol, MODE_STOPLEVEL);
double point = MarketInfo(symbol, MODE_POINT);
double minDistance = point * stopLevel;
double minDistanceSQ = sqMinDistance * sqGetPointCoef(symbol);
if(minDistanceSQ > minDistance){
minDistance = minDistanceSQ;
}
double priceLevel;
if(orderType == OP_BUYLIMIT || orderType == OP_SELLSTOP){
priceLevel = marketPrice - minDistance;
if(price <= priceLevel){
return true;
}
else {
Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", max. price allowed: ", DoubleToString(priceLevel), ", ", name, " price: ", DoubleToString(price), " (this is NOT an error)");
return false;
}
}
else if(orderType == OP_BUYSTOP || orderType == OP_SELLLIMIT){
priceLevel = marketPrice + minDistance;
if(price >= priceLevel){
return true;
}
else {
Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", min. price allowed: ", DoubleToString(priceLevel), ", ", name," price: ", DoubleToString(price), " (this is NOT an error)");
return false;
}
}
else return true;
}//+------------------------------------------------------------------+
int sqGetDirectionFromOrderType(int orderType) {
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
return(1);
} else {
return(-1);
}
}//+------------------------------------------------------------------+
bool sqIsPendingOrder(int orderType) {
if(orderType != OP_BUY && orderType != OP_SELL) {
return(true);
}
return(false);
}//+------------------------------------------------------------------+
void sqSetSLandPT(int ticket, double sl, double pt) {
if(sl == 0 && pt == 0) return;
if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
return;
}
if(sl == OrderOpenPrice()) {
Verbose("SL is the same as order price, cannot set it, so we'll delete the order!");
if(!sqDeleteOrder(ticket)) {
Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError()));
}return;
}if(pt == OrderOpenPrice()) {
pt = 0;
}
if(sl > 0 || pt > 0) {
bool result = sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(sl, OrderSymbol()), sqFixMarketPrice(pt, OrderSymbol()));
if(!result) {
Verbose("Cannot set SL / PT for this order, deleting it!");
if(!sqDeleteOrder(ticket)){
Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError()));
}
}
}
}//+------------------------------------------------------------------+
bool sqOrderModifySL(int ticket,double stopLoss, int type) {
if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
}if(type == SLPTTYPE_RANGE) {
// convert range to price level
if(sqGetDirectionFromOrderType(OrderType()) == 1) {
// it is long order
stopLoss = OrderOpenPrice() - stopLoss;
} else {
stopLoss = OrderOpenPrice() + stopLoss;
}
}return(sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(stopLoss, OrderSymbol()), OrderTakeProfit()));
}//+------------------------------------------------------------------+
bool sqOrderModifyPT(int ticket,double profitTarget, int type) {
if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
}if(type == SLPTTYPE_RANGE) {
// convert range to price level
if(sqGetDirectionFromOrderType(OrderType()) == 1) {
// it is long order
profitTarget = OrderOpenPrice() + profitTarget;
} else {
profitTarget = OrderOpenPrice() - profitTarget;
}
}return(sqOrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), sqFixMarketPrice(profitTarget, OrderSymbol())));
}//+------------------------------------------------------------------+
bool sqOrderModify(int ticket, double price, double stopLoss, double profitTarget) {
if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
}int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);
if (digits > 0) {
stopLoss = NormalizeDouble(stopLoss, digits);
profitTarget = NormalizeDouble(profitTarget, digits);
}Verbose("Modifying order with ticket: ", IntegerToString(ticket), ", SL: ", DoubleToString(stopLoss), " and PT: ", DoubleToString(profitTarget));
int orderType = OrderType();
if(!sqCheckConnected()) {
return(false);
}bool result;
double closestPossibleSL, closestPossiblePT;double point = MarketInfo(OrderSymbol(), MODE_POINT);
double minStopLevel = MarketInfo(OrderSymbol(),MODE_STOPLEVEL);
if(stopLoss > 0) {
// check if SL isn't too close to price
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
if(orderType == OP_BUY) {
closestPossibleSL = NormalizeDouble(Bid-minStopLevel*point, digits);
} else {
closestPossibleSL = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits);
}if(stopLoss > closestPossibleSL) {
Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " > ", DoubleToString(closestPossibleSL));
return(false);
}} else {
if(orderType == OP_SELL) {
closestPossibleSL = NormalizeDouble(Ask+minStopLevel*point, digits);
} else {
closestPossibleSL = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits);
}if(stopLoss < closestPossibleSL) {
Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " < ", DoubleToString(closestPossibleSL));
return(false);
}
}
}
if(profitTarget > 0) {
// check if PT isn't too close to price
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
if(orderType == OP_BUY) {
closestPossiblePT = NormalizeDouble(Bid+minStopLevel*point, digits);
} else {
closestPossiblePT = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits);
}if(profitTarget < closestPossiblePT) {
Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " < ", DoubleToString(closestPossiblePT));
return(false);
}} else {
if(orderType == OP_SELL) {
closestPossiblePT = NormalizeDouble(Ask-minStopLevel*point, digits);
} else {
closestPossiblePT = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits);
}if(profitTarget > closestPossiblePT) {
Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " > ", DoubleToString(closestPossiblePT));
return(false);
}
}
}
result = OrderModifyReliable(ticket, price, sqFixMarketPrice(stopLoss, OrderSymbol()), sqFixMarketPrice(profitTarget, OrderSymbol()), OrderExpiration());
if(result) {
Verbose("Order modified successfuly");
return(true);
}return(false);
}//+------------------------------------------------------------------+
double sqGetPrice(int orderType, string symbol, double price) {
if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) {
// get newest Ask/Bid price for market order
RefreshRates();
if(orderType == OP_BUY) {
price = sqGetAsk(symbol);
} else {
price = sqGetBid(symbol);
}
}
int digits = (int) MarketInfo(symbol, MODE_DIGITS);if (digits > 0) price = NormalizeDouble(price, digits);
return(price);
}
//+------------------------------------------------------------------+double sqGetClosePrice(int orderType, string symbol, double price) {
if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) {
// get newest Ask/Bid price for market order
RefreshRates();
if(orderType == OP_BUY) {
price = sqGetBid(symbol);
} else {
price = sqGetAsk(symbol);
}
}
int digits = (int) MarketInfo(symbol, MODE_DIGITS);if (digits > 0) price = NormalizeDouble(price, digits);
return(price);
}//+------------------------------------------------------------------+
bool sqCheckConnected() {
if (!IsConnected()) {
Verbose("Not connected!");
return(false);
}
if (IsStopped()) {
Verbose("EA stopped!");
return(false);
}return(true);
}//+------------------------------------------------------------------+
int sleepPeriod = 500; // 0.5 s
int maxSleepPeriod = 20000; // 20 s.void sqSleep() {
//if(IsTesting()) return;Sleep(sleepPeriod);
int periods = maxSleepPeriod / sleepPeriod;
for(int i=0; i<periods; i++) {
if (MathRand() > 16383) {
// 50% chance of quitting
break;
}Sleep(sleepPeriod);
}
}//+------------------------------------------------------------------+
string sqGetOrderTypeAsString(int type) {
switch(type) {
case OP_BUY: return("Buy");
case OP_SELL: return("Sell");
case OP_BUYLIMIT: return("Buy Limit");
case OP_BUYSTOP: return("Buy Stop");
case OP_SELLLIMIT: return("Sell Limit");
case OP_SELLSTOP: return("Sell Stop");
}return("Unknown");
}//+------------------------------------------------------------------+
void sqInitInfoPanel() {
ObjectCreate("line1", OBJ_LABEL, 0, 0, 0);
ObjectSet("line1", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("line1", OBJPROP_YDISTANCE, sqOffsetVertical + 0 );
ObjectSet("line1", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("line1", "New strategy", 9, "Tahoma", sqLabelColor);ObjectCreate("linec", OBJ_LABEL, 0, 0, 0);
ObjectSet("linec", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("linec", OBJPROP_YDISTANCE, sqOffsetVertical + 16 );
ObjectSet("linec", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("linec", "Generated by StrategyQuant EA Wizard", 8, "Tahoma", sqLabelColor);ObjectCreate("line2", OBJ_LABEL, 0, 0, 0);
ObjectSet("line2", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("line2", OBJPROP_YDISTANCE, sqOffsetVertical + 28);
ObjectSet("line2", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("line2", "------------------------------------------", 8, "Tahoma", sqLabelColor);ObjectCreate("lines", OBJ_LABEL, 0, 0, 0);
ObjectSet("lines", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("lines", OBJPROP_YDISTANCE, sqOffsetVertical + 44);
ObjectSet("lines", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("lines", "Last Signal: -", 9, "Tahoma", sqLabelColor);ObjectCreate("lineopl", OBJ_LABEL, 0, 0, 0);
ObjectSet("lineopl", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("lineopl", OBJPROP_YDISTANCE, sqOffsetVertical + 60);
ObjectSet("lineopl", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("lineopl", "Open P/L: -", 8, "Tahoma", sqLabelColor);ObjectCreate("linea", OBJ_LABEL, 0, 0, 0);
ObjectSet("linea", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("linea", OBJPROP_YDISTANCE, sqOffsetVertical + 76);
ObjectSet("linea", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("linea", "Account Balance: -", 8, "Tahoma", sqLabelColor);ObjectCreate("lineto", OBJ_LABEL, 0, 0, 0);
ObjectSet("lineto", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("lineto", OBJPROP_YDISTANCE, sqOffsetVertical + 92);
ObjectSet("lineto", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("lineto", "Total profits/losses so far: -/-", 8, "Tahoma", sqLabelColor);ObjectCreate("linetp", OBJ_LABEL, 0, 0, 0);
ObjectSet("linetp", OBJPROP_CORNER, sqLabelCorner);
ObjectSet("linetp", OBJPROP_YDISTANCE, sqOffsetVertical + 108);
ObjectSet("linetp", OBJPROP_XDISTANCE, sqOffsetHorizontal);
ObjectSetText("linetp", "Total P/L so far: -", 8, "Tahoma", sqLabelColor);
}//+------------------------------------------------------------------+
void sqDeinitInfoPanel() {
ObjectDelete("line1");
ObjectDelete("linec");
ObjectDelete("line2");
ObjectDelete("lines");
ObjectDelete("lineopl");
ObjectDelete("linea");
ObjectDelete("lineto");
ObjectDelete("linetp");
}//+------------------------------------------------------------------+
void sqTextFillOpens() {
ObjectSetText("lineopl", "Open P/L: "+DoubleToStr(sqGetOpenPLInMoney(0), 2), 8, "Tahoma", sqLabelColor);
ObjectSetText("linea", "Account Balance: "+DoubleToStr(AccountBalance(), 2) , 8, "Tahoma", sqLabelColor);
}//+------------------------------------------------------------------+
void sqTextFillTotals() {
ObjectSetText("lineto", "Total profits/losses so far: "+DoubleToStr(sqGetTotalProfits(0, 100))+"/"+DoubleToStr(sqGetTotalLosses(0, 100)), 8, "Tahoma", sqLabelColor);
ObjectSetText("linetp", "Total P/L so far: "+DoubleToStr(sqGetTotalClosedPLInMoney(0, 1000), 2), 8, "Tahoma", sqLabelColor);
}
//+------------------------------------------------------------------+double sqGetOpenPLInMoney(int orderMagicNumber) {
double pl = 0;if(orderSelectTimeout > 0){
Sleep(orderSelectTimeout);
}
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
if(OrderSymbol() != Symbol()) continue;
if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue;pl += OrderProfit();
}return(pl);
}//+------------------------------------------------------------------+
int sqGetTotalProfits(int orderMagicNumber, int numberOfLastOrders) {
double pl = 0;
int count = 0;
int profits = 0;for(int i=OrdersHistoryTotal(); i>=0; i--) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
// return the P/L of last order
// or return the P/L of last order with given Magic Number
count++;if(OrderType() == OP_BUY) {
pl = (OrderClosePrice() - OrderOpenPrice());
} else {
pl = (OrderOpenPrice() - OrderClosePrice());
}if(pl > 0) {
profits++;
}if(count >= numberOfLastOrders) break;
}
}
}return(profits);
}//+------------------------------------------------------------------+
int sqGetTotalLosses(int orderMagicNumber, int numberOfLastOrders) {
double pl = 0;
int count = 0;
int losses = 0;for(int i=OrdersHistoryTotal(); i>=0; i--) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
// return the P/L of last order
// or return the P/L of last order with given Magic Number
count++;if(OrderType() == OP_BUY) {
pl = (OrderClosePrice() - OrderOpenPrice());
} else {
pl = (OrderOpenPrice() - OrderClosePrice());
}if(pl < 0) {
losses++;
}if(count >= numberOfLastOrders) break;
}
}
}return(losses);
}
//+------------------------------------------------------------------+double sqGetTotalClosedPLInMoney(int orderMagicNumber, int numberOfLastOrders) {
double pl = 0;
int count = 0;for(int i=OrdersHistoryTotal(); i>=0; i--) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {
if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
// return the P/L of last order or the P/L of last order with given Magic Numbercount++;
pl = pl + OrderProfit();if(count >= numberOfLastOrders) break;
}
}
}return(pl);
}//+------------------------------------------------------------------+
double sqGetSLLevel(string symbol, int orderType, double price, int valueInPips, double value) {
return(sqGetSLPTLevel(-1.0, symbol, orderType, price, valueInPips, value));
}//+------------------------------------------------------------------+
double sqGetPTLevel(string symbol, int orderType, double price, int valueInPips, double value) {
return(sqGetSLPTLevel(1.0, symbol, orderType, price, valueInPips, value));
}//+------------------------------------------------------------------+
/**
* valueType: 1 - pips, 2 - real pips (ATR range), 3 - price level
*/
double sqGetSLPTLevel(double SLorPT, string symbol, int orderType, double price, int valueType, double value) {
string correctedSymbol = correctSymbol(symbol);
double pointCoef = sqGetPointCoef(symbol);if(valueType == 1) {
// convert from pips to real points
value = sqConvertToRealPips(correctedSymbol, value);
}
if(price == 0) {
// price can be zero for market order
if(orderType == OP_BUY) {
price = sqGetAsk(correctedSymbol);
} else {
price = sqGetBid(correctedSymbol);
}
}
double slptValue = value;
if(valueType != 3) {
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
slptValue = price + (SLorPT * value);
} else {
slptValue = price - (SLorPT * value);
}
}// check that SL / PT is within predefined boundaries
double minSLPTValue, maxSLPTValue;
if(SLorPT < 0) {
// it is SL
if(MinimumSL <= 0) {
minSLPTValue = slptValue;
} else {
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
minSLPTValue = price + (SLorPT * MinimumSL * pointCoef);
slptValue = MathMin(slptValue, minSLPTValue);
} else {
minSLPTValue = price - (SLorPT * MinimumSL * pointCoef);
slptValue = MathMax(slptValue, minSLPTValue);
}
}
if(MaximumSL <= 0) {
maxSLPTValue = slptValue;
} else {
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
maxSLPTValue = price + (SLorPT * MaximumSL * pointCoef);
slptValue = MathMax(slptValue, maxSLPTValue);} else {
maxSLPTValue = price - (SLorPT * MaximumSL * pointCoef);
slptValue = MathMin(slptValue, maxSLPTValue);
}}
} else {
// it is PTif(MinimumPT <= 0) {
minSLPTValue = slptValue;
} else {
if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
minSLPTValue = price + (SLorPT * MinimumPT * pointCoef);
slptValue = MathMax(slptValue, minSLPTValue);
} else {
minSLPTValue = price - (SLorPT * MinimumPT * pointCoef);
slptValue = MathMin(slptValue, minSLPTValue);
}}
if(MaximumPT <= 0) {
maxSLPTValue = slptValue;
} else {if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
maxSLPTValue = price + (SLorPT * MaximumPT * pointCoef);
slptValue = MathMin(slptValue, maxSLPTValue);} else {
maxSLPTValue = price - (SLorPT * MaximumPT * pointCoef);
slptValue = MathMax(slptValue, maxSLPTValue);
}
}
}
return (slptValue);
}//+------------------------------------------------------------------+
double sqConvertToPips(string symbol, double value) {
if(symbol == "NULL" || symbol == "Current") {
return(value / gPointCoef);
}// recognize point coeficient
double ticksize = sqGetMarketTickSize(symbol);
if(ticksize < 0){
ticksize = calculatePointCoef(symbol);
}return(value / ticksize);
}
//+------------------------------------------------------------------+double sqConvertToRealPips(string symbol, double value) {
if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
return NormalizeDouble(gPointCoef * value, 6);
}double pointCoef = sqGetPointCoef(symbol);
return NormalizeDouble(pointCoef * value, 6);
}//+------------------------------------------------------------------+
double sqGetPointCoef(string symbol) {
if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
return(gPointCoef);
}return calculatePointCoef(symbol);
}//+------------------------------------------------------------------+
double calculatePointCoef(string symbol){
string correctedSymbol = correctSymbol(symbol);
if(UseSQTickSize) {
double ticksize = sqGetMarketTickSize(correctedSymbol);
if(ticksize >= 0){
return ticksize;
}
}
int realDigits = (int) MarketInfo(correctedSymbol, MODE_DIGITS);
if(realDigits > 0 && realDigits != 2 && realDigits != 4) {
realDigits -= 1;
}
return 1.0 / MathPow(10, realDigits);
}//+------------------------------------------------------------------+
bool sqDoublesAreEqual(double n1, double n2) {
string st1 = DoubleToStr(n1, Digits);
string st2 = DoubleToStr(n2, Digits);return (st1 == st2);
}//+------------------------------------------------------------------+
double sqHighest(string symbol, int timeframe, int computedFrom, int period, int shift) {
double maxnum = -100000000;
double val;for(int i=shift; i<shift+period; i++) {
val = sqGetValue(symbol, timeframe, computedFrom, i);if(val > maxnum) {
maxnum = val;
}
}return(maxnum);
}//+------------------------------------------------------------------+
double sqHighestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) {
double maxnum = -100000000;
int index = 0;
double val;for(int i=shift; i<shift+period; i++) {
val = sqGetValue(symbol, timeframe, computedFrom, i);if(val > maxnum) {
maxnum = val;
index = i;
}
}return(index);
}//+------------------------------------------------------------------+
double sqLowest(string symbol, int timeframe, int computedFrom, int period, int shift) {
double minnum = 100000000;
double val;for(int i=shift; i<shift+period; i++) {
val = sqGetValue(symbol, timeframe, computedFrom, i);if(val < minnum) {
minnum = val;
}
}return(minnum);
}//+------------------------------------------------------------------+
double sqLowestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) {
double minnum = 100000000;
int index = 0;
double val;for(int i=shift; i<shift+period; i++) {
val = sqGetValue(symbol, timeframe, computedFrom, i);if(val < minnum) {
minnum = val;
index = i;
}
}return(index);
}//+------------------------------------------------------------------+
double sqGetValue(string symbol, int timeframe, int computedFrom, int shift) {
double val = 0;
if(symbol == "NULL" || symbol == "Current") {
switch(computedFrom) {
case PRICE_OPEN: val = iOpen(NULL, timeframe, shift); break;
case PRICE_HIGH: return iHigh(NULL, timeframe, shift); break;
case PRICE_LOW: val = iLow(NULL, timeframe, shift); break;
case PRICE_CLOSE: val = iClose(NULL, timeframe, shift); break;
case PRICE_MEDIAN: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift))/2; break;
case PRICE_TYPICAL: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/3; break;
case PRICE_WEIGHTED: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/4; break;
}} else {
switch(computedFrom) {
case PRICE_OPEN: val = iOpen(symbol, timeframe, shift); break;
case PRICE_HIGH: val = iHigh(symbol, timeframe, shift); break;
case PRICE_LOW: val = iLow(symbol, timeframe, shift); break;
case PRICE_CLOSE: val = iClose(symbol, timeframe, shift); break;
case PRICE_MEDIAN: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift))/2; break;
case PRICE_TYPICAL: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/3; break;
case PRICE_WEIGHTED: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/4; break;
}
}return roundValue(val);
}//+------------------------------------------------------------------+
void sqDrawUpArrow(int shift) {
string name = StringConcatenate("Arrow_", MathRand());ObjectCreate(name, OBJ_ARROW, 0, Time[shift], Low[shift]-100*Point); //draw an up arrow
ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWUP);
ObjectSet(name, OBJPROP_COLOR, Green);
}//+------------------------------------------------------------------+
void sqDrawDownArrow(int shift) {
string name = StringConcatenate("Arrow_", MathRand());ObjectCreate(name, OBJ_ARROW, 0, Time[shift], High[shift]+100*Point); //draw an down arrow
ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN);
ObjectSet(name, OBJPROP_COLOR, Red);
}//+------------------------------------------------------------------+
void sqDrawVerticalLine(int shift) {
string name = StringConcatenate("VerticalLine", MathRand());ObjectCreate(name, OBJ_VLINE, 0, Time[shift], 0); //draw a vertical line
ObjectSet(name,OBJPROP_COLOR, Red);
ObjectSet(name,OBJPROP_WIDTH, 1);
ObjectSet(name,OBJPROP_STYLE, STYLE_DOT);
}//+------------------------------------------------------------------+
double sqDaily(string symbol, int tf, string mode, int shift) {
return sqGetOHLC(symbol, PERIOD_D1, mode, shift);
}//+------------------------------------------------------------------+
double sqWeekly(string symbol, int tf, string mode, int shift) {
return sqGetOHLC(symbol, PERIOD_W1, mode, shift);
}//+------------------------------------------------------------------+
double sqMonthly(string symbol, int tf, string mode, int shift) {
return sqGetOHLC(symbol, PERIOD_MN1, mode, shift);
}
//+------------------------------------------------------------------+double sqGetOHLC(string symbol, int tf, string mode, int shift){
if(symbol == "NULL" || symbol == "Current") {
if(mode == "Open") {
return(iOpen(NULL, tf, shift));
}
if(mode == "Close") {
return(iClose(NULL, tf, shift));
}
if(mode == "High") {
return(iHigh(NULL, tf, shift));
}
if(mode == "Low") {
return(iLow(NULL, tf, shift));
}
}
else {
if(mode == "Open") {
return(iOpen(symbol, tf, shift));
}
if(mode == "Close") {
return(iClose(symbol, tf, shift));
}
if(mode == "High") {
return(iHigh(symbol, tf, shift));
}
if(mode == "Low") {
return(iLow(symbol, tf, shift));
}
}return(-1);
}//+------------------------------------------------------------------+
int getHHMM(string time){
string result[];
int k = StringSplit(time, ':', result);
if(k == 2){
int hour = StrToInteger(StringSubstr(result[0], 0, 1) == "0" ? StringSubstr(result[0], 1, 1) : result[0]);
int minute = StrToInteger(StringSubstr(result[1], 0, 1) == "0" ? StringSubstr(result[1], 1, 1) : result[1]);
return (hour * 100) + minute;
}
else {
Print("Incorrect time value format. Value: '" + time + "'");
return 0;
}
}//+------------------------------------------------------------------+
int sqGetDate(int day, int month, int year) {
return (year - 1900) * 10000 + month * 100 + day;
}//+------------------------------------------------------------------+
int sqGetBarDate(datetime dt) {
return (TimeYear(dt) - 1900) * 10000 + TimeMonth(dt) * 100 + TimeDay(dt);
}//+------------------------------------------------------------------+
double sqGetTime(int hour, int minute, int second) {
return 100 * hour + minute + 0.01 * second;
}//+------------------------------------------------------------------+
int getSQTime(datetime time){
int minutesToday = (int) ((ulong) time / 60) % (24 * 60);
int hours = minutesToday / 60;
int minutes = minutesToday % 60;
return hours*100 + minutes;
}//+------------------------------------------------------------------+
double sqSafeDivide(double var1, double var2) {
if(var2 == 0) return(100000000);
return(var1/var2);
}//+------------------------------------------------------------------+
//+ Candle Pattern functions
//+------------------------------------------------------------------+bool sqBearishEngulfing(string symbol, int timeframe, int shift) {
double O = sqOpen(symbol, timeframe, shift);
double O1 = sqOpen(symbol, timeframe, shift+1);
double C = sqClose(symbol, timeframe, shift);
double C1 = sqClose(symbol, timeframe, shift+1);double ocDiff = NormalizeDouble(O-C, _Digits);
double o1c1Diff = NormalizeDouble(C1-O1, _Digits);if ((C1>O1)&&(O>C)&&(O>=C1)&&(O1>=C)&&(ocDiff>o1c1Diff)) {
return(true);
}return(false);
}//+------------------------------------------------------------------+
bool sqBullishEngulfing(string symbol, int timeframe, int shift) {
double O = sqOpen(symbol, timeframe, shift);
double O1 = sqOpen(symbol, timeframe, shift+1);
double C = sqClose(symbol, timeframe, shift);
double C1 = sqClose(symbol, timeframe, shift+1);double coDiff = NormalizeDouble(C-O, _Digits);
double o1c1Diff = NormalizeDouble(O1-C1, _Digits);
if ((O1>C1)&&(C>O)&&(C>=O1)&&(C1>=O)&&(coDiff>o1c1Diff)) {
return(true);
}return(false);
}//+------------------------------------------------------------------+
bool sqDarkCloudCover(string symbol, int timeframe, int shift) {
double L = sqLow(symbol, timeframe, shift);
double H = sqHigh(symbol, timeframe, shift);double O = sqOpen(symbol, timeframe, shift);
double O1 = sqOpen(symbol, timeframe, shift+1);
double C = sqClose(symbol, timeframe, shift);
double C1 = sqClose(symbol, timeframe, shift+1);
double tickSize = sqGetPointCoef(symbol);double Piercing_Line_Ratio = 0.5f;
double Piercing_Candle_Length = 10.0f;
double HL = NormalizeDouble(H-L, _Digits);
double OC = NormalizeDouble(O-C, _Digits);
double OC_HL = HL != 0 ? NormalizeDouble(OC/HL, 6) : 0;
double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits);
double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits);
if(C1 > O1 && O1C1_D2 > C && O > C && C > O1 && OC_HL > Piercing_Line_Ratio && HL >= PCL_MTS) {
return true;
}return(false);
}//+------------------------------------------------------------------+
bool sqDoji(string symbol, int timeframe, int shift) {
double diff = NormalizeDouble(MathAbs(sqOpen(symbol, timeframe, shift) - sqClose(symbol, timeframe, shift)), _Digits);
double coef = NormalizeDouble(sqGetPointCoef(symbol) * 0.6, _Digits);
if(diff < coef) {
return(true);
}
return(false);
}//+------------------------------------------------------------------+
bool sqHammer(string symbol, int timeframe, int shift) {
double H = sqHigh(symbol, timeframe, shift);
double L = sqLow(symbol, timeframe, shift);
double L1 = sqLow(symbol, timeframe, shift+1);
double L2 = sqLow(symbol, timeframe, shift+2);
double L3 = sqLow(symbol, timeframe, shift+3);double O = sqOpen(symbol, timeframe, shift);
double C = sqClose(symbol, timeframe, shift);
double CL = NormalizeDouble(H-L, _Digits);double BodyLow, BodyHigh;
double Candle_WickBody_Percent = 0.9;
double CandleLength = 12;if (O > C) {
BodyHigh = O;
BodyLow = C;
} else {
BodyHigh = C;
BodyLow = O;
}double LW = NormalizeDouble(BodyLow - L, _Digits);
double UW = NormalizeDouble(H - BodyHigh, _Digits);
double BLa = NormalizeDouble(MathAbs(O - C), _Digits);
double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits);
double pipValue = sqGetPointCoef(symbol);
double LW_D2 = NormalizeDouble(LW / 2, _Digits);
double LW_D3 = NormalizeDouble(LW / 3, _Digits);
double LW_D4 = NormalizeDouble(LW / 4, _Digits);
double BL90_M2 = NormalizeDouble(2 * BL90, _Digits);
double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits);
if(L <= L1 && L < L2 && L < L3) {
if(LW_D2 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D3 <= UW && LW_D4 <= UW) {
return(true);
}
if(LW_D3 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D4 <= UW) {
return(true);
}
if(LW_D4 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C) {
return(true);
}
}
return(false);
}//+------------------------------------------------------------------+
bool sqPiercingLine(string symbol, int timeframe, int shift) {
double L = sqLow(symbol, timeframe, shift);
double H = sqHigh(symbol, timeframe, shift);double O = sqOpen(symbol, timeframe, shift);
double O1 = sqOpen(symbol, timeframe, shift+1);
double C = sqClose(symbol, timeframe, shift);
double C1 = sqClose(symbol, timeframe, shift+1);
double tickSize = sqGetPointCoef(symbol);double Piercing_Line_Ratio = 0.5f;
double Piercing_Candle_Length = 10.0f;
double HL = NormalizeDouble(H-L, _Digits);
double CO = NormalizeDouble(C-O, _Digits);
double CO_HL = HL != 0 ? NormalizeDouble(CO/HL, 6) : 0;
double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits);
double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits);
if(C1 < O1 && O1C1_D2 < C && O < C && C < O1 && CO_HL > Piercing_Line_Ratio && HL >= PCL_MTS) {
return true;
}return(false);
}//+------------------------------------------------------------------+
bool sqShootingStar(string symbol, int timeframe, int shift) {
double L = sqLow(symbol, timeframe, shift);
double H = sqHigh(symbol, timeframe, shift);
double H1 = sqHigh(symbol, timeframe, shift + 1);
double H2 = sqHigh(symbol, timeframe, shift + 2);
double H3 = sqHigh(symbol, timeframe, shift + 3);double O = sqOpen(symbol, timeframe, shift);
double C = sqClose(symbol, timeframe, shift);
double CL = NormalizeDouble(H - L, _Digits);double BodyLow, BodyHigh;
double Candle_WickBody_Percent = 0.9;
double CandleLength = 12;if (O > C) {
BodyHigh = O;
BodyLow = C;
} else {
BodyHigh = C;
BodyLow = O;
}double LW = NormalizeDouble(BodyLow - L, _Digits);
double UW = NormalizeDouble(H - BodyHigh, _Digits);
double BLa = NormalizeDouble(MathAbs(O - C), _Digits);
double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits);
double pipValue = sqGetPointCoef(symbol);
double UW_D2 = NormalizeDouble(UW / 2, _Digits);
double UW_D3 = NormalizeDouble(UW / 3, _Digits);
double UW_D4 = NormalizeDouble(UW / 4, _Digits);
double BL90_M2 = NormalizeDouble(2 * BL90, _Digits);
double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits);if(H >= H1 && H > H2 && H > H3) {
if(UW_D2 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D3 <= LW && UW_D4 <= LW) {
return(true);
}
if(UW_D3 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D4 <= LW) {
return(true);
}
if(UW_D4 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C) {
return(true);
}
}return(false);
}
//+------------------------------------------------------------------+double sqOpen(string symbol, int timeframe, int shift) {
if(symbol == "NULL") {
return (iOpen(NULL, timeframe, shift));
} else {
return (iOpen(symbol, timeframe, shift));
}
}//+------------------------------------------------------------------+
double sqHigh(string symbol, int timeframe, int shift) {
if(symbol == "NULL") {
return (iHigh(NULL, timeframe, shift));
} else {
return (iHigh(symbol, timeframe, shift));
}
}//+------------------------------------------------------------------+
double sqLow(string symbol, int timeframe, int shift) {
if(symbol == "NULL") {
return (iLow(NULL, timeframe, shift));
} else {
return (iLow(symbol, timeframe, shift));
}
}//+------------------------------------------------------------------+
double sqClose(string symbol, int timeframe, int shift) {
if(symbol == "NULL") {
return (iClose(NULL, timeframe, shift));
} else {
return (iClose(symbol, timeframe, shift));
}
}
//+------------------------------------------------------------------+double sqTrueRange(string symbol, int timeframe, int shift) {
double close1 = sqClose(symbol, timeframe, shift+1);
double high = sqHigh(symbol, timeframe, shift+1);
double low = sqLow(symbol, timeframe, shift+1);double TrueHigh, TrueLow;
if(close1 > high) {
TrueHigh = close1;
} else {
TrueHigh = high;
}if(close1 < low) {
TrueLow = close1;
} else {
TrueLow = low;
}double TrueRange = TrueHigh - TrueLow;
return (TrueRange);
}//+------------------------------------------------------------------+
bool sqTradeRecentlyClosed(string symbol, int magicNumber, bool checkThisBar, bool checkThisMinute) {
int ordersChecked = 0;string strCurrentTimeMinutes = TimeToStr( TimeCurrent(), TIME_DATE|TIME_MINUTES);
for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) {// skip pending orders
if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) {
continue;
}if(magicNumber != 0 && OrderMagicNumber() != magicNumber) continue;
if(symbol != "Any") {
if(OrderSymbol() != correctSymbol(symbol)) continue;
}ordersChecked++;
if(ordersChecked > 10) {
// check only the very last 10 orders
break;
}if(checkThisBar) {
if(OrderCloseTime() >= Time[0]) {
// order finished this bar
return(true);
}
}if(checkThisMinute) {
string strCloseTimeMinutes = TimeToStr( OrderCloseTime(), TIME_DATE|TIME_MINUTES);if(strCurrentTimeMinutes == strCloseTimeMinutes) {
// order finished this minute
return(true);
}
}
}
}return(false);
}
//+------------------------------------------------------------------+double roundDown(double value, int decimals) {
double p = 0;
switch(decimals) {
case 0: return (int) value;
case 1: p = 10; break;
case 2: p = 100; break;
case 3: p = 1000; break;
case 4: p = 10000; break;
case 5: p = 100000; break;
case 6: p = 1000000; break;
default: p = MathPow(10, decimals);
}value = value * p;
double tmp = MathFloor(value + 0.00000001);
return NormalizeDouble(tmp/p, decimals);
}//+------------------------------------------------------------------+
class CSQTime {
public:datetime setHHMM(datetime time, string hhmm) {
string date = TimeToStr(time,TIME_DATE);//"yyyy.mm.dd"
return (StrToTime(date + " " + hhmm));
}//+------------------------------------------------------------------+
datetime correctDayStart(datetime time) {
MqlDateTime strTime;
TimeToStruct(time, strTime);
strTime.hour = 0;
strTime.min = 0;
strTime.sec = 0;
return (StructToTime(strTime));
}
//+------------------------------------------------------------------+datetime getDateInMs(datetime time) {
MqlDateTime strTime;
TimeToStruct(time, strTime);
strTime.hour = 0;
strTime.min = 0;
strTime.sec = 0;
return (StructToTime(strTime));
}
//+------------------------------------------------------------------+datetime correctDayEnd(datetime time) {
MqlDateTime strTime;
TimeToStruct(time, strTime);
strTime.hour = 23;
strTime.min = 59;
strTime.sec = 59;
return (StructToTime(strTime));
}
//+------------------------------------------------------------------+datetime setDayOfMonth(datetime time, int day) {
MqlDateTime strTime;
TimeToStruct(time, strTime);
strTime.day = day;
return (StructToTime(strTime));
}
//+------------------------------------------------------------------+int getMonth(datetime time) {
return TimeMonth(time);
}
//+------------------------------------------------------------------+int getDaysInMonth(datetime time) {
MqlDateTime strTime;
TimeToStruct(time, strTime);
if(strTime.mon==2) {
return 28+isLeapYear(strTime.year);
}
return 31-((strTime.mon-1)%7)%2;
}
//+------------------------------------------------------------------+bool isLeapYear(const int _year){
if(_year%4 == 0){
if(_year%400 == 0)return true;
if(_year%100 > 0)return true;
}
return false;
}
//+------------------------------------------------------------------+datetime addDays(datetime time, int days) {
int oneDay = 60 * 60 * 24;
return (time + (days * oneDay));
}
//+------------------------------------------------------------------+datetime setDayOfWeek(datetime time, int desiredDow) {
int dow = convertToSQDOW(TimeDayOfWeek(time));
desiredDow = convertToSQDOW(desiredDow);
int diffInDays = desiredDow - dow;
//Print("DiffInDays: ", diffInDays, ", dow: ", dow, ", desiredDow: ", desiredDow);
return addDays(time, diffInDays);
}
//+------------------------------------------------------------------+/**
* converts from MT DOW format: 0 = Sunday, 1 = Monday ... 6 = Saturday
* to SQ DOW format: 1 = Monday, 2 = Tuesday ... 7 = Sunday
*/
int convertToSQDOW(int dow) {
if(dow == 0) dow = 7;
return(dow);
}
};// create variable for class instance (required)
CSQTime* SQTime;//+------------------------------------------------------------------+
bool sqEvaluateFuzzySignal(int conditionsCount, int minTrueConditions) {
bool signalValue = false;
int trueConditionsCount = 0;
if(minTrueConditions <= 0) {
minTrueConditions = 1;
}
for(int i=0; i<conditionsCount; i++) {
bool value = cond[i];
if(value) {
trueConditionsCount++;
}
if(trueConditionsCount >= minTrueConditions) {
signalValue = true;
break;
}
}
return(signalValue);
}//+------------------------------------------------------------------+
string correctSymbol(string symbol){
if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
return Symbol();
}
else return symbol;
}//+------------------------------------------------------------------+
double sqFixMarketPrice(double price, string symbol){
symbol = correctSymbol(symbol);
double tickSize = MarketInfo(symbol, MODE_TICKSIZE);
if(tickSize == 0){
return price;
}
int digits = (int) MarketInfo(symbol, MODE_DIGITS);
double finalPrice = tickSize * MathRound(NormalizeDouble(price, digits) / tickSize);
return NormalizeDouble(finalPrice, digits);
}
//+------------------------------------------------------------------+bool sqIsUptrend(string symbol, int timeframe, int method) {
if(method == 0) {
return (iClose(symbol, timeframe, 1) > sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1));
}
return(false);
}//+------------------------------------------------------------------+
bool sqIsDowntrend(string symbol, int timeframe, int method) {
if(method == 0) {
return (iClose(symbol, timeframe, 1) < sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1));
}
return(false);
}
//+------------------------------------------------------------------+int sqGetMonthLastTradingDay(string symbol, int timeframe, bool includeWeekends) {
datetime barTime = iTime(symbol, timeframe, 0);
datetime lastTradingDate = SQTime.setDayOfMonth(barTime, SQTime.getDaysInMonth(barTime));if(!includeWeekends) {
if(TimeDayOfWeek(lastTradingDate) == 6) {
lastTradingDate = SQTime.addDays(lastTradingDate, -1);
} else if(TimeDayOfWeek(lastTradingDate) == 0) {
lastTradingDate = SQTime.addDays(lastTradingDate, -2);
}
}return TimeDay(lastTradingDate);
}//+------------------------------------------------------------------+
datetime monthFirstTradingDay = 0;
bool sqIsMonthFirstTradingDay(string symbol, int timeframe, bool includeWeekends) {
datetime date = SQTime.getDateInMs(iTime(symbol, timeframe, 0));
if(monthFirstTradingDay == 0) {
monthFirstTradingDay = date;
}if(SQTime.getMonth(monthFirstTradingDay)!=SQTime.getMonth(date)) {
if(!includeWeekends) {
if(TimeDayOfWeek(date) != 6 && TimeDayOfWeek(date) != 0) {
monthFirstTradingDay = date;
}
} else {
monthFirstTradingDay = date;
}
}return monthFirstTradingDay==date;
}//+------------------------------------------------------------------+
bool isMarketClosed(string symbol){
return !IsTesting() && !IsOptimization() && MarketInfo(symbol, MODE_TRADEALLOWED) == 0;
}//+------------------------------------------------------------------+
double fixLotSize(string symbol, double size){
string correctedSymbol = correctSymbol(symbol);
double Smallest_Lot = MarketInfo(correctedSymbol, MODE_MINLOT);
double Largest_Lot = MarketInfo(correctedSymbol, MODE_MAXLOT);
double LotStep = MarketInfo(correctedSymbol, MODE_LOTSTEP);double mod = MathMod(size, LotStep);
double finalSize = size;
if(MathAbs(mod - LotStep) > 0.000001){
finalSize -= mod;
}if(finalSize < Smallest_Lot){
Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is lower than minimum possible (", DoubleToStr(Smallest_Lot), "). Using minimum lot size...");
return Smallest_Lot;
}
else if(finalSize > Largest_Lot){
Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is larger than maximum possible (", DoubleToStr(Largest_Lot), "). Using maximum lot size...");
return Largest_Lot;
}
else {
return finalSize;
}
}double roundValue(double value){
return NormalizeDouble(value + 0.0000000001, 6);
}//+------------------------------------------------------------------+
int sqFixRanges(int value, int min, int max, int defaultVal) {
if(value < min || value > max) {
return (defaultVal);
}
return value;
}//+------------------------------------------------------------------+
double sqBarRange(string symbol, int timeframe, int shift) {
double range;
if(symbol == "NULL" || symbol == "Current") {
range = iHigh(NULL, timeframe, shift) - iLow(NULL, timeframe, shift);
} else {
range = iHigh(symbol, timeframe, shift) - iLow(symbol, timeframe, shift);
}
return roundValue(range);
}//+------------------------------------------------------------------+
double sqHeikenAshi(string symbol, int timeframe, string mode, int shift) {
if(symbol == "NULL" || symbol == "Current") {
if(mode == "Open") {
return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6));
}
if(mode == "Close") {
return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6));
}
if(mode == "High") {
return(NormalizeDouble(MathMax(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
}
if(mode == "Low") {
return(NormalizeDouble(MathMin(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
}} else {
if(mode == "Open") {
return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6));
}
if(mode == "Close") {
return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6));
}
if(mode == "High") {
return(NormalizeDouble(MathMax(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
}
if(mode == "Low") {
return(NormalizeDouble(MathMin(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
}
}return(-1);
}//+------------------------------------------------------------------+
double sqBiggestRange(string symbol, int timeframe, int period, int shift) {
double maxnum = -100000000;
double range;for(int i=shift; i<shift+period; i++) {
if(symbol == "NULL" || symbol == "Current") {
range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
} else {
range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
}if(range > maxnum) {
maxnum = range;
}
}return roundValue(maxnum);
}//+------------------------------------------------------------------+
double sqSmallestRange(string symbol, int timeframe, int period, int shift) {
double minnum = 100000000;
double range;for(int i=shift; i<shift+period; i++) {
if(symbol == "NULL" || symbol == "Current") {
range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
} else {
range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
}if(range < minnum) {
minnum = range;
}
}return roundValue(minnum);
}//+------------------------------------------------------------------+
double sqMA(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) {
ma_method = sqFixRanges(ma_method, 0, 3, 0);
applied_price = sqFixRanges(applied_price, 0, 6, 0);return roundValue(iMA(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift));
}//+------------------------------------------------------------------+
double sqTEMA(string symbol, int timeframe, int ma_period, int applied_price, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqTEMA", ma_period, applied_price, 0, shift));
}//+------------------------------------------------------------------+
double sqIchimoku(string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqIchimoku", tenkanPeriod, kijunPeriod, senkouPeriod, line, shift));
}//+------------------------------------------------------------------+
double sqAroon(string symbol, int timeframe, int period, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqAroon", period, false, false, line, shift));
}//+------------------------------------------------------------------+
double sqBBWidthRatio(string symbol, int timeframe, int period, double deviation, int appliedPrice, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqBBWidthRatio", period, deviation, appliedPrice, 0, shift));
}//+------------------------------------------------------------------+
double sqAvgVolume(string symbol, int timeframe, int period, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqAvgVolume", period, 1, shift));
}
//+------------------------------------------------------------------+double sqFibo(string symbol, int timeframe, int fiboRange, double fiboLevel) {
fiboRange = sqFixRanges(fiboRange, 1, 7, 1);return roundValue(iCustom(symbol, timeframe, "SqFibo", fiboRange, fiboLevel, 0, 0, 0));
}//+------------------------------------------------------------------+
double sqLinReg(string symbol, int timeframe, int period, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqLinReg", period, line, 0, shift));
}//+------------------------------------------------------------------+
double sqPivots(string symbol, int timeframe, int startHour, int startMinute, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqPivots", startHour, startMinute, line, shift));
}//+------------------------------------------------------------------+
double sqQQE(string symbol, int timeframe, int rsiPeriod, int sF, double wF, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqQQE", rsiPeriod, sF, wF, line, shift));
}//+------------------------------------------------------------------+
double sqKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqKeltnerChannel", period, Deviation, line, shift));
}//+------------------------------------------------------------------+
double sqMTKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqMTKeltnerChannel", period, Deviation, line, shift));
}//+------------------------------------------------------------------+
double sqRSI(string symbol, int timeframe, int period, int applied_price, int shift) {
return roundValue(iRSI(symbol, timeframe, period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqCCI(string symbol, int timeframe, int period, int applied_price, int shift) {
return roundValue(iCCI(symbol, timeframe, period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqAC(string symbol, int timeframe, int shift) {
return roundValue(iAC(symbol, timeframe, shift));
}//+------------------------------------------------------------------+
double sqADX(string symbol, int timeframe, int period, int line, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqADX", period, line, shift));
}//+------------------------------------------------------------------+
double sqATR(string symbol, int timeframe, int period, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqATR", period, 0, shift));
}//+------------------------------------------------------------------+
double sqAO(string symbol, int timeframe, int shift) {
return roundValue(iAO(symbol, timeframe, shift));
}//+------------------------------------------------------------------+
double sqBearsPower(string symbol, int timeframe, int period, int applied_price, int shift) {
return roundValue(iBearsPower(symbol, timeframe, period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqBullsPower(string symbol, int timeframe, int period, int applied_price, int shift) {
return roundValue(iBullsPower(symbol, timeframe, period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqDeMarker(string symbol, int timeframe, int period, int shift) {
return roundValue(iDeMarker(symbol, timeframe, period, shift));
}//+------------------------------------------------------------------+
double sqMACD(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int mode, int shift) {
return roundValue(iMACD(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, mode, shift));
}//+------------------------------------------------------------------+
double sqMomentum(string symbol, int timeframe, int period, int applied_price, int shift) {
return roundValue(iMomentum(symbol, timeframe, period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqStochastic(string symbol, int timeframe, int Kperiod, int Dperiod, int slowing, int method, int price_field, int mode, int shift) {
price_field = sqFixRanges(price_field, 0, 1, 0);
method = sqFixRanges(method, 0, 3, 0);
return roundValue(iCustom(symbol, timeframe, "SqStochastic", Kperiod, Dperiod, slowing, method, price_field, mode, shift));
}//+------------------------------------------------------------------+
double sqOsMA(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int shift) {
return roundValue(iOsMA(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, shift));
}//+------------------------------------------------------------------+
double sqBands(string symbol, int timeframe, int period, double deviation, int bands_shift, int applied_price, int mode, int shift) {
return roundValue(iBands(symbol, timeframe, period, deviation, bands_shift, applied_price, mode+1, shift));
}
//+------------------------------------------------------------------+double sqBBRange(string symbol, int timeframe, int period, double deviation, int applied_price, int shift) {
return roundValue(iBands(symbol, timeframe, period, deviation, 0, applied_price, 1, shift) - iBands(symbol, timeframe, period, deviation, 0, applied_price, 2, shift));
}//+------------------------------------------------------------------+
double sqSAR(string symbol, int timeframe, double step, double maximum, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqParabolicSAR", step, maximum, 0, shift));
//return roundValue(iSAR(symbol, timeframe, step, maximum, shift));
}//+------------------------------------------------------------------+
double sqStdDev(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) {
return roundValue(iStdDev(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift));
}//+------------------------------------------------------------------+
double sqHighestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqHighestInRange", timeFrom, timeTo, 0, shift));
}
//+------------------------------------------------------------------+double sqLowestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqLowestInRange", timeFrom, timeTo, 0, shift));
}//+------------------------------------------------------------------+
double sqFractal(string symbol, int timeframe, int fractal, int bufferIndex, int shift) {
return roundValue(iCustom(symbol, timeframe, "SqFractal", fractal, bufferIndex, shift));
}//+------------------------------------------------------------------+
bool sqIchimokuChikouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
double chikouSpan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift+1);
double chikouSpan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift);
double c = iClose(symbol, timeframe, shift);
double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
if(kumoBottom > kumoTop) {
double temp = kumoBottom;
kumoBottom = kumoTop;
kumoTop = temp;
}
signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
bool signal;
if(bullishOrBearish == -1) {
// bearish;
signal = (chikouSpan1 >= c) && (chikouSpan0 < c) && (chikouSpan1 > chikouSpan0);
if(signalStrength == 2) {
// for strong signal the cross should happen below kumo cloud
signal = signal && (c < kumoBottom);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (c < kumoTop);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;;
}
return signal;
} else if(bullishOrBearish == 1) {
// bullish
signal = (chikouSpan1 <= c) && (chikouSpan0 > c) && (chikouSpan1 < chikouSpan0);
if(signalStrength == 2) {
// for strong signal the cross should happen above kumo cloud
signal = signal && (c > kumoTop);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (c > kumoBottom);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;
}return signal;
} else {
return false;
}
}
//+------------------------------------------------------------------+bool sqIchimokuSenkouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
double senkouSpanA1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift+1);
double senkouSpanA0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
double senkouSpanB1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift+1);
double senkouSpanB0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
double c = iClose(symbol, timeframe, shift);
double kumoTop = MathMax(senkouSpanA0, senkouSpanB0);
double kumoBottom = MathMin(senkouSpanA0, senkouSpanB0);
bool signal;
signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
if(bullishOrBearish == -1) {
// bearish;
signal = (senkouSpanA1 > senkouSpanB1) && (senkouSpanA0 < senkouSpanB0);
if(signalStrength == 2) {
// for strong signal the cross should happen below kumo cloud
signal = signal && (c < kumoBottom);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (c < kumoTop);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;;
}
return signal;
} else if(bullishOrBearish == 1) {
// bullish
signal = (senkouSpanA1 < senkouSpanB1) && (senkouSpanA0 > senkouSpanB0);
if(signalStrength == 2) {
// for strong signal the cross should happen above kumo cloud
signal = signal && (c > kumoTop);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (c > kumoBottom);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;
}return signal;
} else {
return false;
}
}//+------------------------------------------------------------------+
bool sqIchimokuKijunSenCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
double o = iOpen(symbol, timeframe, shift);
double c = iClose(symbol, timeframe, shift);
double kijun = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift);double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
if(kumoBottom > kumoTop) {
double temp = kumoBottom;
kumoBottom = kumoTop;
kumoTop = temp;
}
bool signal;
signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
if(bullishOrBearish == -1) {
// bearish;
signal = (o > kijun) && c < kijun;
if(signalStrength == 2) {
// for strong signal the cross should happen below kumo cloud
signal = signal && (kijun < kumoBottom);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (kijun < kumoTop);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;;
}
return signal;
} else if(bullishOrBearish == 1) {
// bullish
signal = (o < kijun) && c > kijun;
if(signalStrength == 2) {
// for strong signal the cross should happen above kumo cloud
signal = signal && (kijun > kumoTop);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (kijun > kumoBottom);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;
}return signal;
} else {
return false;
}
}//+------------------------------------------------------------------+
bool sqIchimokuTenkanKijunCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
double tenkan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift+1);
double tenkan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift);double kijun1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift+1);
double kijun0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift);double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
if(kumoBottom > kumoTop) {
double temp = kumoBottom;
kumoBottom = kumoTop;
kumoTop = temp;
}
bool signal;
signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
if(bullishOrBearish == -1) {
// bearish;
signal = (tenkan1 > kijun1) && tenkan0 < kijun0;
if(signalStrength == 2) {
// for strong signal the cross should happen below kumo cloud
signal = signal && (tenkan0 < kumoBottom);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (tenkan0 < kumoTop);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;;
}
return signal;
} else if(bullishOrBearish == 1) {
// bullish
signal = (tenkan1 < kijun1) && tenkan0 > kijun0;
if(signalStrength == 2) {
// for strong signal the cross should happen above kumo cloud
signal = signal && (tenkan0 > kumoTop);
} else if(signalStrength == 1) {
// for neutral signal the cross should happen in kumo cloud
signal = signal && (tenkan0 > kumoBottom);
} else if(signalStrength == 0) {
// do nothing, if there is cross signal is always at least weak
} else {
return false;
}return signal;
} else {
return false;
}
}//+------------------------------------------------------------------+
bool sqIchimokuKumoBreakout(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift) {
double o = iOpen(symbol, timeframe, shift);
double c = iClose(symbol, timeframe, shift);double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
if(kumoBottom > kumoTop) {
double temp = kumoBottom;
kumoBottom = kumoTop;
kumoTop = temp;
}
bool signal;
if(bullishOrBearish == -1) {
// bearish;
signal = (o > kumoBottom) && c < kumoBottom;
return signal;
} else if(bullishOrBearish == 1) {
// bullish
signal = (o < kumoTop) && c > kumoTop;
return signal;
} else {
return false;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// ExitMethods includes
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// Move Stop Loss to Break Even
void sqManageSL2BE(int ticket) {double val = sqGetGlobalVariable(ticket, "MoveSL2BE");
if(val == 0) {
return;
}if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
return;
}double moveSLAtValue = sqGetValueByIdentification((string) val);
if(moveSLAtValue > 0) {
double newSL = 0;
int error;int valueType = (int) sqGetGlobalVariable(ticket, "MoveSL2BEType");
int orderType = OrderType();
int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
if(valueType == SLPTTYPE_RANGE) {
moveSLAtValue = Bid - moveSLAtValue;
}
} else {
if(valueType == SLPTTYPE_RANGE) {
moveSLAtValue = Ask + moveSLAtValue;
}
}moveSLAtValue = NormalizeDouble(moveSLAtValue, digits);
double addPips = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "SL2BEAddPips")), digits);
double currentSL = OrderStopLoss();if(orderType == OP_BUY) {
newSL = NormalizeDouble(OrderOpenPrice() + addPips, digits);if ((OrderOpenPrice() <= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL < newSL) && !sqDoublesAreEqual(currentSL, newSL)) {
Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(newSL));
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
}
}} else { // orderType == OP_SELL
newSL = NormalizeDouble(OrderOpenPrice() - addPips, digits);if ((OrderOpenPrice() >= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL > newSL) && !sqDoublesAreEqual(currentSL, newSL)) {
Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(newSL));
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
}
}
}
}
}
// Trailing Stop
void sqManageTrailingStop(int ticket) {double val = sqGetGlobalVariable(ticket, "TrailingStop");
if(val == 0) {
return;
}if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
return;
}
double tsValue = sqGetValueByIdentification((string) val);
if(tsValue > 0) {
double plValue;
int error;int valueType = (int) sqGetGlobalVariable(ticket, "TrailingStopType");
int orderType = OrderType();
int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
if(valueType == SLPTTYPE_RANGE) {
tsValue = Bid - tsValue;
}
} else {
if(valueType == SLPTTYPE_RANGE) {
tsValue = Ask + tsValue;
}
}tsValue = NormalizeDouble(tsValue, digits);
double tsActivation = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "TrailingActivation")), digits);
double currentSL = OrderStopLoss();if(orderType == OP_BUY) {
plValue = NormalizeDouble(Bid - OrderOpenPrice(), digits);if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL < tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) {
Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue));
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
}
}
} else { // orderType == OP_SELL
plValue = NormalizeDouble(OrderOpenPrice() - Ask, digits);if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL > tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) {
Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue));
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
}
}
}
}
}
void sqManageExitAfterXBars(int ticket) {
int exitBars = (int) sqGetGlobalVariable(ticket, "ExitAfterBars");
if(exitBars > 0) {
if (sqGetOpenBarsForOrder(ticket, exitBars+10) >= exitBars) {
Verbose("Exit After ", IntegerToString(exitBars), "bars - closing order with ticket: ", IntegerToString(OrderTicket()));
sqClosePositionAtMarket(OrderLots());
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// Trading Options includes
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+class CTradingOption {
public:
virtual bool onBarUpdate() = 0;
};//+------------------------------------------------------------------+
class CDontTradeOnWeekends: public CTradingOption {
private:
datetime thisFridayCloseTime;
datetime thisSundayOpenTime;
public:
CDontTradeOnWeekends() {
thisFridayCloseTime = D'1970.01.01';
thisSundayOpenTime = D'1970.01.01';
}//+----------------------------------------------+
virtual bool onBarUpdate() {
if(!DontTradeOnWeekends) {
return true;
}
if(!sqIsBarOpen()) {
return(true);
}datetime currentTime = TimeCurrent();
if(thisFridayCloseTime < 100) {
initTimes(currentTime, 0);
}
if(currentTime < thisFridayCloseTime) {
// trade normally
return true;
}
if(currentTime < thisSundayOpenTime) {
// do not allow opening new positions until sunday.
// returning false means there will be no more processing on this tick.
// this is what we want because we don't want to be trading after close of all positions
return false;
}
else {
// new week starting
initTimes(currentTime, DayOfWeek() == 0 ? 1 : 0);return true;
}
}//+----------------------------------------------+
void initTimes(datetime currentTime, int addDays) {
if(addDays > 0) {
thisFridayCloseTime = SQTime.addDays(currentTime, addDays);
} else {
thisFridayCloseTime = currentTime;
}
// set time of EOD
thisFridayCloseTime = SQTime.setDayOfWeek(thisFridayCloseTime, (FridayCloseTime == "00:00" || FridayCloseTime == "0:00") ? SATURDAY : FRIDAY);
thisFridayCloseTime = SQTime.setHHMM(thisFridayCloseTime, FridayCloseTime);
thisSundayOpenTime = SQTime.setDayOfWeek(currentTime, SUNDAY);
thisSundayOpenTime = SQTime.setHHMM(thisSundayOpenTime, SundayOpenTime);
}
};// create variable for class instance (required)
CDontTradeOnWeekends* objDontTradeOnWeekends;class CExitAtEndOfDay : public CTradingOption {
private:
datetime dailyEODExitTime;
datetime EODTime;
bool closedThisDay;
public:
CExitAtEndOfDay() {
dailyEODExitTime = D'1970.01.01';
EODTime = D'1970.01.01';
closedThisDay = false;
}//+----------------------------------------------+
virtual bool onBarUpdate() {
if(!ExitAtEndOfDay) {
return(true);
}
onTick();if(!sqIsBarOpen()) {
return(true);
}
datetime currentTime = TimeCurrent();if(currentTime > EODTime) {
//it is a new day
initTimesForCurrentDay(currentTime);
}if(currentTime >= dailyEODExitTime) {
// returning false means there will be no more processing on this tick
// this is what we want because we don't want to be trading after close of all positions
return(false);
}return(true);
}
//------------------------------------------------------------------------virtual void onTick() {
if(!ExitAtEndOfDay) {
return;
}
datetime currentTime = TimeCurrent();
datetime currentTimeDayStart = SQTime.correctDayStart(currentTime);
datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime);
if(!closedThisDay && currentTime >= dailyEODExitTime) {
// we should close all positions at midnight, so close them at the first tick of a new day
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {
if(!checkMagicNumber(OrderMagicNumber())) continue;
bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
//Close all orders at the end of a day. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start
if(currentTimeDayEnd == EODTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) {
if(isLiveOrder){
sqClosePositionAtMarket(OrderLots());
}
else {
sqDeletePendingOrder(OrderTicket());
}
}
}
}
closedThisDay = true;
}
}//+----------------------------------------------+
void initTimesForCurrentDay(datetime currentTime) {
// set end time of the current day (so that we now when new day starts)
EODTime = SQTime.correctDayEnd(currentTime);// set time of EOD
if(EODExitTime == "00:00" || EODExitTime == "0:00"){
dailyEODExitTime = EODTime;
}
else {
dailyEODExitTime = SQTime.setHHMM(currentTime, EODExitTime);
}
closedThisDay = false;
}
};// create variable for class instance (required)
CExitAtEndOfDay* objExitAtEndOfDay;
class CExitOnFriday : public CTradingOption {
private:
datetime thisFridayExitTime;
datetime thisSundayBeginTime;
datetime EOFDayTime;
bool closedThisWeek;
public:
CExitOnFriday() {
thisFridayExitTime = D'1970.01.01';
thisSundayBeginTime = D'1970.01.01';
closedThisWeek = false;
}//+----------------------------------------------+
virtual bool onBarUpdate() {
if(!ExitOnFriday) {
return true;
}
onTick();
if(!sqIsBarOpen()) {
return(true);
}datetime currentTime = TimeCurrent();
if(thisFridayExitTime < 100) {
initFridayExitTime(currentTime, 0);
}
if(currentTime < thisFridayExitTime) {
// trade normally
return true;
}
if(currentTime < thisSundayBeginTime) {
// do not allow opening new positions until sunday.
// returning false means there will be no more processing on this tick.
// this is what we want because we don't want to be trading after close of all positions
return false;
}
else {
// new week starting
initFridayExitTime(currentTime, DayOfWeek() == 0 ? 1 : 0);return true;
}
}
//------------------------------------------------------------------------virtual void onTick() {
if(!ExitOnFriday) {
return;
}
datetime currentTime = TimeCurrent();
datetime currentTimeDayStart = SQTime.correctDayStart(currentTime);
datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime);if(!closedThisWeek && currentTime >= thisFridayExitTime) {
// time is over friday closing time, we should close the positions
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {
if(!checkMagicNumber(OrderMagicNumber())) continue;
bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
//Close all orders at the end of Friday. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start
if(currentTimeDayEnd == EOFDayTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) {
if(isLiveOrder){
sqClosePositionAtMarket(OrderLots());
}
else {
sqDeletePendingOrder(OrderTicket());
}
}
}
}
closedThisWeek = true;
}
}//+----------------------------------------------+
void initFridayExitTime(datetime currentTime, int addDays) {
if(addDays > 0) {
thisFridayExitTime = SQTime.addDays(currentTime, addDays);
} else {
thisFridayExitTime = currentTime;
}
// set time of EOD
thisFridayExitTime = SQTime.setDayOfWeek(thisFridayExitTime, (FridayExitTime == "00:00" || FridayExitTime == "0:00") ? SATURDAY : FRIDAY);
thisFridayExitTime = SQTime.setHHMM(thisFridayExitTime, FridayExitTime);
EOFDayTime = SQTime.correctDayEnd(thisFridayExitTime);
thisSundayBeginTime = SQTime.setDayOfWeek(currentTime, SUNDAY);
thisSundayBeginTime = SQTime.correctDayStart(thisSundayBeginTime);
closedThisWeek = false;
}
};// create variable for class instance (required)
CExitOnFriday* objExitOnFriday;class CLimitTimeRange : public CTradingOption {
private:
datetime dailySignalTimeRangeFrom;
datetime dailySignalTimeRangeTo;
bool closedThisDay;
public:
CLimitTimeRange() {
closedThisDay = false;
}//+----------------------------------------------+
virtual bool onBarUpdate() {
if(!LimitTimeRange) {
return true;
}
onTick();
if(!sqIsBarOpen()) {
return true;
}
datetime currentTime = TimeCurrent();
if(currentTime > dailySignalTimeRangeTo) {
// it is new day
initTimesForCurrentDay(currentTime);
}if(currentTime < dailySignalTimeRangeFrom || currentTime >= dailySignalTimeRangeTo) {
// time is outside given range
// returning false means there will be no more processing on this tick
// this is what we want because we don't want to be trading outside of this time range
return false;
}
return true;
}
//------------------------------------------------------------------------virtual void onTick() {
if(!LimitTimeRange) {
return;
}
datetime currentTime = TimeCurrent();
if(!closedThisDay && ExitAtEndOfRange && currentTime >= dailySignalTimeRangeTo) {
for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
if (OrderSelect(cc, SELECT_BY_POS)) {
if(!checkMagicNumber(OrderMagicNumber())) continue;
bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
if(isLiveOrder){
if(OrderTypeToExit != 2) { // not pending only
sqClosePositionAtMarket(OrderLots());
}
}
else {
if(OrderTypeToExit != 1) { // not live only
sqDeletePendingOrder(OrderTicket());
}
}
}
}
closedThisDay = true;
}
}//------------------------------------------------------------------------
void initTimesForCurrentDay(datetime currentTime) {
// set time of range open
dailySignalTimeRangeFrom = SQTime.setHHMM(currentTime, SignalTimeRangeFrom);
dailySignalTimeRangeTo = SQTime.setHHMM(currentTime, SignalTimeRangeTo);int timeFrom = getHHMM(SignalTimeRangeFrom);
int timeTo = getHHMM(SignalTimeRangeTo);if(timeFrom >= timeTo){
if(getSQTime(currentTime) < timeTo){
dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, -1);
}
else {
dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1);
}
}
else {
if(currentTime > dailySignalTimeRangeTo) {
dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, 1);
dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1);
}
}closedThisDay = false;
}
};
// create variable for class instance (required)
CLimitTimeRange* objLimitTimeRange;class CMaxDistanceFromMarket : public CTradingOption {
private:
public:
CMaxDistanceFromMarket() {
}//+----------------------------------------------+
virtual bool onBarUpdate() {
return true;
}
};// create variable for class instance (required)
CMaxDistanceFromMarket* objMaxDistanceFromMarket;
class CMaxTradesPerDay : public CTradingOption {
private:
int lastHistoryPositionChecked;
datetime openTimeToday;
datetime EODTime;
bool reachedLimitToday;
public:
CMaxTradesPerDay() {
EODTime = D'1970.01.01';
lastHistoryPositionChecked = 0;
}//+----------------------------------------------+
virtual bool onBarUpdate() {
if(MaxTradesPerDay <= 0) {
return true;
}
datetime currentTime = TimeCurrent();if(currentTime > EODTime) {
// it is new day
initTimeForCurrentDay(currentTime);
}
if(reachedLimitToday) {
return false;
}
if(getNumberOfTradesToday() >= MaxTradesPerDay) {
reachedLimitToday = true;
return(false);
}
return true;
}//------------------------------------------------------------------------
void initTimeForCurrentDay(datetime currentTime) {
// set end time of the current day (so that we now when new day starts)
EODTime = SQTime.correctDayEnd(currentTime);openTimeToday = SQTime.correctDayStart(currentTime);
reachedLimitToday = false;
}
//------------------------------------------------------------------------int getNumberOfTradesToday() {
int todayTradesCount = 0;
int i = 0;// count closed trades that started today
int startAt = lastHistoryPositionChecked -10;
if(startAt < 0) {
startAt = 0;
}for(i=startAt;i<OrdersHistoryTotal();i++) {
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && checkMagicNumber(OrderMagicNumber())) {
lastHistoryPositionChecked = i;if(OrderOpenTime() >= openTimeToday) {
todayTradesCount++;
}
}
}for(i=0; i<OrdersTotal(); i++) {
if (OrderSelect(i,SELECT_BY_POS)==true && checkMagicNumber(OrderMagicNumber())) {if(OrderOpenTime() >= openTimeToday) {
todayTradesCount++;
}
}
}
return todayTradesCount;
}
};// create variable for class instance (required)
CMaxTradesPerDay* objMaxTradesPerDay;
class CMinMaxSLPT : public CTradingOption {
private:
public:
CMinMaxSLPT() {
}//+----------------------------------------------+
virtual bool onBarUpdate() {
return true;
}
};// create variable for class instance (required)
CMinMaxSLPT* objMinMaxSLPT;
// Money Management - Fixed Size used//=============================================================================
// OrderReliable.mqh
//
// Copyright ? 2006, Derk Wehler (derkwehler@gmail.com)
//
// This file is simply LibOrderReliable as a header file instead of a library
//
// In order to read this code most clearly in the Metaeditor, it is advised
// that you set your tab settings to 4 (instead of the default 3):
// Tools->Options->General Tab, set Tab Size to 4, uncheck "Insert spaces"
//
// ***************************************************************************
// OrderReliable library MIT license
//
// Copyright (c) 2006 Derk Wehler
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// LICENSE LIMITATION
// This MIT license is limited only for use of OrderReliable within
// strategies generated by StrategyQuant. Any method from this library
// that will be used outside of this source code will be governed
// by GPL license.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ***************************************************************************// ***************************************************************************
//
// A library for MT4 expert advisors, intended to give more reliable
// order handling. This library only concerns the mechanics of sending
// orders to the Metatrader server, dealing with transient connectivity
// problems better than the standard order sending functions. It is
// essentially an error-checking wrapper around the existing transaction
// functions. This library provides nothing to help actual trade strategies,
// but ought to be valuable for nearly all expert advisors which trade 'live'.
//
//
//=============================================================================
//
// Contents:
//
// OrderSendReliable()
// This is intended to be a drop-in replacement for OrderSend()
// which, one hopes is more resistant to various forms of errors
// prevalent with MetaTrader.
//
// OrderSendReliable2Step()
// This function is intended to be used when brokers do not allow
// initial stoploss and take-profit settings as part of the initial
// market order. After successfully playing an order, it will then
// Call OrderModifyReliable() to update the SL and TP settings.
//
// OrderModifyReliable()
// A replacement for OrderModify with more error handling.
//
// OrderCloseReliable()
// A replacement for OrderClose with more error handling.
//
// OrderCloseReliableMKT()
// This function is intended for closing orders ASAP; the
// principal difference is that in its internal retry-loop,
// it uses the new "Bid" and "Ask" real-time variables as opposed
// to the OrderCloseReliable() which uses only the price given upon
// entry to the routine. More likely to get the order closed if
// price moves, but more likely to "slip"
//
// OrderDeleteReliable()
// A replacement for OrderDelete with more error handling.
//
//===========================================================================
// CHANGE LOG BEGUN 28 March, 2014
// Prior to this, Source OffSite was used to save changes
// Start with revision 32, which is what SOS had as last change
//
// v32, 28 Mar 14:
// Small bug fixes for Build 600 changes
//
// v33, 25 Apr 16:
// Tiny adjustment made to GetOrderDetails() for non-forex pairs
//
// v34, 21 Jun 16:
// Changed SleepRandomTime() to just sleep 200ms
//
// v35, 20 Jul 16: (important)
// Added MySymbolConst2Val(), MySymbolVal2String(), necessary for correct
// functioning of GetOrderDetails()
//
// v36, 23 Apr 19: (Mark Fric, SQ)
// Added separate retry_attempts_bad_price variable that can configure repeat
// attempts for ERR_INVALID_PRICE and ERR_INVALID_STOPS errors
//
// 14.10.2020 (Tomas Brynda) - added ERR_MARKET_CLOSED on user requested
// "important when using Daily strategies
// during roll over market is closed for several seconds"
//
//===========================================================================
//=============================================================================
// OrderSendReliable()
//
// This is intended to be a drop-in replacement for OrderSend() which,
// one hopes, is more resistant to various forms of errors prevalent
// with MetaTrader.
//
// RETURN VALUE:
// Ticket number or -1 under some error conditions.
//
// FEATURES:
// * Re-trying under some error conditions, sleeping a random
// time defined by an exponential probability distribution.
//
// * Automatic normalization of Digits
//
// * Automatically makes sure that stop levels are more than
// the minimum stop distance, as given by the server. If they
// are too close, they are adjusted.
//
// * Automatically converts stop orders to market orders
// when the stop orders are rejected by the server for
// being to close to market. NOTE: This intentionally
// applies only to OP_BUYSTOP and OP_SELLSTOP,
// OP_BUYLIMIT and OP_SELLLIMIT are not converted to market
// orders and so for prices which are too close to current
// this function is likely to loop a few times and return
// with the "invalid stops" error message.
// Note, the commentary in previous versions erroneously said
// that limit orders would be converted. Note also
// that entering a BUYSTOP or SELLSTOP new order is distinct
// from setting a stoploss on an outstanding order; use
// OrderModifyReliable() for that.
//
// * Displays various error messages on the log for debugging.
//
// ORIGINAL AUTHOR AND DATE:
// Matt Kennel, 2006-05-28
//
//=============================================================================
int OrderSendReliable(string symbol, int cmd, double volume, double price,
int slippage, double stoploss, double takeprofit,
string comment="", int magic=0, datetime expiration=0,
color arrow_color=CLR_NONE)
{
OrderReliable_Fname = "OrderSendReliable";
int ticket = -1;
price = NormalizeDouble(price, Digits);
takeprofit = NormalizeDouble(takeprofit, Digits);
stoploss = NormalizeDouble(stoploss, Digits);
// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss,
takeprofit, comment, magic, expiration, arrow_color);
return(ticket);
}
}
// ========================================================================
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Get information about this order
double realPoint = MarketInfo(symbol, MODE_POINT);
double adjPoint = realPoint;
if (adjPoint == 0.00001 || adjPoint == 0.001)
adjPoint *= 10;
int digits;
double point, M = 0;
double bid, ask;
double sl, tp;
double priceNow = 0;
double hasSlippedBy = 0;
GetOrderDetails(0, symbol, cmd, digits, point, sl, tp, bid, ask, false);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OrderReliablePrint("Attempted " + OrderTypeToString(cmd) + " " + symbol + ": " + DoubleToStr(volume, 3) + " lots @" +
DoubleToStr(price, digits+1) + " sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1));
// Normalize all price / stoploss / takeprofit to the proper # of digits.
price = NormalizeDouble(price, digits);
stoploss = NormalizeDouble(stoploss, digits);
takeprofit = NormalizeDouble(takeprofit, digits);// Check stop levels, adjust if necessary
EnsureValidStops(symbol, cmd, price, stoploss, takeprofit);int cnt, cnt_bad_price;
GetLastError(); // clear the global variable.
int err = 0;
bool exit_loop = false;
bool limit_to_market = false;
bool fixed_invalid_price = false;// Concatenate to comment if enabled
double symSpr = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID);
if (AddSpreadToComment)
comment = comment + " (Spr: " + DoubleToStr(symSpr / adjPoint, 1) + ")";
// Limit/Stop order...............................................................
if (cmd > OP_SELL)
{
cnt = 0;
cnt_bad_price = 0;
while (!exit_loop)
{
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
// Calculating our own slippage internally should not need to be done for pending orders; see market orders below
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =OrderReliablePrint("About to call OrderSend(), comment = " + comment);
ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss,
takeprofit, comment, magic, expiration, arrow_color);
err = GetLastError();switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
break;// retryable errors
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_OFF_QUOTES:
case ERR_BROKER_BUSY:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_TRADE_TIMEOUT:
case ERR_TRADE_DISABLED:
case ERR_PRICE_CHANGED:
case ERR_REQUOTE:
case ERR_MARKET_CLOSED:
cnt++;
break;case ERR_INVALID_PRICE:
case ERR_INVALID_STOPS:
cnt++;
cnt_bad_price++;
break;case ERR_INVALID_TRADE_PARAMETERS:
default:
// an apparently serious error.
exit_loop = true;
break;} // end switch
if (cnt > retry_attempts)
exit_loop = true;if (cnt_bad_price > retry_attempts_bad_price)
exit_loop = true;
if (exit_loop)
{
if (!limit_to_market)
{
if (err != ERR_NO_ERROR && err != ERR_NO_RESULT)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
else if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")");
}
}
else
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
RefreshRates();
}
}// We have now exited from loop.
if (err == ERR_NO_ERROR || err == ERR_NO_RESULT)
{
OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
sqOrderPrint();
return(ticket); // SUCCESS!
}
if (!limit_to_market)
{
OrderReliablePrint("Failed to execute stop or limit order after " + IntegerToString(retry_attempts) + " retries");
OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol +
"@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
OrderReliablePrint("");
return(-1);
}
} // endif (limit_to_market)
{
OrderReliablePrint("Going from stop/limit order to market order because market is too close.");
cmd %= 2;
if (cmd == OP_BUY) price = ask;
else price = bid;
}// We now have a market order.
err = GetLastError(); // so we clear the global variable.
err = 0;
ticket = -1;
exit_loop = false;
// Market order..........................................................
if (cmd == OP_BUY || cmd == OP_SELL)
{
cnt = 0;
cnt_bad_price = 0;
while (!exit_loop)
{
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
// Get current price and calculate slippage
RefreshRates();
if (cmd == OP_BUY)
{
M = 1.0;
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // Open @ Ask
hasSlippedBy = (priceNow - price) / point; // (Adjusted Point)
}
else if (cmd == OP_SELL)
{
M = -1.0;
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // Open @ Bid
hasSlippedBy = (price - priceNow) / point; // (Adjusted Point)
}// Check if slippage is more than caller's maximum allowed
if (priceNow != price && hasSlippedBy > slippage)
{
// Actual price has slipped against us more than user allowed
// Log error message, sleep, and try again
OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips. Retrying...");
err = ERR_PRICE_CHANGED;
}
else
{
if (priceNow != price)
{
// If the price has slipped "acceptably" (either negative or within
// "Slippage" param), then we need to adjust the SL and TP accordingly
if (stoploss != 0) stoploss += M * hasSlippedBy;
if (takeprofit != 0) takeprofit += M * hasSlippedBy;
OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Requested Price = " + DoubleToStr(price, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips (\'positive slippage\'). Attempting order at market");
}
OrderReliablePrint("About to call OrderSend(), comment = " + comment);
ticket = OrderSend(symbol, cmd, volume, priceNow, (int)(slippage - hasSlippedBy),
stoploss, takeprofit, comment, magic, expiration, arrow_color);
err = GetLastError();
}
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
break;case ERR_INVALID_PRICE:
if (cmd == OP_BUY)
OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Ask = " + DoubleToStr(MarketInfo(symbol, MODE_ASK), Digits));
else
OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Bid = " + DoubleToStr(MarketInfo(symbol, MODE_BID), Digits));
cnt++; // a retryable error
cnt_bad_price++;
break;
case ERR_INVALID_STOPS:
OrderReliablePrint("INVALID STOPS on attempted " + OrderTypeToString(cmd) + " : " + DoubleToStr(volume, 2) + " lots " + " @ " + DoubleToStr(price, Digits) + ", SL = " + DoubleToStr(stoploss, Digits) + ", TP = " + DoubleToStr(takeprofit, Digits));
cnt++; // a retryable error
cnt_bad_price++;
break;
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_OFF_QUOTES:
case ERR_BROKER_BUSY:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_TRADE_TIMEOUT:
case ERR_TRADE_DISABLED:
case ERR_PRICE_CHANGED:
case ERR_REQUOTE:
case ERR_MARKET_CLOSED:
cnt++; // a retryable error
break;default:
// an apparently serious, unretryable error.
exit_loop = true;
break;
}if (cnt > retry_attempts)
exit_loop = true;if (cnt_bad_price > retry_attempts_bad_price)
exit_loop = true;if (exit_loop)
{
if (err != ERR_NO_ERROR && err != ERR_NO_RESULT)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")");
}
else
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
RefreshRates();
}
}// We have now exited from loop; if successful, return ticket #
if (err == ERR_NO_ERROR || err == ERR_NO_RESULT)
{
OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
sqOrderPrint();
return(ticket); // SUCCESS!
}
// If not successful, log and return -1
OrderReliablePrint("Failed to execute OP_BUY/OP_SELL, after " + IntegerToString(retry_attempts) + " retries");
OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol +
"@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(-1);
}
//=============================================================================
// OrderSendReliable2Step()
//
// Some brokers don't allow the SL and TP settings as part of the initial
// market order (Water House Capital). Therefore, this routine will first
// place the market order with no stop-loss and take-profit but later
// update the order accordingly
//
// RETURN VALUE:
// Same as OrderSendReliable; the ticket number
//
// NOTES:
// Order will not be updated if an error continues during
// OrderSendReliableMKT. No additional information will be logged
// since OrderSendReliableMKT would have already logged the error
// condition
//
// ORIGINAL AUTHOR AND DATE:
// Jack Tomlinson, 2007-05-29
//
//=============================================================================
int OrderSendReliable2Step(string symbol, int cmd, double volume, double price,
int slippage, double stoploss, double takeprofit,
string comment="", int magic=0, datetime expiration=0,
color arrow_color=CLR_NONE)
{
OrderReliable_Fname = "OrderSendReliable2Step";
int ticket = -1;
double slipped = 0;
price = NormalizeDouble(price, Digits);
takeprofit = NormalizeDouble(takeprofit, Digits);
stoploss = NormalizeDouble(stoploss, Digits);
// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0,
comment, magic, 0, arrow_color);if (!OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color))
OrderReliablePrint("Order Modify of Ticket #" + IntegerToString(ticket) + " FAILED");
return(ticket);
}
}
// ========================================================================
OrderReliablePrint("Doing OrderSendReliable, followed by OrderModifyReliable:");ticket = OrderSendReliable(symbol, cmd, volume, price, slippage,
0, 0, comment, magic, expiration, arrow_color);if (stoploss != 0 || takeprofit != 0)
{
if (ticket >= 0)
{
double theOpenPrice = price;
if (OrderSelect(ticket, SELECT_BY_TICKET))
{
slipped = OrderOpenPrice() - price;
theOpenPrice = OrderOpenPrice();
}
else
OrderReliablePrint("Failed to select ticket #" + IntegerToString(ticket) + " after successful 2step placement; cannot recalculate SL & TP");
if (slipped > 0)
{
OrderReliablePrint("2step order slipped by: " + DoubleToStr(slipped, Digits) + "; SL & TP modified by same amount");
if (takeprofit != 0) takeprofit += slipped;
if (stoploss != 0) stoploss += slipped;
}
OrderModifyReliable(ticket, theOpenPrice, stoploss, takeprofit, expiration, arrow_color);
}
}
else
OrderReliablePrint("Skipping OrderModifyReliable because no SL or TP specified.");return(ticket);
}
//=============================================================================
// OrderModifyReliable()
//
// This is intended to be a drop-in replacement for OrderModify() which,
// one hopes, is more resistant to various forms of errors prevalent
// with MetaTrader.
//
// RETURN VALUE:
// TRUE if successful, FALSE otherwise
//
// FEATURES:
// * Re-trying under some error conditions, sleeping a random
// time defined by an exponential probability distribution.
//
// * Displays various error messages on the log for debugging.
//
//
// ORIGINAL AUTHOR AND DATE:
// Matt Kennel, 2006-05-28
//
//=============================================================================
bool OrderModifyReliable(int ticket, double price, double stoploss,
double takeprofit, datetime expiration,
color arrow_color=CLR_NONE)
{
OrderReliable_Fname = "OrderModifyReliable";
bool result = false;
bool non_retryable_error = false;// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
result = OrderModify(ticket, price, stoploss,
takeprofit, expiration, arrow_color);
return(result);
}
}
// ========================================================================
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Get information about this order
string symbol = "ALLOCATE"; // This is so it has memory space allocated
int type;
int digits;
double point;
double bid, ask;
double sl, tp;
GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OrderReliablePrint("Attempted modify of #" + IntegerToString(ticket) + " price:" + DoubleToStr(price, digits+1) +
" sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1) +
" exp:" + TimeToStr(expiration));// Below, we call "EnsureValidStops". If the order we are modifying
// is a pending order, then we should use the price passed in. But
// if it's an open order, the price passed in is irrelevant; we need
// to use the appropriate bid or ask, so get those...
double prc = price;
if (type == OP_BUY) prc = bid;
else if (type == OP_SELL) prc = ask;// With the requisite info, we can do error checking on SL & TP
prc = NormalizeDouble(prc, digits);
price = NormalizeDouble(price, digits);
stoploss = NormalizeDouble(stoploss, digits);
takeprofit = NormalizeDouble(takeprofit, digits);
// If SL/TP are not changing then send in zeroes to EnsureValidStops(),
// so that it does not bother to try to change them
double newSL = stoploss;
double newTP = takeprofit;
if (stoploss == sl) newSL = 0;
if (takeprofit == tp) newTP = 0;
EnsureValidStops(symbol, type, prc, newSL, newTP, false);
if (stoploss != sl) stoploss = newSL;
if (takeprofit != tp) takeprofit = newTP;
int cnt = 0;
int cnt_bad_price = 0;
int err = GetLastError(); // so we clear the global variable.
err = 0;
bool exit_loop = false;while (!exit_loop)
{
result = OrderModify(ticket, price, stoploss,
takeprofit, expiration, arrow_color);
err = GetLastError();if (result == true)
exit_loop = true;
else
{
switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
break;case ERR_NO_RESULT:
// Modification to same value as before
// See below for reported result
exit_loop = true;
break;// Shouldn't be any reason stops are invalid (and yet I've seen it); try again
case ERR_INVALID_PRICE:
case ERR_INVALID_STOPS:
OrderReliablePrint("OrderModifyReliable, ERR_INVALID_STOPS, Broker\'s Min Stop Level (in pips) = " + DoubleToStr(MarketInfo(symbol, MODE_STOPLEVEL) * Point / AdjPoint(symbol), 1));
// EnsureValidStops(symbol, price, stoploss, takeprofit);
cnt_bad_price++;
case ERR_COMMON_ERROR:
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_TOO_FREQUENT_REQUESTS:
case ERR_TRADE_TIMEOUT: // for modify this is a retryable error, I hope.
case ERR_OFF_QUOTES:
case ERR_BROKER_BUSY:
case ERR_TOO_MANY_REQUESTS:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_TRADE_DISABLED:
case ERR_MARKET_CLOSED:
cnt++; // a retryable error
break;case ERR_TRADE_MODIFY_DENIED:
// This one may be important; have to Ensure Valid Stops AND valid price (for pends)
break;
case ERR_PRICE_CHANGED:
case ERR_REQUOTE:
RefreshRates();
continue; // we can apparently retry immediately according to MT docs.default:
// an apparently serious, unretryable error.
exit_loop = true;
non_retryable_error = true;
break;} // end switch
}if (cnt > retry_attempts)
exit_loop = true;if (cnt_bad_price > retry_attempts_bad_price)
exit_loop = true;if (!exit_loop)
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
RefreshRates();
}
else
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
else if (non_retryable_error)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
}
}// we have now exited from loop.
if (err == ERR_NO_RESULT)
{
OrderReliablePrint("Server reported modify order did not actually change parameters.");
OrderReliablePrint("Redundant modification: " + IntegerToString(ticket) + " " + symbol +
"@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
OrderReliablePrint("Suggest modifying code logic to avoid.");
}
if (result)
{
OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Modification successful, updated trade details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
sqOrderPrint();
}
else
{
OrderReliablePrint("Failed to execute modify after " + IntegerToString(retry_attempts) + " retries");
OrderReliablePrint("Failed modification: " + IntegerToString(ticket) + " " + symbol +
"@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(result);
}
//=============================================================================
// OrderCloseReliable()
//
// This is intended to be a drop-in replacement for OrderClose() which,
// one hopes, is more resistant to various forms of errors prevalent
// with MetaTrader.
//
// RETURN VALUE:
// TRUE if successful, FALSE otherwise
//
// FEATURES:
// * Re-trying under some error conditions, sleeping a random
// time defined by an exponential probability distribution.
//
// * Displays various error messages on the log for debugging.
//
// ORIGINAL AUTHOR AND DATE:
// Derk Wehler, 2006-07-19
//
//=============================================================================
bool OrderCloseReliable(int ticket, double volume, double price,
int slippage, color arrow_color=CLR_NONE)
{
OrderReliable_Fname = "OrderCloseReliable";
bool result = false;
bool non_retryable_error = false;
// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
result = OrderClose(ticket, volume, price, slippage, arrow_color);
return(result);
}
}
// ========================================================================
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Get information about this order
string symbol = "ALLOCATE"; // This is so it has memory space allocated
int type;
int digits;
double point;
double bid, ask;
double sl, tp;
GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) +
" lots:" + DoubleToStr(volume, 3) + " slippage:" + IntegerToString(slippage));
if (type != OP_BUY && type != OP_SELL)
{
OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL");
return(false);
}
int cnt = 0;
int err = GetLastError(); // so we clear the global variable.
err = 0;
bool exit_loop = false;
double priceNow = 0;
double hasSlippedBy = 0;while (!exit_loop)
{
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
// Get current price and calculate slippage
RefreshRates();
if (type == OP_BUY)
{
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // Close @ Bid
hasSlippedBy = (price - priceNow) / point; // (Adjusted Point)
}
else if (type == OP_SELL)
{
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // Close @ Ask
hasSlippedBy = (priceNow - price) / point; // (Adjusted Point)
}// Check if slippage is more than caller's maximum allowed
if (priceNow != price && hasSlippedBy > slippage)
{
// Actual price has slipped against us more than user allowed
// Log error message, sleep, and try again
OrderReliablePrint("Actual Price (Bid for buy, Ask for sell) Value = " + DoubleToStr(priceNow, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips. Retrying...");
result = false;
err = ERR_PRICE_CHANGED;
}
else
{
result = OrderClose(ticket, volume, priceNow, (int)(slippage - hasSlippedBy), arrow_color);
err = GetLastError();
}
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =if (result == true)
exit_loop = true;
else
{
switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
OrderReliablePrint("If order did not actually close, error code is apparently wrong");
break;case ERR_NO_RESULT:
exit_loop = true;
OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting");
OrderReliablePrint("If order did not actually close, error code is apparently wrong");
break;case ERR_INVALID_PRICE:
OrderReliablePrint("ERR_INVALID_PRICE received, but should not occur since we are refreshing rates");
cnt++; // a retryable error
break;case ERR_PRICE_CHANGED:
case ERR_COMMON_ERROR:
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_TOO_FREQUENT_REQUESTS:
case ERR_TRADE_TIMEOUT: // for close this is a retryable error, I hope.
case ERR_TRADE_DISABLED:
case ERR_OFF_QUOTES:
case ERR_BROKER_BUSY:
case ERR_REQUOTE:
case ERR_TOO_MANY_REQUESTS:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_MARKET_CLOSED:
cnt++; // a retryable error
break;default:
// Any other error is an apparently serious, unretryable error.
exit_loop = true;
non_retryable_error = true;
break;} // end switch
}if (cnt > retry_attempts)
exit_loop = true;if (exit_loop)
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
else if (non_retryable_error)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
}
else
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
}
}// We have now exited from loop
if (result || err == ERR_NO_RESULT || err == ERR_NO_ERROR)
{
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else if (OrderCloseTime() > 0) // Then it closed ok
OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else
{
OrderReliablePrint("Close result reported success (or failure, but w/ERR_NO_ERROR); yet order remains! Must re-try close from EA logic!");
OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " +
DoubleToString(price) + ", Slippage: " + DoubleToString(slippage));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
result = false;
}
}
else
{
OrderReliablePrint("Failed to execute close after " + IntegerToString(cnt-1) + " retries");
OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " + DoubleToString(priceNow) +
" (Requested Price: " + DoubleToString(price) + "), Slippage: " + IntegerToString(slippage));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(result);
}
//=============================================================================
// OrderCloseReliableMKT()
//
// This function is intended for closing orders ASAP; the principal
// difference is that in its internal retry-loop, it uses the new "Bid"
// and "Ask" real-time variables as opposed to the OrderCloseReliable(),
// which uses only the price given upon entry to the routine. More likely
// to get the order closed if price moves, but more likely to "slip"
//
// RETURN VALUE:
// TRUE if successful, FALSE otherwise
//
// FEATURES:
// * Re-trying under some error conditions, sleeping a random
// time defined by an exponential probability distribution.
//
// * Displays various error messages on the log for debugging.
//
// ORIGINAL AUTHOR AND DATE:
// Derk Wehler, 2009-04-03
//
//=============================================================================
bool OrderCloseReliableMKT(int ticket, double volume, double price,
int slippage, color arrow_color=CLR_NONE)
{
OrderReliable_Fname = "OrderCloseReliableMKT";
bool result = false;
bool non_retryable_error = false;
// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
result = OrderClose(ticket, volume, price, slippage, arrow_color);
return(result);
}
}
// ========================================================================
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Get information about this order
string symbol = "ALLOCATE"; // This is so it has memory space allocated
int type;
int digits;
double point;
double bid, ask;
double sl, tp;
GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) +
" lots:" + DoubleToStr(price, 3) + " slippage:" + IntegerToString(slippage));
if (type != OP_BUY && type != OP_SELL)
{
OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL");
return(false);
}
int cnt = 0;
int err = GetLastError(); // so we clear the global variable.
err = 0;
bool exit_loop = false;
double pnow = 0;
int slippagenow = 0;while (!exit_loop)
{
if (type == OP_BUY)
{
pnow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
if (pnow > price)
{
// Do not allow slippage to go negative; will cause error
slippagenow = (int) MathMax(0, slippage - (pnow - price) / point);
}
}
else if (type == OP_SELL)
{
pnow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
if (pnow < price)
{
// Do not allow slippage to go negative; will cause error
slippagenow = (int) MathMax(0, slippage - (price - pnow) / point);
}
}result = OrderClose(ticket, volume, pnow, slippagenow, arrow_color);
err = GetLastError();if (result == true)
exit_loop = true;
else
{
switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
break;case ERR_NO_RESULT:
exit_loop = true;
OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting");
break;case ERR_COMMON_ERROR:
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_TOO_FREQUENT_REQUESTS:
case ERR_TRADE_TIMEOUT: // for close this is a retryable error, I hope.
case ERR_TRADE_DISABLED:
case ERR_PRICE_CHANGED:
case ERR_INVALID_PRICE:
case ERR_OFF_QUOTES:
case ERR_BROKER_BUSY:
case ERR_REQUOTE:
case ERR_TOO_MANY_REQUESTS:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_MARKET_CLOSED:
cnt++; // a retryable error
break;default:
// Any other error is an apparently serious, unretryable error.
exit_loop = true;
non_retryable_error = true;
break;} // end switch
}if (cnt > retry_attempts)
exit_loop = true;if (!exit_loop)
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+ ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
}if (exit_loop)
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
else if (non_retryable_error)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
}
}// we have now exited from loop.
if (result)
{
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else if (OrderCloseTime() > 0) // Then it closed ok
OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else
{
OrderReliablePrint("Close result reported success, but order remains! Must re-try close from EA logic!");
OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " +
DoubleToString(price) + ", Slippage: " + IntegerToString(slippage));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
result = false;
}
}
else
{
OrderReliablePrint("Failed to execute close after " + IntegerToString(retry_attempts) + " retries");
OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " +
DoubleToString(pnow) + " (Initial Price: " + DoubleToString(price) + "), Slippage: " +
IntegerToString(slippagenow) + " (Initial Slippage: " + IntegerToString(slippage) + ")");
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(result);
}
//=============================================================================
// OrderDeleteReliable()
//
// This is intended to be a drop-in replacement for OrderDelete() which,
// one hopes, is more resistant to various forms of errors prevalent
// with MetaTrader.
//
// RETURN VALUE:
// TRUE if successful, FALSE otherwise
//
//
// FEATURES:
// * Re-trying under some error conditions, sleeping a random
// time defined by an exponential probability distribution.
//
// * Displays various error messages on the log for debugging.
//
// ORIGINAL AUTHOR AND DATE:
// Derk Wehler, 2006-12-21
//
//=============================================================================
bool OrderDeleteReliable(int ticket, color clr=CLR_NONE)
{
OrderReliable_Fname = "OrderDeleteReliable";
bool result = false;
bool non_retryable_error = false;// ========================================================================
// If testing or optimizing, there is no need to use this lib, as the
// orders are not real-world, and always get placed optimally. By
// refactoring this option to be in this library, one no longer needs
// to create similar code in each EA.
if (!UseForTesting)
{
if (IsOptimization() || IsTesting())
{
result = OrderDelete(ticket, clr);
return(result);
}
}
// ========================================================================
OrderReliablePrint("Attempted deletion of pending order, #" + IntegerToString(ticket));
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Get information about this order
string symbol = "ALLOCATE"; // This is so it has memory space allocated
int type;
int digits;
double point;
double bid, ask;
double sl, tp;
GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (type == OP_BUY || type == OP_SELL)
{
OrderReliablePrint("error: Trying to close ticket #" + IntegerToString(ticket) +
", which is " + OrderTypeToString(type) +
", not OP_BUYSTOP, OP_SELLSTOP, OP_BUYLIMIT, or OP_SELLLIMIT");
return(false);
}
int cnt = 0;
int err = GetLastError(); // so we clear the global variable.
err = 0;
bool exit_loop = false;while (!exit_loop)
{
result = OrderDelete(ticket, clr);
err = GetLastError();if (result == true)
exit_loop = true;
else
{
switch (err)
{
case ERR_NO_ERROR:
exit_loop = true;
OrderReliablePrint("ERR_NO_ERROR received, but OrderDelete() returned false; exiting");
break;case ERR_NO_RESULT:
exit_loop = true;
OrderReliablePrint("ERR_NO_RESULT received, but OrderDelete() returned false; exiting");
break;case ERR_COMMON_ERROR:
case ERR_SERVER_BUSY:
case ERR_NO_CONNECTION:
case ERR_TOO_FREQUENT_REQUESTS:
case ERR_TRADE_TIMEOUT: // for delete this is a retryable error, I hope.
case ERR_TRADE_DISABLED:
case ERR_OFF_QUOTES:
case ERR_PRICE_CHANGED:
case ERR_BROKER_BUSY:
case ERR_REQUOTE:
case ERR_TOO_MANY_REQUESTS:
case ERR_TRADE_CONTEXT_BUSY:
case ERR_MARKET_CLOSED:
cnt++; // a retryable error
break;default: // Any other error is an apparently serious, unretryable error.
exit_loop = true;
non_retryable_error = true;
break;} // end switch
}if (cnt > retry_attempts)
exit_loop = true;if (!exit_loop)
{
OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
}
else
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
else if (non_retryable_error)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
}
}// we have now exited from loop.
if (result)
{
OrderReliablePrint("Successful deletion of Ticket #" + IntegerToString(ticket));
return(true); // SUCCESS!
}
else
{
OrderReliablePrint("Failed to execute delete after " + IntegerToString(retry_attempts) + " retries");
OrderReliablePrint("Failed deletion: Ticket #" + IntegerToString(ticket));
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(result);
}//=============================================================================
//=============================================================================
// Utility Functions
//=============================================================================
//=============================================================================string OrderReliableErrTxt(int err)
{
return (IntegerToString(err) + " :: " + ErrorDescription(err));
}
// Defaut level is 3
// Use level = 1 to Print all but "Retry" messages
// Use level = 0 to Print nothing
void OrderReliableSetErrorLevel(int level)
{
ErrorLevel = level;
}
void OrderReliablePrint(string s)
{
// Print to log prepended with stuff;
if (ErrorLevel >= 99 || (!(IsTesting() || IsOptimization())))
{
if (ErrorLevel > 0)
Print(OrderReliable_Fname + " " + OrderReliableVersion + ": " + s);
}
}
void sqOrderPrint() {
Print("Ticket: "+IntegerToString(OrderTicket())+" - "+
"OpenTime: "+TimeToString(OrderOpenTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+
"Type: "+IntegerToString(OrderType())+","+
"Size: "+DoubleToString(OrderLots())+","+
"Symbol: "+OrderSymbol()+","+
"OpenPrice: "+DoubleToString(OrderOpenPrice())+","+
"SL: "+DoubleToString(OrderStopLoss())+","+
"PT: "+DoubleToString(OrderTakeProfit()));Print("Ticket: "+IntegerToString(OrderTicket())+" (continue) - "+
"CloseTime: "+TimeToString(OrderCloseTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+
"ClosePrice: "+DoubleToString(OrderClosePrice())+","+
"Commission: "+DoubleToString(OrderCommission())+","+
"Swap: "+DoubleToString(OrderSwap())+","+
"Profit: "+DoubleToString(OrderProfit())+","+
"Comment: "+OrderComment()+","+
"MagicNumber: "+IntegerToString(OrderMagicNumber()));
}string OrderTypeToString(int type)
{
if (type == OP_BUY) return("BUY");
if (type == OP_SELL) return("SELL");
if (type == OP_BUYSTOP) return("BUY STOP");
if (type == OP_SELLSTOP) return("SELL STOP");
if (type == OP_BUYLIMIT) return("BUY LIMIT");
if (type == OP_SELLLIMIT) return("SELL LIMIT");
return("None (" + IntegerToString(type) + ")");
}
//=============================================================================
// EnsureValidStops()
//
// Most MQ4 brokers have a minimum stop distance, which is the number of
// pips from price where a pending order can be placed or where a SL & TP
// can be placed. THe purpose of this function is to detect when the
// requested SL or TP is too close, and to move it out automatically, so
// that we do not get ERR_INVALID_STOPS errors.
//
// FUNCTION COMPLETELY OVERHAULED:
// Derk Wehler, 2008-11-08
//
//=============================================================================
void EnsureValidStops(string symbol, int cmd, double price, double& sl, double& tp, bool isNewOrder=true)
{
string prevName = OrderReliable_Fname;
OrderReliable_Fname = "EnsureValidStops";
double point = MarketInfo(symbol, MODE_POINT);
// We only use point for StopLevel, and StopLevel is reported as 10 times
// what you expect on a 5-digit broker, so leave it as is.
//if (point == 0.001 || point == 0.00001)
// point *= 10;
double orig_sl = sl;
double orig_tp = tp;
double new_sl, new_tp;
int min_stop_level = (int) MarketInfo(symbol, MODE_STOPLEVEL);
double servers_min_stop = min_stop_level * point;
double spread = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID);
//Print(" EnsureValidStops: Symbol = " + symbol + ", servers_min_stop = " + servers_min_stop);// Skip if no S/L (zero)
if (sl != 0)
{
if (cmd % 2 == 0) // we are long
{
// for pending orders, sl/tp can bracket price by servers_min_stop
new_sl = price - servers_min_stop;
//Print(" EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] - servers_min_stop [", servers_min_stop, "]");
// for market order, sl/tp must bracket bid/ask
if (cmd == OP_BUY && isNewOrder)
{
new_sl -= spread;
//Print(" EnsureValidStops: Minus spread [", spread, "]");
}
sl = MathMin(sl, new_sl);
}
else // we are short
{
new_sl = price + servers_min_stop; // we are short
//Print(" EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] + servers_min_stop [", servers_min_stop, "]");
// for market order, sl/tp must bracket bid/ask
if (cmd == OP_SELL && isNewOrder)
{
new_sl += spread;
//Print(" EnsureValidStops: Plus spread [", spread, "]");
}sl = MathMax(sl, new_sl);
}
sl = NormalizeDouble(sl, (int) MarketInfo(symbol, MODE_DIGITS));
}
// Skip if no T/P (zero)
if (tp != 0)
{
// check if we have to adjust the stop
if (MathAbs(price - tp) <= servers_min_stop)
{
if (cmd % 2 == 0) // we are long
{
new_tp = price + servers_min_stop; // we are long
tp = MathMax(tp, new_tp);
}
else // we are short
{
new_tp = price - servers_min_stop; // we are short
tp = MathMin(tp, new_tp);
}
tp = NormalizeDouble(tp, (int) MarketInfo(symbol, MODE_DIGITS));
}
}
// notify if changed
if (sl != orig_sl)
OrderReliablePrint("SL was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved SL to: " + DoubleToString(sl));
if (tp != orig_tp)
OrderReliablePrint("TP was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved TP to: " + DoubleToString(tp));
OrderReliable_Fname = prevName;
}
//=============================================================================
// EnsureValidPendPrice()
//
// This function is called if OrderSendReliable gets an ERR_INVALID_PRICE
// or ERR_INVALID_STOPS error when attempting to place a pending order.
// We assume these are signs that the brokers minumum stop distance, which
// is what is used for pending distances as well, is too small and the price
// is too close to the pending's requested price. Therefore we want to do
// one of two things:
//
// If UseLimitToMarket is enabled, then see if the actual and requested
// prices are close enough to be within the requested slippage, and if so
// return true to indicate a swap to a market order.
//
// Otherwise, we move the requested price far enough from current price to
// (hopefully) place the pending order, and return false (price, sl & tp
// are all I/O params). If this does not work, and the the same error is
// received, and the function is called again, it attempts to move the
// entry price (and sl & tp) out one more pip at a time.
//
// RETURN VALUE:
// True if calling function should convert this to market order,
// otherwise False
//
// ORIGINAL AUTHOR AND DATE:
// Derk Wehler, 2011-05-17
//
//=============================================================================
bool EnsureValidPendPrice(int err, bool& fixed, string symbol, int cmd, double& price,
double& stoploss, double& takeprofit, int slippage, double point, int digits)
{
OrderReliable_Fname = "EnsureValidPendPrice";double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * Point;
double old_price, priceNow = 0, hasSlippedBy;
// Assume buy pendings relate to Ask, and sell pendings relate to Bid
if (cmd % 2 == OP_BUY)
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS));
else if (cmd % 2 == OP_SELL)
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS));// If we are too close to put in a limit/stop order so go to market.
if (MathAbs(priceNow - price) <= servers_min_stop)
{
if (UseLimitToMarket)
{
hasSlippedBy = MathAbs(priceNow - price) / point; // (Adjusted Point)// Check if slippage is more than caller's maximum allowed
if (priceNow != price && hasSlippedBy > slippage)
{
// Actual price is too far from requested price to do market order,
// and too close to place pending order (because of broker's minimum
// stop distance). Therefore, report the problem and try again...
OrderReliablePrint("Actual price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits) + ", and requested pend price = " + DoubleToStr(priceNow, Digits) + "; slippage between the two = ?" + DoubleToStr(hasSlippedBy, 1) + " pips, which is larger than user specified. Cannot Convert to Market Order.");
}
else
{
// Price has moved close enough (within slippage) to requested
// pending price that we can go ahead and enter a market position
return(true);
}
}
else
{
if (fixed)
{
if (cmd == OP_BUYSTOP || cmd == OP_SELLLIMIT)
{
price += point;
if (stoploss > 0) stoploss += point;
if (takeprofit > 0) takeprofit += point;
OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', adding 1 pip; new price = " + DoubleToStr(price, Digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
else if (cmd == OP_BUYLIMIT || cmd == OP_SELLSTOP)
{
price -= point;
if (stoploss > 0) stoploss -= point;
if (takeprofit > 0) takeprofit -= point;
OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', subtracting 1 pip; new price = " + DoubleToStr(price, digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
}
else
{
if (cmd == OP_BUYLIMIT)
{
old_price = price;
price = priceNow - servers_min_stop;
if (stoploss > 0) stoploss += (price - old_price);
if (takeprofit > 0) takeprofit += (price - old_price);
OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
else if (cmd == OP_BUYSTOP)
{
old_price = price;
price = priceNow + servers_min_stop;
if (stoploss > 0) stoploss += (price - old_price);
if (takeprofit > 0) takeprofit += (price - old_price);
OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
else if (cmd == OP_SELLSTOP)
{
old_price = price;
price = priceNow - servers_min_stop;
if (stoploss > 0) stoploss -= (old_price - price);
if (takeprofit > 0) takeprofit -= (old_price - price);
OrderReliablePrint("Pending SellStop has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
else if (cmd == OP_SELLLIMIT)
{
old_price = price;
price = priceNow + servers_min_stop;
if (stoploss > 0) stoploss -= (old_price - price);
if (takeprofit > 0) takeprofit -= (old_price - price);
OrderReliablePrint("Pending SellLimit has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
if (stoploss > 0 || takeprofit > 0)
OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
}
fixed = true;
}
EnsureValidStops(symbol, cmd, price, stoploss, takeprofit);
}
}
return(false);
}
//=============================================================================
// SleepRandomTime()
//
// This sleeps a random amount of time defined by an exponential
// probability distribution. The mean time, in Seconds is given
// in 'mean_time'.
//
// This is the back-off strategy used by Ethernet. This will
// quantize in fiftieths of seconds, so don't call this with a too
// small a number. This returns immediately if we are backtesting
// and does not sleep.
//
//=============================================================================
void SleepRandomTime(double mean_time, double max_time)
{
// No need for pauses on tester
if (IsTesting())
return;
/*
// 19Jun16 : Noticed for a long time that when an order fails,
// it fails all 10 tries. So try a different tack here and just
// sleep a set time per try.
Sleep(200);
return;
*/double tenths = MathCeil(mean_time / 0.1);
if (tenths <= 0)
return;int maxtenths = (int) MathRound(max_time / 0.1); // 250
double p = 1.0 - 1.0 / tenths; // 0.975// Always sleep at least some minimum
Sleep(20);// Now loop through and sleep 1/10th second a max of
// (10 * mean_time) times. But break out "randomly".
for (int i = 0; i < maxtenths; i++)
{
if (MathRand() > p*32768)
break;// MathRand() returns in 0..32767
Sleep(20);
}
}
//=============================================================================
// Adjusted Point funtion
//=============================================================================
double AdjPoint(string sym="")
{
if (sym == "")
sym = Symbol();
double ticksize = MarketInfo(sym, MODE_TICKSIZE);
if (ticksize == 0.00001 || ticksize == 0.001)
ticksize *= 10;
return(ticksize);
}
//=============================================================================
// LimitToMarket()
//
// Setting to toggle what OrderSendReliable does with Stop or Limit orders
// that are requested to be placed too close to the current price.
//
// When set True, it will turn any such conundrum from a stop/limit order
// into a simple market order
//
// When set False, the library will alter the price of the Stop/Limit order\
// just far enough to be able to place the order as a pending order.
//
//=============================================================================
void LimitToMarket(bool limit2market)
{
UseLimitToMarket = limit2market;
}
//=============================================================================
// OrderReliableUseForTesting()
//
// Setting to toggle whether this OrderReliable library is used in testing
// and optimization. By default, it is set to false, and will thus just pass
// orders straight through.
//
// When set true, it will use the full functions as normally all the time,
// including testing / optimization.
//
//=============================================================================
void OrderReliableUseForTesting(bool use)
{
UseForTesting = use;
}
//=============================================================================
// OrderReliableAddSpreadToComment()
//
// Setting to toggle whether this to add the current spread to the trade
// commment, so that user can monitor variable spread situations on a
// per trade basis.
//
//=============================================================================
void OrderReliableAddSpreadToComment(bool use)
{
AddSpreadToComment = use;
}
//=============================================================================
// GetOrderDetails()
//
// For some OrderReliable functions (such as Modify), we need to know some
// things about the order (such as direction and symbol). To do this, we
// need to select the order. However, the caller may already have an order
// selected so we need to be responsible and put it back when done.
//
// Return false if there is a problem, true otherwise.
//
//=============================================================================
bool GetOrderDetails(int ticket, string& symb, int& type, int& digits,
double& point, double& sl, double& tp, double& bid,
double& ask, bool exists=true)
{
// If this is existing order, select it and get symbol and type
if (exists)
{
int lastTicket = OrderTicket();
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
{
OrderReliablePrint("OrderSelect() error: " + ErrorDescription(GetLastError()));
return(false);
}
symb = OrderSymbol();
type = OrderType();
tp = OrderTakeProfit();
sl = OrderStopLoss();
// Select back the prior ticket num in case caller was using it.
if (lastTicket >= 0)
{
if (!OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(lastTicket));
}
}
// Get bid, ask, point & digits
bid = NormalizeDouble(MarketInfo(symb, MODE_BID), (int) MarketInfo(symb, MODE_DIGITS));
ask = NormalizeDouble(MarketInfo(symb, MODE_ASK), (int) MarketInfo(symb, MODE_DIGITS));
point = MarketInfo(symb, MODE_POINT);
if (point == 0.001 || point == 0.00001)
point *= 10;
digits = (int) MarketInfo(symb, MODE_DIGITS);
// If this is a forex pair (i.e. symbol length == 6), then digits should not be zero
if (digits == 0 && StringLen(MySymbolVal2String(MySymbolConst2Val(Symbol()))) == 6)
{
string prevName = OrderReliable_Fname;
OrderReliable_Fname = "GetDigits";
OrderReliablePrint("error: MarketInfo(symbol (" + symb + "), MODE_DIGITS) == 0");
OrderReliable_Fname = prevName;
return(false);
}
else if (exists)
{
tp = NormalizeDouble(tp, digits);
sl = NormalizeDouble(sl, digits);
bid = NormalizeDouble(bid, digits);
ask = NormalizeDouble(ask, digits);
}
return(true);
}//=============================================================================
// 20Jul16: Not sure what BS this is; all this ised to work, but not sure how.
// DerksUtils includes OrderReliable, but not vice versa... So copied these
// functions from DerksUtils and changed the names. Also, abive, where used,
// it WAS: StringLen(MySymbolVal2String(Symbol())) == 6), which was wrong.
//=============================================================================
int MySymbolConst2Val(string symbol)
{
// Handle problem of trailing chars on mini accounts.
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 == "CADJPY") return(5);
if (mySymbol == "CHFJPY") return(6);
if (mySymbol == "EURAUD") return(7);
if (mySymbol == "EURCAD") return(8);
if (mySymbol == "EURCHF") return(9);
if (mySymbol == "EURGBP") return(10);
if (mySymbol == "EURJPY") return(11);
if (mySymbol == "EURUSD") return(12);
if (mySymbol == "GBPCHF") return(13);
if (mySymbol == "GBPJPY") return(14);
if (mySymbol == "GBPUSD") return(15);
if (mySymbol == "NZDJPY") return(16);
if (mySymbol == "NZDUSD") return(17);
if (mySymbol == "USDCAD") return(18);
if (mySymbol == "USDCHF") return(19);
if (mySymbol == "USDJPY") return(20);
// These symbols were added 26Sep10
if (mySymbol == "AUDCHF") return(22);
if (mySymbol == "AUDDKK") return(23);
if (mySymbol == "AUDNOK") return(24);
if (mySymbol == "AUDSEK") return(25);
if (mySymbol == "CADCHF") return(26);
if (mySymbol == "CHFNOK") return(27);
if (mySymbol == "EURDKK") return(28);
if (mySymbol == "EURNZD") return(29);
if (mySymbol == "EURPLN") return(30);
if (mySymbol == "EURSEK") return(31);
if (mySymbol == "EURSGD") return(32);
if (mySymbol == "EURZAR") return(33);
if (mySymbol == "GBPAUD") return(34);
if (mySymbol == "GBPCAD") return(35);
if (mySymbol == "GBPNOK") return(36);
if (mySymbol == "GBPNZD") return(37);
if (mySymbol == "GBPSGD") return(38);
if (mySymbol == "NOKJPY") return(39);
if (mySymbol == "NZDCAD") return(40);
if (mySymbol == "NZDCHF") return(41);
if (mySymbol == "NZDGBP") return(42);
if (mySymbol == "SEKJPY") return(43);
if (mySymbol == "USDAED") return(44);
if (mySymbol == "USDBHD") return(45);
if (mySymbol == "USDDKK") return(46);
if (mySymbol == "USDEGP") return(47);
if (mySymbol == "USDHKD") return(48);
if (mySymbol == "USDJOD") return(49);
if (mySymbol == "USDKWD") return(50);
if (mySymbol == "USDMXN") return(51);
if (mySymbol == "USDNOK") return(52);
if (mySymbol == "USDPLN") return(53);
if (mySymbol == "USDQAR") return(54);
if (mySymbol == "USDSAR") return(55);
if (mySymbol == "USDSEK") return(56);
if (mySymbol == "USDSGD") return(57);
if (mySymbol == "USDTHB") return(58);
if (mySymbol == "USDZAR") return(59);
if (mySymbol == "XAGUSD") return(60);
if (mySymbol == "XAUUSD") return(61);
// Originally, this was "other"; kept
// the same for backward compatability
return(21);
}
string MySymbolVal2String(int val)
{
if (val == 1) return("AUDCAD");
if (val == 2) return("AUDJPY");
if (val == 3) return("AUDNZD");
if (val == 4) return("AUDUSD");
if (val == 5) return("CADJPY");
if (val == 6) return("CHFJPY");
if (val == 7) return("EURAUD");
if (val == 😎 return("EURCAD");
if (val == 9) return("EURCHF");
if (val == 10) return("EURGBP");
if (val == 11) return("EURJPY");
if (val == 12) return("EURUSD");
if (val == 13) return("GBPCHF");
if (val == 14) return("GBPJPY");
if (val == 15) return("GBPUSD");
if (val == 16) return("NZDJPY");
if (val == 17) return("NZDUSD");
if (val == 18) return("USDCAD");
if (val == 19) return("USDCHF");
if (val == 20) return("USDJPY");
// These symbols were added 26Sep10
if (val == 22) return("AUDCHF");
if (val == 23) return("AUDDKK");
if (val == 24) return("AUDNOK");
if (val == 25) return("AUDSEK");
if (val == 26) return("CADCHF");
if (val == 27) return("CHFNOK");
if (val == 28) return("EURDKK");
if (val == 29) return("EURNZD");
if (val == 30) return("EURPLN");
if (val == 31) return("EURSEK");
if (val == 32) return("EURSGD");
if (val == 33) return("EURZAR");
if (val == 34) return("GBPAUD");
if (val == 35) return("GBPCAD");
if (val == 36) return("GBPNOK");
if (val == 37) return("GBPNZD");
if (val == 38) return("GBPSGD");
if (val == 39) return("NOKJPY");
if (val == 40) return("NZDCAD");
if (val == 41) return("NZDCHF");
if (val == 42) return("NZDGBP");
if (val == 43) return("SEKJPY");
if (val == 44) return("USDAED");
if (val == 45) return("USDBHD");
if (val == 46) return("USDDKK");
if (val == 47) return("USDEGP");
if (val == 48) return("USDHKD");
if (val == 49) return("USDJOD");
if (val == 50) return("USDKWD");
if (val == 51) return("USDMXN");
if (val == 52) return("USDNOK");
if (val == 53) return("USDPLN");
if (val == 54) return("USDQAR");
if (val == 55) return("USDSAR");
if (val == 56) return("USDSEK");
if (val == 57) return("USDSGD");
if (val == 58) return("USDTHB");
if (val == 59) return("USDZAR");
if (val == 60) return("XAGUSD");
if (val == 61) return("XAUUSD");
return("Unrecognized Pair");
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/GreaterCount.mq4 -------------------------------------+
//+------------------------------------------------------------------+
bool sqIsGreaterCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) {bool atLeastOnce = false;
for(int i=0; i<bars; i++) { /// bars != Bars in mq4
double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation
double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5);
if(leftIndicator<rightIndicator){return (false);
}
if(leftIndicator==rightIndicator && NotStrict == false){return (false);
}
if(leftIndicator>rightIndicator){atLeastOnce = true;
}
}
return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/LowerCount.mq4 -------------------------------------+
//+------------------------------------------------------------------+bool sqIsLowerCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) {
bool atLeastOnce = false;
for(int i=0; i<bars; i++) { /// bars != Bars in mq4
double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation
double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5);
if(leftIndicator>rightIndicator){return (false);
}
if(leftIndicator==rightIndicator && NotStrict == false){return (false);
}
if(leftIndicator<rightIndicator){atLeastOnce = true;
}
}
return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SessionOHLC.mq4 -------------------------------------+double SessionOpen(string symbol, int tf, int startHours, int startMinutes, int daysAgo){
return getSessionPrice(symbol, tf, 1, startHours, startMinutes, startHours, startMinutes, daysAgo);
}//+------------------------------------------------------------------+
double SessionHigh(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
return getSessionPrice(symbol, tf, 2, startHours, startMinutes, endHours, endMinutes, daysAgo);
}//+------------------------------------------------------------------+
double SessionLow(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
return getSessionPrice(symbol, tf, 3, startHours, startMinutes, endHours, endMinutes, daysAgo);
}//+------------------------------------------------------------------+
double SessionClose(string symbol, int tf, int endHours, int endMinutes, int daysAgo){
return getSessionPrice(symbol, tf, 4, endHours, endMinutes, endHours, endMinutes, daysAgo);
}//+------------------------------------------------------------------+
double getSessionPrice(string symbol, int tf, int type, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
string correctedSymbol = correctSymbol(symbol);
return iCustom(correctedSymbol, tf, "SqSessionOHLC", type, startHours, startMinutes, endHours, endMinutes, daysAgo, 0, 0);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankAboveLevelXBars.mqh -------------------------------------+
//+------------------------------------------------------------------+bool sqSRPercRankAboveLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) {
bool atLeastOnce = false;
for(int i=0; i<bars; i++) { /// bars != Bars in mq4
if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){
return (false);
}
if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){
atLeastOnce = true;
}
}
return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankBelowLevelXBars.mqh -------------------------------------+bool sqSRPercRankBelowLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) {
bool atLeastOnce = false;for(int i=0; i<bars; i++) { /// bars != Bars in mq4
if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){
return (false);
}
if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){
atLeastOnce = true;
}
}
return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/CustomFunctions.mq4 -------------------------------------+//+------------------------------------------------------------------+
//+ Custom functions
//+
//+ Here you can define your own custom functions that can be used
//+ in Algo Wizard.
//+ The functions can perform some action (for example draw on chart
//+ or manipulate with orders) or they can return value that
//+ can be used in comparison.
//+
//+ Note! All the functions below must be in valid MQL code!
//+ Contents of this file will be appended to your EA code.
//+
//+------------------------------------------------------------------+double exampleFunction(double value) {
return(2 * value);
}//+------------------------------------------------------------------+
Thousand thanks in advance
- 1
Need help on unable to loan EA on IG MT4
in IG Chart Support - Charts, MT4 and PRT
Posted
Thanks alot for the info .