I am totally drain out as the second if statement couldn't be executed.
My original idea was when volatility is in a range of 90 - 110, the program will send one and only one order. And it will wait and see till the volatility reaches in a range of 111 - 150, and then it will send the second order.
If I don't use a bool function here, the program will send countless order when the range is reached.
Could someone please help me?
if ( TodayMaxVolatilityPercentage >= 90.0
&& ( dayTrend == 1 )
&& orderOpened == false
)
{
Print( "Entered if clause" );
// Print( "Today volatility percentage is: ", TodayMaxVolatilityPercentage + "%" );
// ticket: Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
ticket = OrderSend( Symbol(),
OP_SELL,
0.3,
Bid,
3,
0 * MyPoint,
30 * MyPoint,
NULL,
MagicNumber,
0,
Blue
);
Print( "Order is opened on", OrderOpenTime()+" at price: ", OrderOpenPrice() );
Print( "trend number is ",dayTrend );
if ( ticket > 0 )
{
if ( TakeProfit > 0 ) TheTakeProfit = Bid - TakeProfit * MyPoint;
OrderSelect( ticket, SELECT_BY_TICKET ); // bool value
/* OrderModify( OrderTicket(),
OrderOpenPrice(),
0,
NormalizeDouble( TheTakeProfit, Digits ),
0,
Green
);
*/
}
orderOpened = true;
if ( TodayMaxVolatilityPercentage >= 110.0 ) orderOpened = false;
}
if ( TodayMaxVolatilityPercentage >= 110.0
&& ( dayTrend == 1 )
&& orderOpened == false
)
{
Print( "Entered second if clause" );
// ticket: Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
ticket = OrderSend( Symbol(),
OP_SELL,
0.3,
Bid,
3,
0 * MyPoint,
30 * MyPoint,
NULL,
MagicNumber,
0,
Blue
);
if ( ticket > 0 )
{
if ( TakeProfit > 0 ) TheTakeProfit = Bid - TakeProfit * MyPoint;
OrderSelect( ticket, SELECT_BY_TICKET ); // bool value
/* OrderModify( OrderTicket(),
OrderOpenPrice(),
0,
NormalizeDouble( TheTakeProfit, Digits ),
0,
Green
);
*/
}
orderOpened = true;
}
A hidden show-stopper:
By design, the first successful OrderSend() returns a value you assign into an ticket = OrderSend(...).
The devil is hidden in detail.
[MQL4-Help] says:
Returns number of the ticket assigned to the order by the trade server or -1 if it fails.
So the first successful OrderSend() ticket# returned is 0 ( in StrategyTester, a real MT4/Server rather runs into high numbers drawn from it's db.pool of tickets ).
Thus the second if ( ticket > 0 ) will never let you in.
It is common to rather use if ( ticket > EMPTY ) so as to also clarify the intention and use symbolic instead of a -1 integer constant.
Related
Another user was helping me with this problem, but i'm having trouble executing it, i'm getting error:
syntax error line 3 at position 8 unexpected 'time'. syntax error line 3 at position 23 unexpected ':'. (line 3)
it seems i'm either declaring the variables wrong, actually i'm sure of that because when i comment out "time", it gives me an error with "curDay".
Here is the function i'm trying to execute;
CREATE OR REPLACE FUNCTION DB_BI_DEV.RAW_CPMS_AAR.cfn_GetShiftIDFromDateTime (dateTime TIMESTAMP_NTZ(9), shiftCalendarID int)
RETURNS table (shiftID int)
AS
$$
DECLARE
time time TIME(:dateTime);
curDay int;
prvDay int;
shiftID int;
BEGIN
SELECT TOP 1
ID,
DATEDIFF( day, BeginDate, :dateTime ) % PeriodInDays + 1,
( :curDay + PeriodInDays - 2 ) % PeriodInDays + 1
INTO :shiftCalendarID, :curDay, :prvDay
FROM RAW_CPMS_AAR.ShiftCalendar
WHERE ID = :shiftCalendarID
OR ( :shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= :dateTime )
ORDER BY BeginDate DESC;
SELECT ID into :shiftID
FROM Shift
WHERE ShiftCalendarID = #shiftCalendarID
AND ( ( FromDay = :curDay AND FromTimeOfDay <= :time AND TillTimeOfDay > :time )
OR ( FromDay = :curDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= :time )
OR ( FromDay = :prvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > :time )
);
END;
$$
This may need some small changes, but should be close to what you require:
CREATE OR REPLACE FUNCTION DB_BI_DEV.RAW_CPMS_AAR.cfn_GetShiftIDFromDateTime (dateTime TIMESTAMP_NTZ(9), shiftCalendarID int)
RETURNS table (shiftID int)
AS
$$
WITH T0 (ShiftCalendarID, CurDay, PrvDay)
AS (
SELECT TOP 1
ID AS ShiftCalendarID,
DATEDIFF( day, BeginDate, :dateTime ) % PeriodInDays + 1 AS CurDay,
( CurDay + PeriodInDays - 2 ) % PeriodInDays + 1 AS PrvDay
FROM RAW_CPMS_AAR.ShiftCalendar
WHERE ID = :shiftCalendarID
OR ( :shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= :dateTime )
ORDER BY BeginDate DESC
),
T1 (TimeValue)
AS (
SELECT TIME_FROM_PARTS(
EXTRACT(HOUR FROM :datetime),
EXTRACT(MINUTE FROM :datetime),
EXTRACT(SECOND FROM :datetime))
)
)
SELECT ID as shiftID
FROM Shift, T0, T1
WHERE Shift.ShiftCalendarID = T0.ShiftCalendarID
AND ( ( FromDay = T0.CurDay AND FromTimeOfDay <= T1.TimeValue AND TillTimeOfDay > T1.TimeValue )
OR ( FromDay = T0.CurDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= T1.TimeValue )
OR ( FromDay = T0.PrvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > T1.TimeValue )
);
$$
To add on to Dave Weldon's solution - in UDF bodies, there are no colons in front of parameters. Instead of :shiftCalendarID it is shiftCalendarID and :dateTime is just dateTime. Colons are needed in Stored Procedures, because the parameters are treated as string literal constants, but this is not the case with User Defined Functions.
I have a simple backtest of below EA:
void OnTick()
{
double rsi = iRSI( Symbol(), PERIOD_M5, 14, PRICE_CLOSE, 0 );
int day = TimeDay( TimeCurrent() );
int hour = TimeHour( TimeCurrent() );
int min = TimeMinute( TimeCurrent() );
if ( day == 7
&& hour >= 9
&& hour < 11
) {
Print( Symbol(), " / ", PERIOD_M5, " rsi: ", (string) rsi );
}
}
However, the backtest log seems does not match with show in the chart as this image:
http://i.imgur.com/PRhtvQD.png
Could you please give some explanation?
Q : "Could you please give some explanation?"
Sure, your code calculates & updates a printed RSI(14)-value (per-tick)
Kindly notice, that the previous bar 08:55 has finished with RSI(14)-value well above the HLINE ~ 30% (if in doubts, one can initially Print( iRSI( Symbol(), PERIOD_M5, 14, PRICE_CLOSE, 1 ) ); where you will see the "previous"-bar value numerically.
From about that value ( above ~ 30% ) the newly opened bar [0] will start to "develop" the actual RSI(14)-value, inside the new bar. So, initially, the values will "move" and the graph plots / redraws the line ( we can visualise each such change as a dot, marker or a Hi/Lo-range ), which is THE REASON, why we finally see a blue line fallen to the position, where the Close[0] has "finished" upon exiting of the bar under review (the 09:00 one, at about the 09:04:59:9999 time).
Sirs,
In connection with another problem, I am trying to create an array whose contents are the previous hourly closing values of the EURUSD. I have code as follows:
void Trade()
{
double longThresh = this.longThreshold;
double longTP = this.longTakeProfit;
double longSL = this.longStopLoss;
double shortThresh = this.shortThreshold;
double shortTP = this.shortTakeProfit;
double shortSL = this.shortStopLoss;
int dummyIndex = 0;
Print( "Triggered reload of stack data for trading routine" );
this.stackArray[0] = iClose( "EURUSD", PERIOD_H1, 1 );
this.stackArray[1] = iClose( "EURUSD", PERIOD_H1, 2 );
this.stackArray[2] = iClose( "EURUSD", PERIOD_H1, 3 );
this.stackArray[3] = iClose( "EURUSD", PERIOD_H1, 4 );
this.stackArray[4] = iClose( "EURUSD", PERIOD_H1, 5 );
this.stackArray[5] = iClose( "EURUSD", PERIOD_H1, 6 );
this.stackArray[6] = iClose( "EURUSD", PERIOD_H1, 7 );
this.stackArray[7] = iClose( "EURUSD", PERIOD_H1, 8 );
this.PrintStackArray();
}
The function above is actually an object method. The Object is instantiated, and a do-while loop causes the method above to be re-executed every hour at the five minute mark.
The problem is that when the code above executes an hour later, the PrintStackArray() output indicates that the iClose() function is not keeping up with new candlesticks every hour.
To put it another way, if the code were to execute at 5:05, it would give the same output as it would at 6:05, and in turn give identical output at 7:05.
I cannot for the life of me figure out why re-executing the iClose() functions does not update the array with the new candlestick values. Despite over two weeks of tinkering with this issue, I cannot force my EA to update and recognize new candlestick values.
This may happen uder such condition,that the code was being run without a live-feed of events from market, using just a localhost time-bound triggered Object method invocation ( which was not disclosed as an MCVE above ) thus forever showing the same time-series data head, which under such conditions simply get no live-feed updates, yielding the same [1,2,3,..] values forever:
if ( !IsConnected() )
{ Print( "No connection!" );
return( 0 );
}
may validate your EA state against a live server.
I'm trying to develop a piece of MQL4 code which sends you a notification when an position opened by an Expert Advisor fails to close/liquidate when the conditions specified by the Expert Advisor are met.
Here is what I have so far.The ClosePosition() returns true when the position is closed successfully and returns false when the EA fails to close the position. This is where the else if (ClosePosition == false) kicks in.
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for(int PosSel = ordersTotal-1; PosSel>=0; PosSel--)
{
if(OrderSelect(PosSel,SELECT_BY_POS,MODE_TRADES))
if(OrderTicket() > 0)
if(OrderMagicNumber() == Period())
if(OrderSymbol() == Symbol())
if(TimeCurrent() >=(OrderOpenTime() + 60 * Period()))
{
ClosePosition = OrderClose(OrderTicket(),8,MarketInfo(sym,MODE_BID) + MarketInfo(sym,MODE_SPREAD) * MarketInfo(sym,MODE_POINT),300,clrNONE);
if(ClosePosition == true)
{
Sleep(60000);
int PosSelHist = OrdersHistoryTotal()-1;
bool reshist = OrderSelect(PosSelHist,SELECT_BY_POS,MODE_HISTORY);
if(reshist == true && Digits == 5)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been closed on the account "+AccountName()+
"\n"+
"\nThe order exit price for this trade is "+DoubleToStr(ClosingPrice,5)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
"\n"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+"has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
else if(reshist == true && Digits == 3)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been placed on the account "+AccountName()+
"\n"+
"\nThe order entry price for this trade is "+DoubleToStr(ClosingPrice,3)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+" has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
}
else if(ClosePosition == false)
{
int failedClosePosition = OrdersTotal()-1;
bool fail = OrderSelect(failedClosePosition,SELECT_BY_POS,MODE_HISTORY);
if(fail == true)
{
SendNotification("Order Number #"+IntegerToString(OrderTicket(),10)+" has failed to close. Please refer to error code "+IntegerToString(GetLastError()));
}
}
}
}
Firstly, is this the correct way in getting the desired result, and secondly; is this the correct way of coding the alternative for the ClosePosition == true, or would this be an if instead of an else if?
It is possible that you will try to close your position but fail due to some regular issues - requote, or trade context is busy or some other.
For such reason you MUST make sure the closing price is fresh
RefreshRates();
also you may try to solve TradeContext issue and others, alternative way - try to send some number of close requests:
int ATTEMPTS; // declare on a global scope
int OnInit(){ // initialise
ATTEMPTS = IsTesting() ? 1 : 100; // ternary-op =boolA?valB:valC
//---
return(INIT_SUCCEEDED);
}
void Order_Close(){
int ticket = GetTicketNumberToClose(); // put all checks here
TradeClose(ticket);
}
void TradeClose(int ticket){ // change to bool
// returning T/F if you need
while(IsTradeContextBusy()) Sleep(5); // a blocking-loop
int current_attempt = 0, err=-1;
while(current_attempt < ATTEMPTS){
RefreshRates(); // get fresh prices from Market
if (!OrderClose(ticket,OrderLots(),OrderClosePrice(),5)){
err = GetLastError();
current_attempt++;
}else return;
}
Print( __LINE__,
"failed to close ticket#", ticket,
" at price", DoubleToStr( OrderClosePrice(), Digits ),
". err#", err
); // send notification
// instead of Print() if you need
}
No, sorry. The code is hard to get confirmed to be correct.
Sure, a few syntax errors could be fixed.
A big portion of processing is duplicated, which may work, but is hard to maintain in a longer run and is considered a poor software engineering practice/habit.You may benefit from rather retaining a unique OrderTicket() value once searching the db.POOL and then straight SELECT_BY_TICKET, which is robust against all order_state / order_relative_position changes in both of the { MODE_TRADES | MODE_HISTORY } parts of the db.POOL.
Next is the worse enemy for the proposed MQL4 code:
If one may believe this, never block the flow of the code. MQL4 code-execution environment is event-based, triggered by the external source of events ( The Market ) and calling Sleep( 60000 ) is worse than taking a sleep on the rails, right in the exit from the EuroTunnel. OUCH!!
Your code is envictimed not to be able to react, and worse, not to be able to let other parts of the MQL4 code eco-system breathe in sync with the flow of The Market Events. There are sure better ways, how to do "almost nothing", than Sleep(), believe me.
Efficiency tips:
Avoid code-duplicates and rather use Digits-specific formatting, be it via a variable set to actual number of decimal places, or via StringFormat() patterns.
May enjoy a bit different layout of code, that will help you avoid syntax errors, missed parentheses et al.
Prefer to use globally unique, direct-pointer-alike OrderTicket() numbers, as evaluated in OrderClose() and rather pre-store it's value, as you wish to re-use it later in the code, but not having it readily available from the OrderClose()-moment.
May enjoy another IDE for MQL4 code-effort, where collapsing and columnar blocks become very handy ( Geany, SciTe, JEdit, Notepad++ ).Here, you soon physically view the inefficiency in if(){}else if(){} code-blocks, where the natural mutual {True|False}-dichotomy was duplicated in the else part.
Anyway, enjoy the wild worlds of MQL4
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for ( int PosSel = ordersTotal - 1; // loopVar .SET
PosSel >= 0; // loopVar .PRE-condition
PosSel-- // loopVar .DEC at loop-end
)
{
if ( OrderSelect( PosSel, SELECT_BY_POS, MODE_TRADES ) )
if ( OrderTicket() > 0 )
if ( OrderMagicNumber() == Period() )
if ( OrderSymbol() == Symbol() )
if ( OrderOpenTime() <= TimeCurrent() - ( 60 * Period() ) )
{
ClosePosition = OrderClose( OrderTicket(),
8,
MarketInfo( sym, MODE_BID )
+ MarketInfo( sym, MODE_SPREAD )
* MarketInfo( sym, MODE_POINT ),
300,
clrNONE
);
if ( ClosePosition == true )
{ // ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
Sleep( 60000 ); //|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| BLOCKS EA-EXECUTION
// ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
int PosSelHist = OrdersHistoryTotal() - 1;
bool reshist = OrderSelect( PosSelHist, SELECT_BY_POS, MODE_HISTORY );
if ( reshist == true
&& Digits == 5
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been closed on the account " + AccountName()
+ "\n"
+ "\nThe order exit price for this trade is " + DoubleToStr( ClosingPrice, 5 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ "\n"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ "has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
else if ( reshist == true
&& Digits == 3
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been placed on the account " + AccountName()
+ "\n"
+ "\nThe order entry price for this trade is " + DoubleToStr( ClosingPrice, 3 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ " has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
}
else if ( ClosePosition == false )
{
int failedClosePosition = OrdersTotal() - 1;
bool fail = OrderSelect( failedClosePosition, SELECT_BY_POS, MODE_HISTORY );
if ( fail == true )
{
SendNotification( "Order Number #"
+ IntegerToString( OrderTicket(), 10 )
+ " has failed to close. Please refer to error code "
+ IntegerToString( GetLastError() )
);
}
}
}
}
I'm attempting to modify my market orders to breakeven the position when the position get 100 pips to the good. This also accounts for the StopLevels which are around 20-30 pips for my broker. It checks the param's via a "for(){...} loop" function
The MagicNumber is the timeframe number for the chart it is on (i.e. 240=4H, 60=1H) I don't set a TakeProfit price & initially no StopLoss price.
The EA is not adding a SL to be equal to the opening price when the trade reaches 100 pip in profit (plus stoplevels). Profit points reaches well over 130 points.
My code is below for a OP_SELL order - any help would be appreciated. Regards, Todd
/*Global Declarations*/
double pnlPoints;
double price, sl, tp;
double point;
int stopLevel;
int breakeven;
double newSL;
/*Local Declaratons*/
pnlPoints = 0;
point = MarketInfo( Symbol(), MODE_POINT );
stopLevel = int( MarketInfo( Symbol(), MODE_STOPLEVEL )
+ MarketInfo( Symbol(), MODE_SPREAD )
);
sl = NormalizeDouble( OrderStopLoss(), Digits );
tp = OrderTakeProfit();
breakeven = 100;
for( int s = OrdersTotal() - 1; s >= 0; s-- )
{ if ( ( OrderSelect( s, SELECT_BY_POS, MODE_TRADES ) ) == true )
price = MarketInfo( Symbol(), MODE_ASK );
newSL = NormalizeDouble( OrderOpenPrice(), Digits );
pnlPoints = ( OrderOpenPrice() - price ) / point;
if ( OP_SELL == OrderType() )
if ( Period() == OrderMagicNumber() )
if ( stopLevel < ( newSL - price ) / point )
if ( breakeven < pnlPoints )
if ( newSL != sl )
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
newSL,
tp,
buycolor
);
else if ( ModBuy == false )
{ Print( "OrderModify failed with error #",
GetLastError()
);
}
}
For the moment being,refine the codeandadd self-debuging / tracing code
After OrderModify() use a self-debugging / journaling Print( StringFormat( ... ) ) to document all instructed values used in the actual OrderModify() call and also the remote-execution ( { server-side | StrategyTester } ) reported issues.
The current code does not enter into such self-diagnostics and ModSell is not inspected at all, ModBuy is inspected only at uncertain conditions / by-coincidence at some future visit of the for(){...} code-execution path to a part after newSL == sl ( and all above stated conditions are just by chance met too )
Next, check an assigned value of tp
As stated above,
/*Local Declarations*/
...
tp = OrderTakeProfit();
which introduces a reasonable doubt, that re-using of this ( inherently uncertain value, as no one knows, which OrderSelect() was the last one that set a db.Pool pointer to decide, from which record from the db.Pool this veryOrderTakeProfit() would accidentally read ( if any record is present in db.Pool already ) inside the whole for(){...} traversing the db.Pool records will not meet conditions for setting properly a TakeProfit price in the next series of OrderModify() calls.
This seems to be the root cause, or a source of unhandled exceptions to the valid, Broker-compliant, OrderModify() values.
Try this:
if (newSL != sl ) {
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
OrderOpenPrice(),
0,
OrderExpiration(),
clrRed
);
if(ModBuy == false )
Print( "OrderModify failed with error #", GetLastError());
}
Then check the Expert-tab for error-message if it fails to set the stop.
Also, you need to take note that StopLoss will ONLY occur if you are on the right chart-timeframe; Otherwise, it won't even get into the if-statements.