try to convert this EA using 2calgo.net
try to convert this EA using 2calgo.net
17 Nov 2020, 18:54
Hello,
I recently try algowizard.io and it let me generate some code from strategies I have create free of charge, unfortunately it looks that support most trading programs except ctrader,
i try to use 2calgo to convert the metatrader4 code but got an error.
i past the full code here and pseudocode, anyone that would convert it (its a ichimoku bot) and share with the community is well came.
//+------------------------------------------------------------------+
//| ichibuono EA
//|
//| Generated by StrategyQuant 3.9.132 at 11/17/2020 17:39
//|
//| 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 = "ichibuono";
extern int MagicNumber = 11111;
bool LongEntrySignal = false;
bool ShortEntrySignal = false;
bool LongExitSignal = false;
bool ShortExitSignal = false;
extern int IchimokuTnkKjnCrsBshTnkPrd = 9;
extern int IchimokuTnkKjnCrsBshKjnPrd = 26;
extern int IchimokuTnkKjnCrsBshSnkPrd = 52;
extern int IchimokuKjnSenCrsBshTnkPrd = 9;
extern int IchimokuKjnSenCrsBshKjnPrd = 26;
extern int IchimokuKjnSenCrsBshSnkPrd = 52;
extern int IchimokuSnkSpnCrsBshTnkPrd = 9;
extern int IchimokuSnkSpnCrsBshKjnPrd = 26;
extern int IchimokuSnkSpnCrsBshSnkPrd = 52;
extern double TrailingStopCoef = 5;
extern double TrailingActCef = 5;
//+------------------------------------------------------------------+
// Money Management variables
//+------------------------------------------------------------------+
extern string smm = "----------- Money Management - Risk Fixed % Of Balance -----------";
extern double mmRiskPercent = 3.0;
extern int mmDecimals = 1;
extern double mmLotsIfNoMM = 1.0;
extern double mmMaxLots = 5.0;
//+------------------------------------------------------------------+
// Trading Options variables
//+------------------------------------------------------------------+
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 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 = 10000; // 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 ms
double 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 execution
int 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;
//////////
//+------------------------------------------------------------------+
// -- Functions
//+------------------------------------------------------------------+
void OnTick() {
sqInitStart();
sqManageOrders(MagicNumber);
openingOrdersAllowed = sqHandleTradingOptions();
//------------------------
// Rule: Trading signals
//------------------------
if (sqIsBarOpen()) {
// init signals only on bar open
LongEntrySignal = sqIchimokuTenkanKijunCross(1, NULL,0, IchimokuTnkKjnCrsBshTnkPrd, IchimokuTnkKjnCrsBshKjnPrd, IchimokuTnkKjnCrsBshSnkPrd, 1, 2);
LongExitSignal = (sqIchimokuKijunSenCross(-1, NULL,0, IchimokuKjnSenCrsBshTnkPrd, IchimokuKjnSenCrsBshKjnPrd, IchimokuKjnSenCrsBshSnkPrd, 1, 1)
&& sqIchimokuSenkouSpanCross(-1, NULL,0, IchimokuSnkSpnCrsBshTnkPrd, IchimokuSnkSpnCrsBshKjnPrd, IchimokuSnkSpnCrsBshSnkPrd, 1, 0));
ShortEntrySignal = sqIchimokuTenkanKijunCross(-1, NULL,0, IchimokuTnkKjnCrsBshTnkPrd, IchimokuTnkKjnCrsBshKjnPrd, IchimokuTnkKjnCrsBshSnkPrd, 1, 2);
ShortExitSignal = (sqIchimokuKijunSenCross(1, NULL,0, IchimokuKjnSenCrsBshTnkPrd, IchimokuKjnSenCrsBshKjnPrd, IchimokuKjnSenCrsBshSnkPrd, 1, 1)
&& sqIchimokuSenkouSpanCross(1, NULL,0, IchimokuSnkSpnCrsBshTnkPrd, IchimokuSnkSpnCrsBshKjnPrd, IchimokuSnkSpnCrsBshSnkPrd, 1, 0));
}
//------------------------
// Rule: Long entry
//------------------------
if (sqIsBarOpen()
&& ((LongEntrySignal
&& (!(ShortEntrySignal)))
&& (!(LongExitSignal))))
{
// Action #1
_ticket = sqOpenOrder(OP_BUY, "Current", sqMMRiskFixedBalancePct("Current",OP_BUY,0,0,mmRiskPercent,mmDecimals,mmLotsIfNoMM,mmMaxLots), 0, MagicNumber, "", 0, false, true, 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
// TrailingStop initialization
sqSetGlobalVariable(_ticket, "TrailingStop", sqStringHash("TrailingStopCoef * sqATR(NULL,0,20,1)"));
sqSetGlobalVariable(_ticket, "TrailingStopType", SLPTTYPE_RANGE);
sqSetGlobalVariable(_ticket, "TrailingActivation", sqStringHash("TrailingActCef * sqATR(NULL,0,20,1)"));
}
}
//------------------------
// Rule: Short entry
//------------------------
if (sqIsBarOpen()
&& ((ShortEntrySignal
&& (!(LongEntrySignal)))
&& (!(ShortExitSignal))))
{
// Action #1
_ticket = sqOpenOrder(OP_SELL, "Current", sqMMRiskFixedBalancePct("Current",OP_SELL,0,0,mmRiskPercent,mmDecimals,mmLotsIfNoMM,mmMaxLots), 0, MagicNumber, "", 0, false, true, 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
// TrailingStop initialization
sqSetGlobalVariable(_ticket, "TrailingStop", sqStringHash("TrailingStopCoef * sqATR(NULL,0,20,1)"));
sqSetGlobalVariable(_ticket, "TrailingStopType", SLPTTYPE_RANGE);
sqSetGlobalVariable(_ticket, "TrailingActivation", sqStringHash("TrailingActCef * sqATR(NULL,0,20,1)"));
}
}
//------------------------
// 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");
gPointCoef = calculatePointCoef(Symbol());
VerboseLog("--------------------------------------------------------");
if(sqDisplayInfoPanel) {
sqInitInfoPanel();
}
SQTime = new CSQTime();
if(!IsTesting() && !IsOptimization()) {
initTimer();
}
initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
objExitAtEndOfDay = new CExitAtEndOfDay();
objExitOnFriday = new CExitOnFriday();
objLimitTimeRange = new CLimitTimeRange();
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("--------------------------------------------------------");
}
return(0);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
sqDeinitInfoPanel();
delete SQTime;
delete objExitAtEndOfDay;
delete objExitOnFriday;
delete objLimitTimeRange;
delete objMaxTradesPerDay;
delete objMinMaxSLPT;
return;
}
//+------------------------------------------------------------------+
void initTimer(){
int period = 20 * 3600; //20 hours
period += MathRand() % (10 * 3600); //add another 0-10 hours randomly
if(!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(!objExitAtEndOfDay.onBarUpdate()) continueWithBarUpdate = false;
if(!objExitOnFriday.onBarUpdate()) continueWithBarUpdate = false;
if(!objLimitTimeRange.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("TrailingStopCoef * sqATR(NULL,0,20,1)")) {
return (TrailingStopCoef * sqATR(NULL,0,20,1));
}
if(idHash == (string) sqStringHash("TrailingActCef * sqATR(NULL,0,20,1)")) {
return (TrailingActCef * sqATR(NULL,0,20,1));
}
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("TrailingStopCoef * sqATR(NULL,0,20,1)")) {
return (TrailingStopCoef * sqATR(NULL,0,20,1));
}
if(idHash == (string) sqStringHash("TrailingActCef * sqATR(NULL,0,20,1)")) {
return (TrailingActCef * sqATR(NULL,0,20,1));
}
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) {
continue;
}
int ticket = OrderTicket();
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
// handle Exit Methods only for live orders
sqManageSL2BE(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, 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: ", magicNumber, ", symbol: ", symbol, ", direction: ", 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: ", magicNumber, ", symbol: ", symbol, ", direction: ", 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: ", magicNumber, ", symbol: ", symbol, ", direction: ", 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 = 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));
}
//+------------------------------------------------------------------+
int 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);
}
//+------------------------------------------------------------------+
int 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) {
double 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) {
if(size <= 0) return (0);
string correctedSymbol = correctSymbol(symbol);
double ask = sqGetAsk(correctedSymbol);
double bid = sqGetBid(correctedSymbol);
int direction = sqGetDirectionFromOrderType(orderType);
double marketPrice = direction == 1 ? ask : bid;
price = price > 0 ? price : marketPrice;
price = sqFixMarketPrice(price, correctedSymbol);
openingOrdersAllowed = openingOrdersAllowed && sqHandleTradingOptions();
if(!openingOrdersAllowed) return(0);
Verbose("Opening order type ", OrderTypeToString(orderType)," with price ", price, ". Current market prices: ", ask, " / ", bid);
// check if live order exists
if(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(sqSelectOrder(magicNumber, correctedSymbol, direction, comment, false, false, true)) {
if(replaceExisting) {
if(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;
}
string commentToUse = "";
if(comment != ""){
commentToUse = comment;
}
else {
commentToUse = CustomComment;
StringReplace(commentToUse, "Optimization", "Opt."); //shorten the name of optimized strategies
}
commentToUse = StringSubstr(commentToUse, 0, 30); //limit the length to 30 characters
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);
}
//----------------------------------------------------------------------------
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: ", marketPrice, ", order price: ", 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: ", marketPrice, ", max. price allowed: ", priceLevel, ", ", name, " price: ", 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: ", marketPrice, ", min. price allowed: ", priceLevel, ", ", name," price: ", 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 = 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: ", stopLoss, " > ", 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: ", stopLoss, " < ", 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: ", profitTarget, " < ", 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: ", profitTarget, " > ", 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 = 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 = 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);
}
//+------------------------------------------------------------------+
double sleepPeriod = 500; // 0.5 s
double 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", "ichibuono", 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: "+sqGetTotalProfits(0, 100)+"/"+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);
}
//+------------------------------------------------------------------+
int 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 Number
count++;
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 PT
if(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;
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;
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[0]);
return (hour * 100) + minute;
}
else {
Print("Incorrect time value format. Value: '" + time + "'");
return 0;
}
}
//+------------------------------------------------------------------+
string sqGetDate(int day, int month, int year) {
string strMonth = month;
if(month < 10) strMonth = "0"+strMonth;
string strDay = day;
if(day < 10) strDay = "0"+strDay;
return(StringConcatenate(year, ".", strMonth, ".", strDay));
}
//+------------------------------------------------------------------+
string sqGetTime(int hour, int minute, int second) {
string strHour = hour;
if(hour < 10) strHour = "0"+strHour;
string strMinute = minute;
if(minute < 10) strMinute = "0"+strMinute;
string strSecond = second;
if(second < 10) strSecond = "0"+strSecond;
return(StringConcatenate(strHour, ":", strMinute, ":", strSecond));
}
//+------------------------------------------------------------------+
int getSQTime(datetime time){
int minutesToday = (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 = H-L;
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));
}
}
//+------------------------------------------------------------------+
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 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 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);
}
//+------------------------------------------------------------------+
int sqGetMonthFirstTradingDay(string symbol, int timeframe, bool includeWeekends) {
datetime barTime = iTime(symbol, timeframe, 0);
datetime firstTradingDate = SQTime.setDayOfMonth(barTime, 1);
if(!includeWeekends) {
if(TimeDayOfWeek(firstTradingDate) == 6) {
firstTradingDate = SQTime.addDays(firstTradingDate, 2);
} else if(TimeDayOfWeek(firstTradingDate) == 0) {
firstTradingDate = SQTime.addDays(firstTradingDate, 1);
}
}
return TimeDay(firstTradingDate);
}
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( val );
if(moveSLAtValue > 0) {
double newSL = 0;
int error;
int valueType = sqGetGlobalVariable(ticket, "MoveSL2BEType");
int orderType = OrderType();
int digits = 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(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: ", OrderTicket(), " to :", newSL);
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", 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: ", OrderTicket(), " to :", newSL);
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", 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( val );
if(tsValue > 0) {
double plValue;
int error;
int valueType = sqGetGlobalVariable(ticket, "TrailingStopType");
int orderType = OrderType();
int digits = 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( 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: ", OrderTicket(), " to :", tsValue);
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", 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: ", OrderTicket(), " to :", tsValue);
if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
error = GetLastError();
Verbose("Failed, error: ", error, " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
}
}
}
}
}
void sqManageExitAfterXBars(int ticket) {
int exitBars = sqGetGlobalVariable(ticket, "ExitAfterBars");
if(exitBars > 0) {
if (sqGetOpenBarsForOrder(ticket, exitBars+10) >= exitBars) {
Verbose("Exit After ", exitBars, "bars - closing order with ticket: ", OrderTicket());
sqClosePositionAtMarket(OrderLots());
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// Trading Options includes
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CTradingOption {
public:
virtual bool onBarUpdate() = 0;
};
//+------------------------------------------------------------------+
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 EODTime;
datetime dailySignalTimeRangeFrom;
datetime dailySignalTimeRangeTo;
bool closedThisDay;
public:
CLimitTimeRange() {
EODTime = D'1970.01.01';
closedThisDay = false;
}
//+----------------------------------------------+
virtual bool onBarUpdate() {
if(!LimitTimeRange) {
return true;
}
onTick();
if(!sqIsBarOpen()) {
return true;
}
datetime currentTime = TimeCurrent();
if(currentTime > EODTime) {
// 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 end time of the current day (so that we now when new day starts)
EODTime = SQTime.correctDayEnd(currentTime);
// set time of range open
dailySignalTimeRangeFrom = SQTime.setHHMM(currentTime, SignalTimeRangeFrom);
dailySignalTimeRangeTo = SQTime.setHHMM(currentTime, SignalTimeRangeTo);
closedThisDay = false;
}
};
// create variable for class instance (required)
CLimitTimeRange* objLimitTimeRange;
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;
double sqMMRiskFixedBalancePct(string symbol, int orderType, double price, double sl, double RiskInPercent, int Decimals, double LotsIfNoMM, double MaximumLots) {
Verbose("Computing Money Management for order - Risk fixed % of account balance");
symbol = correctSymbol(symbol);
double openPrice = price > 0 ? price : (orderType == OP_BUY ? sqGetAsk(symbol) : sqGetBid(symbol));
double LotSize=0;
if(RiskInPercent < 0 ) {
Verbose("Computing Money Management - Incorrect RiskInPercent size, it must be above 0");
return(0);
}
double PointValue = MarketInfo(symbol, MODE_TICKVALUE) / MarketInfo(symbol, MODE_TICKSIZE);
double Smallest_Lot = MarketInfo(symbol, MODE_MINLOT);
double Largest_Lot = MarketInfo(symbol, MODE_MAXLOT);
double LotStep = MarketInfo(symbol, MODE_LOTSTEP);
//Maximum amount of money to risk
double moneyToRisk = AccountBalance() * RiskInPercent / 100;
//Maximum drawdown of this order if we buy 1 lot
double oneLotSLDrawdown = PointValue * MathAbs(openPrice - sl);
if(oneLotSLDrawdown > 0) {
LotSize = roundDown(moneyToRisk / oneLotSLDrawdown, Decimals);
}
else {
LotSize = 0;
}
//--- MAXLOT and MINLOT management
Verbose("Computing Money Management - Smallest_Lot: ", Smallest_Lot, ", Largest_Lot: ", Largest_Lot,", Computed LotSize: ", LotSize);
Verbose("Max money to risk: ", moneyToRisk, ", SL:", sl, ", One lot drawdown: ", oneLotSLDrawdown, ", Point value: ", PointValue);
if(LotSize <= 0) {
Verbose("Calculated LotSize is <= 0. Using LotsIfNoMM value: ", LotsIfNoMM, ")");
LotSize = LotsIfNoMM;
}
if(LotSize > MaximumLots) {
Verbose("LotSize is too big. LotSize set to maximal allowed value (MaximumLots): ", MaximumLots);
LotSize = MaximumLots;
}
//--------------------------------------------
if (LotSize < Smallest_Lot) {
Verbose("Calculated LotSize is too small. Minimal allowed lot size from the broker is: ", Smallest_Lot, ". Please, increase your risk or set fixed LotSize.");
LotSize = 0;
}
else if (LotSize > Largest_Lot) {
Verbose("LotSize is too big. LotSize set to maximal allowed market value: ", Largest_Lot);
LotSize = Largest_Lot;
}
return (LotSize);
}
//=============================================================================
// 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
//
//===========================================================================
//=============================================================================
// 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;
double bid, ask;
double sl, tp;
double priceNow;
double hasSlippedBy;
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:
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 " + retry_attempts +"("+retry_attempts_bad_price+")");
}
}
else
{
OrderReliablePrint("Result of attempt " + cnt + " of " + retry_attempts+"("+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 #" + ticket + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + ticket);
sqOrderPrint();
return(ticket); // SUCCESS!
}
if (!limit_to_market)
{
OrderReliablePrint("Failed to execute stop or limit order after " + retry_attempts + " retries");
OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol +
"@" + price + " tp@" + takeprofit + " sl@" + stoploss);
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
OrderReliablePrint("");
return(-1);
}
} // end
if (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), 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), 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, (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:
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 " + retry_attempts +"("+retry_attempts_bad_price+")");
}
else
{
OrderReliablePrint("Result of attempt " + cnt + " of " + retry_attempts +"("+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 #" + ticket + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + ticket);
sqOrderPrint();
return(ticket); // SUCCESS!
}
// If not successful, log and return -1
OrderReliablePrint("Failed to execute OP_BUY/OP_SELL, after " + retry_attempts + " retries");
OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol +
"@" + price + " tp@" + takeprofit + " sl@" + 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 #" + 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 #" + 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 #" + 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:
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 " + cnt + " of " + retry_attempts+"("+retry_attempts_bad_price+")" + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
RefreshRates();
}
else
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + 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: " + ticket + " " + symbol +
"@" + price + " tp@" + takeprofit + " sl@" + stoploss);
OrderReliablePrint("Suggest modifying code logic to avoid.");
}
if (result)
{
OrderReliablePrint("Ticket #" + ticket + ": Modification successful, updated trade details follow.");
if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
OrderReliablePrint("Could Not Select Ticket #" + ticket);
sqOrderPrint();
}
else
{
OrderReliablePrint("Failed to execute modify after " + retry_attempts + " retries");
OrderReliablePrint("Failed modification: " + ticket + " " + symbol +
"@" + price + " tp@" + takeprofit + " sl@" + 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 #" + ticket + " initial price:" + DoubleToStr(price, digits+1) +
" lots:" + DoubleToStr(volume, 3) + " slippage:" + slippage);
if (type != OP_BUY && type != OP_SELL)
{
OrderReliablePrint("Error: Trying to close ticket #" + 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;
double hasSlippedBy;
while (!exit_loop)
{
// = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
// Get current price and calculate slippage
RefreshRates();
if (type == OP_BUY)
{
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), MarketInfo(symbol, MODE_DIGITS)); // Close @ Bid
hasSlippedBy = (price - priceNow) / point; // (Adjusted Point)
}
else if (type == OP_SELL)
{
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), 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, (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:
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 " + retry_attempts);
else if (non_retryable_error)
OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
}
else
{
OrderReliablePrint("Result of attempt " + cnt + " of " + 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 #" + ticket + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else if (OrderCloseTime() > 0) // Then it closed ok
OrderReliablePrint("Successful close of Ticket #" + 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 #" + ticket + ", Price: " +
price + ", Slippage: " + slippage);
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
result = false;
}
}
else
{
OrderReliablePrint("Failed to execute close after " + (cnt-1) + " retries");
OrderReliablePrint("Failed close: Ticket #" + ticket + " @ Price: " + priceNow +
" (Requested Price: " + price + "), Slippage: " + 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 #" + ticket + " initial price:" + DoubleToStr(price, digits+1) +
" lots:" + DoubleToStr(price, 3) + " slippage:" + slippage);
if (type != OP_BUY && type != OP_SELL)
{
OrderReliablePrint("Error: Trying to close ticket #" + 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;
int slippagenow;
while (!exit_loop)
{
if (type == OP_BUY)
{
pnow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
if (pnow > price)
{
// Do not allow slippage to go negative; will cause error
slippagenow = MathMax(0, slippage - (pnow - price) / point);
}
}
else if (type == OP_SELL)
{
pnow = NormalizeDouble(MarketInfo(symbol, MODE_BID), MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
if (pnow < price)
{
// Do not allow slippage to go negative; will cause error
slippagenow = 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:
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 " + cnt + " of " + retry_attempts + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
}
if (exit_loop)
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + 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 #" + ticket + " [ Last error: " + OrderReliableErrTxt(err) + " ]");
else if (OrderCloseTime() > 0) // Then it closed ok
OrderReliablePrint("Successful close of Ticket #" + 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 #" + ticket + ", Price: " +
price + ", Slippage: " + slippage);
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
result = false;
}
}
else
{
OrderReliablePrint("Failed to execute close after " + retry_attempts + " retries");
OrderReliablePrint("Failed close: Ticket #" + ticket + " @ Price: " +
pnow + " (Initial Price: " + price + "), Slippage: " +
slippagenow + " (Initial Slippage: " + 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, #" + 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 #" + 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:
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 " + cnt + " of " + retry_attempts + ": Retryable error: " + OrderReliableErrTxt(err));
SleepRandomTime(sleep_time, sleep_maximum);
}
else
{
if (cnt > retry_attempts)
OrderReliablePrint("Retry attempts maxed at " + 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 #" + ticket);
return(true); // SUCCESS!
}
else
{
OrderReliablePrint("Failed to execute delete after " + retry_attempts + " retries");
OrderReliablePrint("Failed deletion: Ticket #" + ticket);
OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
}
return(result);
}
//=============================================================================
//=============================================================================
// Utility Functions
//=============================================================================
//=============================================================================
string OrderReliableErrTxt(int err)
{
return (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: "+OrderTicket()+" - "+
"OpenTime: "+OrderOpenTime()+","+
"Type: "+OrderType()+","+
"Size: "+OrderLots()+","+
"Symbol: "+OrderSymbol()+","+
"OpenPrice: "+OrderOpenPrice()+","+
"SL: "+OrderStopLoss()+","+
"PT: "+OrderTakeProfit());
Print("Ticket: "+OrderTicket()+" (continue) - "+
"CloseTime: "+OrderCloseTime()+","+
"ClosePrice: "+OrderClosePrice()+","+
"Commission: "+OrderCommission()+","+
"Swap: "+OrderSwap()+","+
"Profit: "+OrderProfit()+","+
"Comment: "+OrderComment()+","+
"MagicNumber: "+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 (" + 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 = 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, 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, MarketInfo(symbol, MODE_DIGITS));
}
}
// notify if changed
if (sl != orig_sl)
OrderReliablePrint("SL was too close to brokers min distance (" + min_stop_level + "); moved SL to: " + sl);
if (tp != orig_tp)
OrderReliablePrint("TP was too close to brokers min distance (" + min_stop_level + "); moved TP to: " + 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, hasSlippedBy;
// Assume buy pendings relate to Ask, and sell pendings relate to Bid
if (cmd % 2 == OP_BUY)
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), MarketInfo(symbol, MODE_DIGITS));
else if (cmd % 2 == OP_SELL)
priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), 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 = 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 #" + lastTicket);
}
}
// Get bid, ask, point & digits
bid = NormalizeDouble(MarketInfo(symb, MODE_BID), MarketInfo(symb, MODE_DIGITS));
ask = NormalizeDouble(MarketInfo(symb, MODE_ASK), MarketInfo(symb, MODE_DIGITS));
point = MarketInfo(symb, MODE_POINT);
if (point == 0.001 || point == 0.00001)
point *= 10;
digits = 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 == 8) 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/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);
}
//+------------------------------------------------------------------+
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SessionOHLC.mq4 -------------------------------------+
double SessionOpen(int startHours, int startMinutes, int daysAgo){
return getSessionPrice(1, startHours, startMinutes, startHours, startMinutes, daysAgo);
}
//+------------------------------------------------------------------+
double SessionHigh(int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
return getSessionPrice(2, startHours, startMinutes, endHours, endMinutes, daysAgo);
}
//+------------------------------------------------------------------+
double SessionLow(int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
return getSessionPrice(3, startHours, startMinutes, endHours, endMinutes, daysAgo);
}
//+------------------------------------------------------------------+
double SessionClose(int endHours, int endMinutes, int daysAgo){
return getSessionPrice(4, endHours, endMinutes, endHours, endMinutes, daysAgo);
}
//+------------------------------------------------------------------+
double getSessionPrice(int type, int startHours, int startMinutes, int endHours, int endMinutes, int daysShift){
int totalEndDaysShift = daysShift;
int totalStartDaysShift = daysShift;
datetime currentTime = Time[0];
int currentHHMM = TimeHour(currentTime) * 100 + TimeMinute(currentTime);
int startHHMM = startHours * 100 + startMinutes;
int endHHMM = endHours * 100 + endMinutes;
if(type == 1){
if(currentHHMM < startHHMM){
totalEndDaysShift++;
totalStartDaysShift++;
}
}
else if(type == 4){
if(currentHHMM >= startHHMM){
totalEndDaysShift--;
totalStartDaysShift--;
}
}
else {
if(startHHMM < endHHMM){
if(currentHHMM < startHHMM){
totalEndDaysShift++;
totalStartDaysShift++;
}
}
else {
if(currentHHMM < startHHMM){
totalStartDaysShift++;
}
else {
totalEndDaysShift--;
}
}
}
int totalBars = Bars(NULL, 0);
int currentIndex = 0;
int lastDayOfYear = TimeDayOfYear(currentTime);
int daysAgo = 0;
double highest = -1000000000;
double lowest = 1000000000;
while(currentIndex < totalBars){
datetime time = Time[currentIndex];
int hhmm = TimeHour(time) * 100 + TimeMinute(time);
int curDayOfYear = TimeDayOfYear(time);
if(curDayOfYear != lastDayOfYear) {
lastDayOfYear = curDayOfYear;
daysAgo++;
}
if(type == 2 || type == 3){
if(totalStartDaysShift == totalEndDaysShift){
if(daysAgo == totalEndDaysShift && hhmm < endHHMM && hhmm >= startHHMM) {
if(type == 2){
highest = MathMax(highest, High[currentIndex]);
}
else {
lowest = MathMin(lowest, Low[currentIndex]);
}
}
}
else {
if((daysAgo == totalEndDaysShift && hhmm < endHHMM) || (daysAgo == totalStartDaysShift && hhmm >= startHHMM)) {
if(type == 2){
highest = MathMax(highest, High[currentIndex]);
}
else {
lowest = MathMin(lowest, Low[currentIndex]);
}
}
}
}
if(daysAgo > totalStartDaysShift || (daysAgo == totalStartDaysShift && ((type < 4 && hhmm <= startHHMM) || (type == 4 && hhmm < endHHMM)))) {
switch(type){
case 1:
return Open[currentIndex];
case 2: return highest != -1000000000 ? highest : 0;
case 3: return lowest != 1000000000 ? lowest : 0;
case 4:
return Close[currentIndex];
default: return 0;
}
}
currentIndex++;
}
switch(type){
case 2: return highest != -1000000000 ? highest : 0;
case 3: return lowest != 1000000000 ? lowest : 0;
default: return 0;
}
}
PSEUDO CODE
//--------------------------------------------------------------------
// Pseudo Source Code of ichibuono
//
// Generated by StrategyQuant 3.9.132 for MetaTrader
// at 11/17/2020 17:39
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Strategy Parameters
//--------------------------------------------------------------------
int MagicNumber = 11111;
int IchimokuTnkKjnCrsBshTnkPrd = 9;
int IchimokuTnkKjnCrsBshKjnPrd = 26;
int IchimokuTnkKjnCrsBshSnkPrd = 52;
int IchimokuKjnSenCrsBshTnkPrd = 9;
int IchimokuKjnSenCrsBshKjnPrd = 26;
int IchimokuKjnSenCrsBshSnkPrd = 52;
int IchimokuSnkSpnCrsBshTnkPrd = 9;
int IchimokuSnkSpnCrsBshKjnPrd = 26;
int IchimokuSnkSpnCrsBshSnkPrd = 52;
double TrailingStopCoef = 5;
double TrailingActCef = 5;
Main chart = Current Symbol / Current TF;
//--------------------------------------------------------------------
// Trading options logic
//--------------------------------------------------------------------
Exit at End Of Day = false (2355);
Exit On Friday = false (2300);
LimitSignalsTimeRange = false (From: 0800 to: 1600, Exit at End Of Range = false);
MaxTradesPerDay = 0;
Min SL: 0, Max SL: 0, Min PT: 0, Max PT: 0; // in ticks/pips, 0 means unlimited
//--------------------------------------------------------------------
// Trading rule: Trading signals (On Bar Open)
//--------------------------------------------------------------------
LongEntrySignal = Ichimoku(Main chart,IchimokuTnkKjnCrsBshTnkPrd, IchimokuTnkKjnCrsBshKjnPrd, IchimokuTnkKjnCrsBshSnkPrd) TenkanSen crosses KijunSen bullish;
LongExitSignal = (Ichimoku(Main chart,IchimokuKjnSenCrsBshTnkPrd, IchimokuKjnSenCrsBshKjnPrd, IchimokuKjnSenCrsBshSnkPrd) price crosses KijunSen bearish
and Ichimoku(Main chart,IchimokuSnkSpnCrsBshTnkPrd, IchimokuSnkSpnCrsBshKjnPrd, IchimokuSnkSpnCrsBshSnkPrd) Senkou Span cross bearish);
ShortEntrySignal = Ichimoku(Main chart,IchimokuTnkKjnCrsBshTnkPrd, IchimokuTnkKjnCrsBshKjnPrd, IchimokuTnkKjnCrsBshSnkPrd) TenkanSen crosses KijunSen bearish;
ShortExitSignal = (Ichimoku(Main chart,IchimokuKjnSenCrsBshTnkPrd, IchimokuKjnSenCrsBshKjnPrd, IchimokuKjnSenCrsBshSnkPrd) price crosses KijunSen bullish
and Ichimoku(Main chart,IchimokuSnkSpnCrsBshTnkPrd, IchimokuSnkSpnCrsBshKjnPrd, IchimokuSnkSpnCrsBshSnkPrd) Senkou Span cross bullish);
//--------------------------------------------------------------------
// Trading rule: Long entry (On Bar Open)
//--------------------------------------------------------------------
if ((LongEntrySignal
and Not ShortEntrySignal)
and Not LongExitSignal)
{
// Action #1
Open Long order at Market;
Duplicate trades: allowed;
Trailing Stop = TrailingStopCoef * ATR(20), TS Activation at TrailingActCef * ATR(20);
}
//--------------------------------------------------------------------
// Trading rule: Short entry (On Bar Open)
//--------------------------------------------------------------------
if ((ShortEntrySignal
and Not LongEntrySignal)
and Not ShortExitSignal)
{
// Action #1
Open Short order at Market;
Duplicate trades: allowed;
Trailing Stop = TrailingStopCoef * ATR(20), TS Activation at TrailingActCef * ATR(20);
}
//--------------------------------------------------------------------
// Trading rule: Long exit (On Bar Open)
//--------------------------------------------------------------------
if (LongExitSignal
and (MarketPosition("Any", MagicNumber, "") is Long))
{
// Action #1
Close Full position for Symbol = Any and Magic Number = MagicNumber;
}
//--------------------------------------------------------------------
// Trading rule: Short exit (On Bar Open)
//--------------------------------------------------------------------
if (ShortExitSignal
and (MarketPosition("Any", MagicNumber, "") is Short))
{
// Action #1
Close Full position for Symbol = Any and Magic Number = MagicNumber;
}