• No results found

We're going to add all of the features we've covered in this section to the simple expert advisor we created on page 36. We'll be adding order modification, stop level verification, trade context

checking, predefined variable refreshing and lot size verification to our EA. Here is our file, starting at the beginning:

#property copyright "Andrew Young"

#include <stdlib.mqh>

// External variables

extern bool DynamicLotSize = true;

extern double EquityPercent = 2;

extern double FixedLotSize = 0.1;

extern double StopLoss = 50;

extern double TakeProfit = 100;

extern int Slippage = 5;

extern int MagicNumber = 123;

extern int FastMAPeriod = 10;

extern int SlowMAPeriod = 20;

// Global variables int BuyTicket;

int SellTicket;

double UsePoint;

int UseSlippage;

int ErrorCode;

We've added the #include statement for the stdlib.mqh file that contains the

ErrorDescription() function for our error handling routines. We've added three external variables for the lot sizing, and a global variable for the error code.

The following code goes at the beginning of the start() function:

// Moving averages

double FastMA = iMA(NULL,0,FastMAPeriod,0,0,0,0);

double SlowMA = iMA(NULL,0,SlowMAPeriod,0,0,0,0);

// Lot size calculation if(DynamicLotSize == true)

{

double RiskAmount = AccountEquity() * (EquityPercent / 100);

double TickValue = MarketInfo(Symbol(),MODE_TICKVALUE);

if(Point == 0.001 || Point == 0.00001) TickValue *= 10;

double CalcLots = (RiskAmount / StopLoss) / TickValue;

double LotSize = CalcLots;

The lot size calculation and verification code from page 51 is added to the beginning of our start function. Since our stop loss level is known beforehand, this is a good a place as any to put it. The remaining code is our modified buy market order routine:

// Buy Order

if(FastMA > SlowMA && BuyTicket == 0) {

// Close Order

OrderSelect(SellTicket,SELECT_BY_TICKET);

if(OrderCloseTime() == 0 && SellTicket > 0) {

// Error handling if(Closed == false)

{

ErrorCode = GetLastError();

string ErrDesc = ErrorDescription(ErrorCode);

string ErrAlert = StringConcatenate("Close Sell Order - Error ", ErrorCode,": ",ErrDesc);

Alert(ErrAlert);

string ErrLog = StringConcatenate("Ask: ",Ask," Lots: ",LotSize,

" Ticket: ",SellTicket);

ErrDesc = ErrorDescription(ErrorCode);

ErrAlert = StringConcatenate("Open Buy Order - Error ", ErrorCode,": ",ErrDesc);

Alert(ErrAlert);

ErrLog = StringConcatenate("Ask: ",Ask," Lots: ",LotSize);

Print(ErrLog);

double OpenPrice = OrderOpenPrice();

// Calculate stop level

double StopLevel = MarketInfo(Symbol(),MODE_STOPLEVEL) * Point;

RefreshRates();

double UpperStopLevel = Ask + StopLevel;

double LowerStopLevel = Bid - StopLevel;

double MinStop = 5 * UsePoint;

// Calculate stop loss and take profit

if(StopLoss > 0) double BuyStopLoss = OpenPrice - (StopLoss * UsePoint);

if(TakeProfit > 0) double BuyTakeProfit = OpenPrice + (TakeProfit * UsePoint);

// Verify stop loss and take profit

if(BuyStopLoss > 0 && BuyStopLoss > LowerStopLevel) {

BuyStopLoss = LowerStopLevel - MinStop;

}

if(BuyTakeProfit > 0 && BuyTakeProfit < UpperStopLevel) {

BuyTakeProfit = UpperStopLevel + MinStop;

}

// Modify order

if(IsTradeContextBusy()) Sleep(10);

if(BuyStopLoss > 0 || BuyTakeProfit > 0) {

ErrorCode = GetLastError();

ErrDesc = ErrorDescription(ErrorCode);

ErrAlert = StringConcatenate("Modify Buy Order - Error ", ErrorCode,": ",ErrDesc);

Alert(ErrAlert);

ErrLog = StringConcatenate("Ask: ",Ask," Bid: ",Bid," Ticket: ", BuyTicket," Stop: ",BuyStopLoss," Profit: ",BuyTakeProfit);

Print(ErrLog);

The remainder of our code contains the sell market order placement block, as well as the PipPoint() and GetSlippage() functions. You can view the full code for this expert advisor in Appendix B.

Note that we've added the IsTradeContextBusy() function prior to every trade operation. We want to make sure that the trade thread is free before attempting to trade. We use the RefreshRates()

function before each reference of the Bid or Ask variables, to ensure that we are always using the latest prices.

We begin by selecting the previous sell order ticket and closing it using OrderClose(). If the function fails, the error handling block is run. Next, we open the buy market order using

OrderSend(). If the function fails, it's error handling block is run. Otherwise, we continue to the order modification block.

We select the order that was just placed using OrderSelect(), and assign the order's opening price to the OpenPrice variable. We then calculate the stop level and the upper and lower stop level prices. Next, we calculate our stop loss and take profit prices, verify those, and finally we modify the order using OrderModify(). A final error handling block deals with errors from the order

modification.

Here's how we modify the code for a pending buy stop order:

// Close order

OrderSelect(SellTicket,SELECT_BY_TICKET);

if(OrderCloseTime() == 0 && SellTicket > 0 && OrderType() == OP_SELL) {

double CloseLots = OrderLots();

while(IsTradeContextBusy()) Sleep(10);

RefreshRates();

double ClosePrice = Ask;

bool Closed = OrderClose(SellTicket,CloseLots,ClosePrice,UseSlippage,Red);

// Error handling if(Closed == false)

{

ErrorCode = GetLastError();

string ErrDesc = ErrorDescription(ErrorCode);

string ErrAlert = StringConcatenate("Close Sell Order - Error ",ErrorCode,

": ",ErrDesc);

Alert(ErrAlert);

string ErrLog = StringConcatenate("Ask: ",Ask," Lots: ",LotSize,

" Ticket: ",SellTicket);

Print(ErrLog);

} }

// Delete order

else if(OrderCloseTime() == 0 && SellTicket > 0 && OrderType() == OP_SELLSTOP) {

bool Deleted = OrderDelete(SellTicket,Red);

if(Deleted == true) SellTicket = 0;

// Error handling if(Deleted == false)

{

ErrorCode = GetLastError();

ErrDesc = ErrorDescription(ErrorCode);

ErrAlert = StringConcatenate("Delete Sell Stop Order - Error ",ErrorCode,

": ",ErrDesc);

Alert(ErrAlert);

ErrLog = StringConcatenate("Ask: ",Ask," Ticket: ",SellTicket);

Print(ErrLog);

} }

We've added the code to delete pending orders using OrderDelete() after the OrderClose() function. The order type of the previous sell order determines which function is used to close the order.

The main difference between the following code and the market order code is that we do not have an order modification block. It is not necessary to place the stop loss and take profit separately for pending orders. Therefore we will calculate the stop loss and take profit before placing the order with OrderSend().

// Calculate stop level

double StopLevel = MarketInfo(Symbol(),MODE_STOPLEVEL) * Point;

RefreshRates();

double UpperStopLevel = Ask + StopLevel;

double MinStop = 5 * UsePoint;

// Calculate pending price

double PendingPrice = High[0] + (PendingPips * UsePoint);

if(PendingPrice < UpperStopLevel) PendingPrice = UpperStopLevel + MinStop;

// Calculate stop loss and take profit

if(StopLoss > 0) double BuyStopLoss = PendingPrice - (StopLoss * UsePoint);

if(TakeProfit > 0) double BuyTakeProfit = PendingPrice + (TakeProfit * UsePoint);

// Verify stop loss and take profit UpperStopLevel = PendingPrice + StopLevel;

double LowerStopLevel = PendingPrice – StopLevel;

if(BuyStopLoss > 0 && BuyStopLoss > LowerStopLevel) {

BuyStopLoss = LowerStopLevel - MinStop;

}

if(BuyTakeProfit > 0 && BuyTakeProfit < UpperStopLevel) {

BuyTakeProfit = UpperStopLevel + MinStop;

}

ErrorCode = GetLastError();

ErrDesc = ErrorDescription(ErrorCode);

ErrAlert = StringConcatenate("Open Buy Stop Order - Error ",ErrorCode,

": ",ErrDesc);

Alert(ErrAlert);

ErrLog = StringConcatenate("Ask: ",Ask," Lots: ",LotSize," Price: ",PendingPrice,

" Stop: ",BuyStopLoss," Profit: ",BuyTakeProfit);

Print(ErrLog);

}

SellTicket = 0;

First, we calculate the upper stop level. We then calculate and verify our pending order price, which is stored in PendingPrice. We then recalculate UpperStopLevel and calculate the LowerStopLevel so that they are relative to the pending order price. Note that we do not need to use the Ask or Bid prices, or figure in the spread when verifying the stop loss and take profit prices.

Finally, we place our pending order using OrderSend(), placing the stop loss and take profit along with it. We have the standard error handling function to deal with order placement errors.

Despite all the extra code, these expert advisors are using the same strategy as the one at the end of chapter 2. This code simply has extra features for calculating and verifying lot size, stop levels, stop loss, take profit and pending order prices. We've also added trade context checks and error handling code. In the next chapter, we'll learn how to create functions so we can reuse and simplify this code.

Chapter 4

Related documents