How to modify a StopLoss of an active trade? - algorithmic-trading

I have trouble with modifying the stoploss of a running trade using MQL5. Selecting the order works out for me. But if I try to access the variables ( for instance OrderTicket() & OrderOpenPrice() ), it always returns 0.00000:
2017.06.01 00:06:32.114 2016.04.08 00:00:00 failed modify buy 0.00 sl: 0.00000, tp: 0.00000 -> sl: 1.41594, tp: 0.00000 [Invalid request]
Here's my stoploss modyfing void:
void modifyStops() {
int total = OrdersTotal(); // total number of placed pending orders
Print( total + " Orders on the line!!!" );
//--- Over all placed pending orders
for ( int i = 0; i < total; i++ )
{ bool isOrderSelected = OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
if ( isOrderSelected )
{ // TODO: Check the Trades to contain the correct Order Number
Print( "Symbol & Magicnumber matching" );
double newStopLoss;
// Update the stop loss
if ( OrderType() == OP_BUY )
{
newStopLoss = addTolerance( SL );
}
else if ( OrderType() == OP_SELL )
{
newStopLoss = minusTolerance( SL );
}
newStopLoss = NormalizeDouble( newStopLoss, Digits );
Print( "NEW STOP LOSS::::=====> ", Symbol(), " at ", newStopLoss );
if ( !OrderModify( OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, Green ) )
{
Print( "OrderModify returned the error of ", GetLastError() );
}
}
}
The CTrade class isn't working properly for me. I tried to implement the code you've posted - however: It still doesn't seem to work out.
Unfortunately I implemented that in my EA and the OrderGetTicket(i) returns zero when the trade is live. So my void looks like this:
void modifyStops() {
for(int i=0; i<PositionsTotal();i++)
{
ulong ticket;
if((ticket=PositionGetTicket(i))>0)
{
//--- return order properties
double open_price =PositionGetDouble(POSITION_PRICE_OPEN);
datetime time_open =(datetime)PositionGetInteger(POSITION_TIME);
string symbol =PositionGetString(POSITION_SYMBOL);
int order_magic =PositionGetInteger(POSITION_MAGIC);
double volume =PositionGetDouble(POSITION_VOLUME);
double stoploss =PositionGetDouble(POSITION_SL);
double takeprofit =PositionGetDouble(POSITION_TP);
ENUM_ORDER_TYPE type =EnumToString(ENUM_ORDER_TYPE(PositionGetInteger(POSITION_TYPE)));
//--- prepare and show information about the order
printf("#ticket %d %s %G %s at %G, with sl: %G tp: %G was set up at %s",
ticket, // order ticket
type, // type
volume, // placed volume
symbol, // symbol
open_price, // specified open price
stoploss, //
takeprofit, //
TimeToString(time_open) // time of order placing
);
}
}
}
And the printf function returns nothing:
2017.06.02 01:42:26.910 2016.04.07 00:00:00 #ticket 1 (non-string passed) 0 at 0, with sl: 0 tp: 0 was set up at 1970.01.01 00:00
I can't believe it's that hard to simply modify an SL in MQL5. That's horribly. However I need to get through it to test my strategy over several pairs...
Do you have another idea? I set up trades with the following code:
void createPendingOrder(ENUM_ORDER_TYPE orderType, double lots, double stopLoss) {
MqlTradeRequest request={0};
MqlTradeResult result={0};
//--- parameters to place a pending order
request.action =TRADE_ACTION_PENDING; // type of trade operation
request.symbol =Symbol(); // symbol
request.volume =lots; // volume of 0.1 lot
//request.deviation=2; // allowed deviation from the price
request.magic =224466 ; // MagicNumber of the order
//int offset = 3; // offset from the current price to place the order, in points
double price; // order triggering price
double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); // value of point
int digits=SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); // number of decimal places (precision)
//--- checking the type of operation
if(orderType==ORDER_TYPE_BUY_STOP)
{
request.type =ORDER_TYPE_BUY_STOP; // order type
price =entryPrice;
request.price =NormalizeDouble(price,digits); // normalized opening price
request.sl =stopLoss;
}
else if(orderType==ORDER_TYPE_SELL_STOP)
{
request.type =ORDER_TYPE_SELL_STOP; // order type
price =entryPrice;
request.price =NormalizeDouble(price,digits); // normalized opening price
request.sl =stopLoss;
}
else Alert("This example is only for placing pending orders"); // if not pending order is selected
//--- send the request
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code
//--- information about the operation
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
}
Would it for instance be possible to save the result object in a Array and then access the running trade through that object?

Your problem is you are trying to run MQL4 code in MQL5.
There are no OrderModify(), OrderOpenPrice(), OrderTicket() in MQL5!!!
See the documentation here on how to select, query values and modify trades.
you will need to be using OrderGetDouble(), OrderGetInteger() and OrderGetString() to query open price, stop loss etc.
e.g.
if((ticket=OrderGetTicket(i))>0)
{
//--- return order properties
open_price =OrderGetDouble(ORDER_PRICE_OPEN);
time_setup =(datetime)OrderGetInteger(ORDER_TIME_SETUP);
symbol =OrderGetString(ORDER_SYMBOL);
order_magic =OrderGetInteger(ORDER_MAGIC);
positionID =OrderGetInteger(ORDER_POSITION_ID);
initial_volume=OrderGetDouble(ORDER_VOLUME_INITIAL);
type =EnumToString(ENUM_ORDER_TYPE(OrderGetInteger(ORDER_TYPE)));
//--- prepare and show information about the order
printf("#ticket %d %s %G %s at %G was set up at %s",
ticket, // order ticket
type, // type
initial_volume, // placed volume
symbol, // symbol
open_price, // specified open price
TimeToString(time_setup)// time of order placing
);
}
Orders are modified using the OrderSend() function https://www.mql5.com/en/docs/trading/ordersend
Update
MQL5 uses a much more complex system of Orders, Positions, Deals and historyOrders. An MQL5 community article attempts to explain how they all relate to one another.
Orders = Pending trades (Buy Stop, Buy Limit, Sell Stop, Sell Limit)
Positions = Open trades (Buy, Sell)
HistoryOrders = Closed/Deleted Trades
Deals = transactions that make up an order/position
To loop through and look at pending Orders:
for(int i=0; i<OrdersTotal();i++)
{
if((ticket=OrderGetTicket(i))>0)
{
//--- return order properties
open_price =OrderGetDouble(ORDER_PRICE_OPEN);
time_setup =(datetime)OrderGetInteger(ORDER_TIME_SETUP);
symbol =OrderGetString(ORDER_SYMBOL);
order_magic =OrderGetInteger(ORDER_MAGIC);
positionID =OrderGetInteger(ORDER_POSITION_ID);
initial_volume=OrderGetDouble(ORDER_VOLUME_INITIAL);
type =EnumToString(ENUM_ORDER_TYPE(OrderGetInteger(ORDER_TYPE)));
//--- prepare and show information about the order
printf("#ticket %d %s %G %s at %G was set up at %s",
ticket, // order ticket
type, // type
initial_volume, // placed volume
symbol, // symbol
open_price, // specified open price
TimeToString(time_setup)// time of order placing
);
}
}
To loop through and look at open trades:
for(int i=0; i<PositionsTotal();i++)
{
if((ticket= PositionGetTicket(i))>0)
{
//--- return order properties
open_price =PositionGetDouble(POSITION_PRICE_OPEN);
time_open =(datetime)PositionGetInteger(POSITION_TIME);
symbol =PositionGetString(POSITION_SYMBOL);
order_magic =PositionGetInteger(POSITION_MAGIC);
volume =PositionGetDouble(POSITION_VOLUME);
stoploss =PositionGetDouble(POSITION_SL);
takeprofit =PositionGetDouble(POSITION_TP);
type =EnumToString(ENUM_ORDER_TYPE(PositionGetInteger(POSITION_TYPE)));
//--- prepare and show information about the order
printf("#ticket %d %s %G %s at %G, with sl: %G tp: %G was set up at %s",
ticket, // order ticket
type, // type
volume, // placed volume
symbol, // symbol
open_price, // specified open price
stoploss, //
takeprofit, //
TimeToString(time_open) // time of order placing
);
}
}
Hopefully, someone else will be able to provide a better explanation of Orders, Positions, Deals, history Orders as they still give me a headache.
To make it simpler I usually just create an instance of the CTrade Class
Update2
Minimal example of trailSL for buy Positions using standard trade functions and Ctrade class
Init
Ctrade *m_trade;
CSymbolInfo *m_symbol;
Void OnInit()
{
m_trade = new Ctrade();
m_trade.SetExpertMagicNumber(100);
m_symbol = new CSymbolInfo();
m_symbol.Name(Symbol());
}
void OnTick()
{
m_symbol.RefreshRates();
}
Trail SL of Buy trade with standard functions
void modifysl()
{
ulong ticket;
MqlTradeRequest request = {0};
MqlTradeResult result = {0};
double newsl;
for(int i=0; i<PositionsTotal();i++)
{
ticket=PositionGetTicket(i);
if(ticket>0)
{
request.action = TRADE_ACTION_SLTP; // type of trade operation
request.position = ticket; // ticket of the position
request.symbol = PositionGetString(POSITION_SYMBOL); // symbol
request.sl = PositionGetDouble(POSITION_SL); // Stop Loss of the position
request.tp = PositionGetDouble(POSITION_TP); // Take Profit of the position
request.magic = 100; // MagicNumber of the position
newsl = NormalizeDouble(m_symbol.Bid()-100*m_symbol.Point(),
m_symbol.Digits());
if(newsl>request.sl)
{
request.sl = newsl;
if(!OrderSend(request,result))
{
PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code
}
//--- information about the operation
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
}
}
}
}
Trail Buy Position StopLoss using CTrade
void modifyslCtrade()
{
ulong ticket;
MqlTradeRequest request= {0};
MqlTradeResult response ={0};
double newsl;
for(int i=0; i<PositionsTotal();i++)
{
ticket=PositionGetTicket(i);
if(ticket>0)
{
newsl = NormalizeDouble(m_symbol.Bid()-100*m_symbol.Point(),
m_symbol.Digits());
if(newsl>PositionGetDouble(POSITION_SL))
{
m_trade.PositionModify(ticket,
newsl,
PositionGetDouble(POSITION_TP));
}
}
}
}

Related

Requesting random number on Chainlink Testnet and getting zeroes

I have been working on something that encapsulates chainlink random number on nfts to provide them to users, using a chainlink subscription and adding my smart contract as a comsumer. When working on testnet I am finding some times it gives me zero numbers and not a random one. This behaviour is random. Subscription is funded and smart contract added as a comsumer.
May this happen on mainnet also?
On most cases this kind of errors are only testnet timeouts, or other stuff related to slower infrastructure.
I wish to implement something to prevent shipping the NFT when zeroes are recevied:
I tried to put assert(randomNumber!=[zero]); but I got some errors, as gas stimation functions on wallets can ensure this, so they set highest fee.
Any suggestions to keep this secured?
This is the main testnet smart contract bsc address https://testnet.bscscan.com/address/0x74623BaE2c3AcC39Db224c236229dc4d5aD1F64d#code
is there any warranty the request random number operation finishes succesfully, or how can I take care of it on my code?
I have posted chainlink related functions too, where I slice the numbers to get them one by one in the lottery.
Subscription is funded and smart contract added as a comsumer. geting some times zero numbers and not a random one
these are the two functions
function closeSaleGetWinner()
external
nonReentrant
onlyRole(OPERATOR_ROLE)
{
requestRandomWords();
require(
isDrawLive,
"There's not a live draw neither ticket sale is opened"
);
uint256[6] memory numberOfMatches;
uint256 drawPrice;
// set the total pool price to BUSD smart contract balance
drawPrice =
checkBUSDContractBalance() *
allDraws[currentDraw].poolPercentage; // use 1 * 10**18 for use the whole pool
// close ticket sale and get random winner number from s_randomWords
isDrawLive = false;
//assert(s_randomWords[0]!=0);
allDraws[currentDraw].winnerNumber = s_slicedRandomWords;
//unchecked {
uint256 j;
Ticket storage _ticket;
uint256 _match;
// check and update matched numbers per ticket on allTickets structure
for (uint256 i = 0; i < drawToTickets[currentDraw].length; i++) {
j = drawToTickets[currentDraw][i];
_ticket = allTickets[j];
_match = checkWinner(_ticket);
_ticket.matchedNumbers = _match;
numberOfMatches[_match] = numberOfMatches[_match] + 1;
}
// after storing number of winners with [_match] matches calculate win per group
// it's time to overwrite reward variable with
// 1st the part of the price from the total pool for #i number of matches
// 2nd divide e
for (uint256 i = 0; i < 5; i++) {
allDraws[currentDraw].reward[i] =
allDraws[currentDraw].reward[i] *
drawPrice;
if (numberOfMatches[i + 1] > 0) {
allDraws[currentDraw].reward[i] = SafeMath.div(
allDraws[currentDraw].reward[i],
numberOfMatches[i + 1]
);
} else {
allDraws[currentDraw].reward[i] = 0;
}
}
// once stored delete random generated number for further checks
delete (s_randomWords);
delete (s_slicedRandomWords);
}
/*
compares the ticket number with the winner number of the draw and returns a value
representing matched number between 0 to 5 (6 values)
*/
function checkWinner(Ticket storage t) internal view returns (uint256) {
uint256 _match = 0;
// we go and compare digit by digit storing number of consecutive matches and stopping when
// there are no more coincidences
uint256[5] memory ticketNumber = t.number;
uint256[5] memory winnerNumber = allDraws[_drawIdCounter.current() - 1]
.winnerNumber;
for (uint256 i = 0; i < 5; i++) {
// If there exists any distinct
// lastTicketDigit, then return No
if (ticketNumber[i] == winnerNumber[i]) {
_match = _match + 1;
} else return _match;
}
return _match;
}
function buyRandomTicket() public nonReentrant {
uint256[] storage myTickets = accounts[msg.sender].myTicketsHistory;
require(isDrawLive, "Sorry there's no live draw by now");
require(!Address.isContract(msg.sender), "only EOA allowed");
address user = address(msg.sender);
uint256 _value = allDraws[currentDraw].ticketPrice;
// check balance and user allowance
uint256 busdUserBalance = BUSD.balanceOf(msg.sender);
require(busdUserBalance >= _value, "Not enough balance");
uint256 allowance = BUSD.allowance(msg.sender, address(this));
require(allowance >= _value, "Check the BUSD allowance");
uint256 devsReward = _value.mul(5).div(100);
uint256 otherReward = _value.mul(20).div(100);
// get payment
BUSD.safeTransferFrom(msg.sender, address(this), _value);
requestRandomWords();
BUSD.safeTransfer(w1, devsReward);
BUSD.safeTransfer(w2, devsReward);
BUSD.safeTransfer(w3, otherReward);
/*pay referral*/
if (accounts[msg.sender].referrer != address(0))
payReferral(_value, address(msg.sender));
Ticket memory randomTicket = Ticket(
user,
currentDraw,
_ticketIdCounter.current(),
s_slicedRandomWords,
false,
0
);
//require(s_randomWords[0]!=0);
uint256[] storage drawTickets = drawToTickets[currentDraw];
// add to the mapping to store tickets sold for a draw
drawTickets.push(randomTicket.ticketID);
myTickets.push(randomTicket.ticketID);
allTickets.push(randomTicket);
safeMint(user);
// set to 0 random storage variable for further checks
delete (s_randomWords);
delete (s_slicedRandomWords);
}
/* CHAINLINK FUNCTIONS */
// Assumes the subscription is funded sufficiently.
function requestRandomWords() internal {
// Will revert if subscription is not set and funded.
s_requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
uint256 _lastDigit;
s_randomWords = randomWords;
uint256 aux = randomWords[0];
for (uint256 i = 0; i < 5; i++) {
_lastDigit = aux % 10;
s_slicedRandomWords[i] = _lastDigit;
aux = aux / 10;
}
}
```

Expert Advisor timefilter doesn't work (mql5)?

I can't figure out why my timefilter doesn't work. Let's say I would like to only enter to positions between 7:35-11:30 and 14:30-22:30 and I don't want to enter a position on Friday.
The time filter only works when I create a simple EA with only a trade.Buy function and no other conditions.
The more complex EA should only enter a position when the vaule of the Supertrend indicator becomes higher/lower than the price and only in the given time intervals.
It should close the position at the next sell/buy signal (if it was a buy position then the position should be closed at the next 'sell' signal' ). When closing positions the time interval shouldn't matter it should only mater when entering a new position.
The 'TradingIsAllowed' variable should be 'true' when the current time is in the allowed time intervals but it always returns false for some reason and I can't figure out why.
It works perfectly fine when I don't use the supertrend and close trades with a simple tp/sl.
Could you please help me?
#include <Trade\Trade.mqh>
CTrade trade;
ulong posTicket;
input double Lots=0.1;
int stHandle;
int totalBars;
input ENUM_TIMEFRAMES Timeframe = PERIOD_CURRENT;
input int Periods =12;
input double Multiplier = 3.0;
//for the timefilter
input string StartTradingTime="07:35";
input string StopTradingTime="11:30";
input string StartTradingTime2="14:35";
input string StopTradingTime2="22:30";
string CurrentTime;
bool TradingIsAllowed=false;
bool TradingIsAllowed2=false;
int OnInit(){
totalBars=iBars(_Symbol,Timeframe);
stHandle = iCustom(_Symbol, Timeframe, "Supertrend.ex5", Periods, Multiplier);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){
}
void OnTick(){
//for the timefilter
datetime LocalTime=TimeLocal();
string HoursAndMinutes=TimeToString(LocalTime,TIME_MINUTES);
string YearAndDate=TimeToString(LocalTime, TIME_DATE);
MqlDateTime DateTimeStructure;
TimeToStruct(LocalTime, DateTimeStructure);
int DayOfWeek=DateTimeStructure.day_of_week;
datetime time = TimeLocal();
CurrentTime=TimeToString(time,TIME_MINUTES);
//this should only run if there is a new bar
int bars=iBars(_Symbol, Timeframe);
if(totalBars !=bars){
totalBars=bars;
double st[];
CopyBuffer(stHandle,0,0,3,st);
double close1 = iClose(_Symbol, Timeframe, 1);
double close2 = iClose(_Symbol, Timeframe, 2);
//BUY CONDITION
if(close1 > st[1] && close2 < st[0]){
if(posTicket > 0 ){
if(PositionSelectByTicket(posTicket)){
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
if (trade.PositionClose(posTicket)){
Print(__FUNCTION__," > Pos ", posTicket, "was closed..");
}
}
}
}
if(CheckTradingTime()==true || CheckTradingTime2()==true){
if(PositionsTotal()==0 && DayOfWeek!=5){
Print(__FUNCTION__, " > BOUGHT");
if(trade.Buy(Lots, _Symbol)){
if(trade.ResultRetcode() == TRADE_RETCODE_DONE){
posTicket= trade.ResultOrder();
}
}
}
}
}
else if(close1 < st[1] && close2 > st[0]){
if(posTicket > 0 ){
if(PositionSelectByTicket(posTicket)){
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
if (trade.PositionClose(posTicket)) {
Print(__FUNCTION__," > Pos ", posTicket, "was closed..");
}
}
}
}
if(CheckTradingTime()==true || CheckTradingTime2()==true){
if(PositionsTotal()==0 && DayOfWeek!=5){
Print(__FUNCTION__, " > SOLD");
if(trade.Sell(Lots, _Symbol)){
if(trade.ResultRetcode() == TRADE_RETCODE_DONE){
posTicket= trade.ResultOrder();
}
}
}
}
}
}
Comment (
"TradingIsAllowed", TradingIsAllowed, TradingIsAllowed2, "\n", //TradingIsAllowed always returns false..
"Current Time=", CurrentTime,"\n",
"Trading Session1=", StartTradingTime,"-" ,StopTradingTime, "\n",
"Trading Session2=", StartTradingTime2, "-", StopTradingTime2,"\n",
"Day of Week", DayOfWeek
);
}
//trading session 1
bool CheckTradingTime()
{
if(StringSubstr(CurrentTime,0,5)==StartTradingTime)
TradingIsAllowed=true;
if(StringSubstr(CurrentTime,0,5)==StopTradingTime)
TradingIsAllowed=false;
return TradingIsAllowed;
}
//trading session 2
bool CheckTradingTime2()
{
if(StringSubstr(CurrentTime,0,5)==StartTradingTime2)
TradingIsAllowed2=true;
if(StringSubstr(CurrentTime,0,5)==StopTradingTime2)
TradingIsAllowed2=false;
return TradingIsAllowed2;
}
you dont neet to write "(StringSubstr(CurrentTime,0,5)==StartTradingTime)"
you can write only "CurrentTime == StartTradingTime"

How to use CopyRates() to search and filter through several timeframes for Bullish Engulfing pattern

I am trying to use CopyRates() to search for a bullish engulfing candlestick pattern (bearish candle followed by a bigger bullish candle) on several timeframes (all timeframes H2 to M10 within an H4 bullish candle after it closes). I read the definition of CopyRates() but I'm finding it a bit challenging to implement. The idea here is from the patterns I want to filter the pattern that has the biggest bearish to bullish candle pair ratio. See what I've done so far below:
In the OnTick():
for (int i=ArraySize(timeframes); i>=1; i--) {
if(CopyRates(Symbol(), timeframes[i - 1], 1, MyPeriod, rates)!=MyPeriod) {
Print("Error CopyRates errcode = ",GetLastError());
return;
}
// Using bullish engulfing pattern:
if ((rates[numCandle].open < rates[numCandle].close) &&
(rates[numCandle + 1].open > rates[numCandle + 1].close) &&
(rates[numCandle + 1].open < rates[numCandle].close) &&
(rates[numCandle + 1].close > rates[numCandle].open)) {
// Not too certain what should be done here
}
}
Here's the other related code:
input int numCandle=0;
MqlRates rates[];
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
void OnInit() {
ArraySetAsSeries(rates, true);
}
UPDATED
Below is the definition of the bullish engulfing pattern:
The bullish engulfing pattern as shown in the above image is a bearish candle followed by a bullish candle. The bearish candle’s open less than the bullish candle’s close and the bearish candle’s close is greater than the bullish candle’s open. Please note that in several cases, the bearish candle's close is greater than the bullish candle's open by only a fraction. Each of the candles has a body size bigger than it’s upper and lower wicks combined.
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
//ENUM_TIMEFRAMES timeframes[4] = {PERIOD_H1, PERIOD_M30, PERIOD_M15, PERIOD_M5};
//---
const int LONG=1, SHORT=-1, NO_DIR=0;
const ENUM_TIMEFRAMES timeframeHighest = PERIOD_H4;
string bestRatioObjectName="bestBullish2BearishPattern!";
datetime lastCandleTime=0;
void OnTick()
{
if(!isNewBar(PERIOD_H4))
return;
//most likely you will call this block after new bar check?
MqlRates rates[];
ArraySetAsSeries(rates,true);
if(CopyRates(_Symbol,timeframeHighest,0,2,rates)==-1)
{
printf("%i %s: failed to load/copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
if(getCandleDir(rates[1])!=LONG)
return;
const datetime timeStart=rates[1].time, timeEnd=rates[0].time; //within a bullish H4 candle - DONE
double bestRatio = -1;//once a bearish2bullish ratio is higher, we'll move to new place
for(int i=ArraySize(timeframes)-1;i>=0;i--)
{
if(CopyRates(_Symbol,timeframes[i],timeStart,timeEnd,rates)<0)
{
printf("%i %s: failed to copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
processRates(rates,bestRatio,bestRatioObjectName);
}
printf("%i %s: best=%.5f, objName =%s: %.5f-%.5f",__LINE__,__FILE__,bestRatio,bestRatioObjectName,
ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE1),ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE2));
//ExpertRemove();//for scripting, a one time call
}
bool isNewBar(const ENUM_TIMEFRAMES tf)
{
const datetime time=iTime(_Symbol,tf,0);
if(time>lastCandleTime)
{
lastCandleTime=time;
return true;
}
return false;
}
int getCandleDir(const MqlRates& rate) // candle direction: +1 for BULL, -1 for BEAR
{
if(rate.close-rate.open>_Point/2.)
return 1;
if(rate.open-rate.close>_Point/2.)
return-1;
return 0;
}
void processRates(const MqlRates& rates[],double &best,const string bestObjName)
{
for(int i=ArraySize(rates)-2; i>0; /* no sense to catch last candle - we cant compare it with anybody */ i--)
{
if(getCandleDir(rates[i])!=LONG)
continue;//current - bullish
if(getCandleDir(rates[i+1])!=SHORT)
continue;//prev - bearish
if(rates[i].close-rates[i+1].open>_Point/2.){}
else continue;
if(rates[i+1].close-rates[i].open>_Point/2.){}
else continue;
const double body=rates[i].close-rates[i].open, twoWicks = rates[i].high-rates[i].low- body;
if(body<twoWicks)
continue; //Each of the candles has a body size bigger than it’s upper and lower wicks combined.
//---
const double prevBody = rates[i+1].open - rates[i+1].close;
const double newRatio = body / prevBody;
if(newRatio>best) // eventually we'll find best bull2bear ratio
{
moveRectangle(rates[i+1],rates[i].time,bestObjName);
best = newRatio;
}
}
}
void moveRectangle(const MqlRates& rate,const datetime rectEnd,const string objectName)
{
if(ObjectFind(0,objectName)<0)
{
if(!ObjectCreate(0,objectName,OBJ_RECTANGLE,0,0,0,0,0))
{
printf("%i %s: failed to draw %s. error=%d",__LINE__,__FILE__,objectName,_LastError);
return;
}
//add GUI things like how to display the rectangle
}
//moving the rectangle to a new place, even for the first time
ObjectSetDouble(0,objectName,OBJPROP_PRICE,0,rate.open);
ObjectSetDouble(0,objectName,OBJPROP_PRICE,1,rate.close);
ObjectSetInteger(0,objectName,OBJPROP_TIME,0,rate.time);
ObjectSetInteger(0,objectName,OBJPROP_TIME,1,rectEnd);
}
Assuming that MyPeriod is initialized to 2, the rest of the code seems correct. You should create a variable to keep the timeframe that had the greatest ratio. Inside your if you have to calculate the candlestick body size for candle+1 and candle and calculate the ratio, then if the calculated ratio is greater than the previous calculated you change the value AND update the timeframe in which you find it.
By the end of your for loop you may decide in which timeframe you want to put your order.

How to get OHLC-values from each new candle?

I am new in MQL5 and I am trying to capture the values of Open, High, Low and Close of each new candle.
For now I am using a one minute TimeFRAME for each candle.
I read the documentation and have not figured out how can I do it.
My only clue was the CopyOpen() functions, but I am still stuck.
Let's split the task:
How to read OHLC-values?
How to detect (each) new candle?
A1: MQL4/MQL5 syntax reports OHLCV-values straight in Open[], High[], Low[], Close[], Volume[] time-series arrays. As a rule of thumb, these arrays are time-series, reverse-stepping indexed, so that the most recent cell ( The Current Bar ( candle ) ) always has cell-index == 0. So Open[1], High[1], Low[1], Close[1] are values for the "current instrument" ( _Symbol ), retrieved from the "current TimeFRAME" for a candle, that was already closed right before the "current Candle" has started. Complex? Well, just on the first few reads. You will get acquainted with this.
If your code does not want to rely on "current" implicit contexts, the syntax allows one to use explicit, indirect, specifications:
/* iVolume( ||| ... )
iTime( ||| ... )
iClose( ||| ... )
iLow( ||| ... )
iHigh( vvv ... ) */
iOpen( aTradingSymbolNameSTRING, // Broker specific names, "DE-30.." may surprise
PERIOD_M1, // explicit reference to use M1 TimeFRAME
1 // a Cell-index [1] last, closed Candle
)
A2: There is neat way how to detect a new Candle, indirectly, the same trick allows one to thus detect a moment, when the previous Candle stops evolving ( values do not change anymore ) which thus makes sense to report "already frozen" OHLCV-values to be reported anywhere else.
Remeber, the "current" OHLCV-registers-[0] are always "hot" == continuously changing throughout the time of the "current" TimeFRAME Candle duration, so one has to wait till a new Candle starts ( indirectly meaning the "now-previous" Candle [0] has ended and has thus got a reverse-stepping index "re-indexed" to become [1], a frozen one ).
For detecting a new candle it is enough to monitor changes of a system register int Bars, resp. an indirect, context aware, int iBars( ... ).
One may realise, that there are some "theoretical" Candles, that do not happen and are thus not "visible" / "accessible" in data of time-series -- whence a market was not active during such period of time and no PriceDOMAIN change has happened during such administratively-framed epoch in time -- for such situations, as there was no price-change, there was no QUOTE and thus such candle did not happen and is "missing" both in linear counting and in data-cells. The first next QUOTE arrival is thus painted right "besides" a candle, that was principally "older" than a "previous"-neighbour ( the missing candles are not depicted, so due care ought be taken in processing ). This typically happens even on major instruments near the Friday EoB/EoWk market closing times and around midnights UTC +0000 during the 24/5-cycles.
In case you become too frustrated, here is a script that will export selected chart contents the second a new candle appears. Just choose the pair you want and attach this to the chart and you will get exported a .csv file on each new candle.
//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
//| Input Parameters Definition |
//+------------------------------------------------------------------+
extern int BarCount = 500;
extern string Pairs = "EURAUD,EURCAD,EURCHF,EURGBP,EURNZD,EURUSD,EURJPY,AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPUSD,CADCHF,CADJPY,USDCAD,USDCHF,USDJPY,NZDCAD,NZDCHF,NZDJPY,NZDUSD,CHFJPY";
extern string delimiter = ",";
//+------------------------------------------------------------------+
//| Local Parameters Definition |
//+------------------------------------------------------------------+
datetime lastExport[];
string pairs[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//------------------------------------------------------------------
Split(Pairs, pairs, ",");
//------------------------------------------------------------------
if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "")
{
Alert("Pairs are not entered correctly please check it...");
return (0);
}
//------------------------------------------------------------------
ArrayResize(lastExport, ArraySize(pairs));
ArrayInitialize(lastExport, 0);
//------------------------------------------------------------------
Comment("quote exporter is active :)");
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//------------------------------------------------------------------
Comment("");
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
//------------------------------------------------------------------
if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "") return (0);
//------------------------------------------------------------------
BarCount = MathMin(Bars, BarCount);
//------------------------------------------------------------------
for (int j = 0; j < ArraySize(pairs); j++)
{
if (lastExport[j] == Time[0]) continue;
lastExport[j] = Time[0];
if (StringTrimLeft(StringTrimRight(pairs[j])) == "") continue;
if (MarketInfo(pairs[j], MODE_BID) == 0) { Alert("symbol " + pairs[j] + " is not loaded!!!"); continue; }
//------------------------------------------------------------------
string file = pairs[j] + "_" + GetTimeFrameName(0) + ".csv";
int log = FileOpen(file, FILE_CSV|FILE_WRITE, "~");
if (log < 0) { Alert("can not create/overwrite csv file " + file + "!!!"); continue; }
string buffer;
buffer = "Date"+delimiter+"Time"+delimiter+"Open"+delimiter+"High"+delimiter+"Low"+delimiter+"Close"+delimiter+"Volume";
FileWrite(log, buffer);
int digits = MarketInfo(pairs[j], MODE_DIGITS);
for (int i = BarCount; i >= 1; i--)
{
buffer = TimeToStr(Time[i], TIME_DATE)+delimiter+TimeToStr(Time[i], TIME_MINUTES)+delimiter+DoubleToStr(iOpen(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iHigh(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iLow(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iClose(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iVolume(pairs[j], 0, i), 0);
FileWrite(log, buffer);
}
buffer = "0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0";
FileWrite(log, buffer);
FileClose(log);
}
//------------------------------------------------------------------
return(0);
}
//+------------------------------------------------------------------+
string GetTimeFrameName(int TimeFrame)
{
switch (TimeFrame)
{
case PERIOD_M1: return("M1");
case PERIOD_M5: return("M5");
case PERIOD_M15: return("M15");
case PERIOD_M30: return("M30");
case PERIOD_H1: return("H1");
case PERIOD_H4: return("H4");
case PERIOD_D1: return("D1");
case PERIOD_W1: return("W1");
case PERIOD_MN1: return("MN1");
case 0: return(GetTimeFrameName(Period()));
}
}
//+------------------------------------------------------------------+
void Split(string buffer, string &splitted[], string separator)
{
string value = "";
int index = 0;
ArrayResize(splitted, 0);
if (StringSubstr(buffer, StringLen(buffer) - 1) != separator) buffer = buffer + separator;
for (int i = 0; i < StringLen(buffer); i++)
if (StringSubstr(buffer, i, 1) == separator)
{
ArrayResize(splitted, index + 1);
splitted[index] = value;
index ++;
value = "";
}
else
value = value + StringSubstr(buffer, i, 1);
}
//+------------------------------------------------------------------+

Why MQL4 OrderModify() will not modify the order when backtesting?

I'm trying to ADD a stop loss to my open market orders in MetaTrader 4 when a position gets 100 pips "to the good" which is to be equal to the Order Open Price;
OrderStopLoss() == OrderOpenPrice()
But this isn't happening.
I've added Print() & GetLastError() functions and nothing is coming up in the journal, so it must be something in my coding - but cannot see what would be wrong.
OK this is what I have so far, one for loop for the buy, one for the sell. I've also Normalized the "doubles" as I have been advised to do & have also declared the BuyMod & SellMod to "true" at the very top. This should ensure that the default won't resort to false. I also thought it might be helpful if I told you I have the MetaEditor version 5 build 1241:)
The following code I have is the following;
/*Breakeven Order Modification*/
bool BuyMod = true;
bool SellMod = true;
for(int b = OrdersTotal()-1;b>=0;b--)
{
if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
{
double aBidPrice = MarketInfo(Symbol(),MODE_BID);
double anOpenPrice = OrderOpenPrice();
double aNewTpPrice = OrderTakeProfit();
double aCurrentSL = OrderStopLoss();
double aNewSLPrice = anOpenPrice;
double pnlPoints = (aBidPrice - anOpenPrice)/_Point;
double stopPoints = (aBidPrice - aNewSLPrice)/_Point;
int stopLevel = int(MarketInfo(Symbol(),MODE_STOPLEVEL));
int aTicket = OrderTicket();
if(OrderType() == OP_BUY)
if(stopPoints >= stopLevel)
if(aTicket > 0)
if(pnlPoints >= breakeven)
if(aNewSLPrice != aCurrentSL)
{
BuyMod = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,buycolor);
SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
}
}
}
for(int s = OrdersTotal()-1; s>=0; s--)
{
if(OrderSelect(s,SELECT_BY_POS,MODE_TRADES))
{
double anAskPrice = MarketInfo(Symbol(),MODE_ASK);
double anOpenPrice = OrderOpenPrice();
double aNewTpPrice = OrderTakeProfit();
double aCurrentSL = OrderStopLoss();
double aNewSLPrice = anOpenPrice;
double pnlPoints = (anOpenPrice - anAskPrice)/_Point;
double stopPoints = (aNewSLPrice - anAskPrice)/_Point;
int stopLevel = int(MarketInfo(Symbol(),MODE_STOPLEVEL));
int aTicket = OrderTicket();
if(OrderType()== OP_SELL)
if(stopPoints >= stopLevel)
if(pnlPoints >= breakeven)
if(aNewSLPrice != aCurrentSL)
if(aTicket > 0)
{
SellMod = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(aNewSLPrice,Digits),NormalizeDouble(aNewTpPrice,Digits),0,sellcolor);
SendMail("Notification of Order Modification for Ticket#"+IntegerToString(OrderTicket(),10),"Good news! Order Ticket#"+IntegerToString(OrderTicket(),10)+"has been changed to breakeven");
}
}
}
trading algorithmic-trading mql4 metatrader4
shareeditdeleteflag
edited just now
asked 2 days ago
Todd Gilbey
264
You might want to know, StackOverflow does not promote duplicate questions. ( see the
Besides meeting an MQL4 syntax-rules,there are more conditions:
A first hidden trouble is in number rounding issues.
MetaQuotes, Inc., recommends wherever possible, to normalise float values into a proper price-representation.
Thus,wherever a price goes into a server-side instruction { OrderSend(), OrderModify(), ... } one shall always prepare such aPriceDOMAIN valueby a call to NormalizeDouble( ... , _Digits ), before a normalised price hits any server-side instruction call.
May sound rather naive, but this saves you issues with server-side rejections.
Add NormalizeDouble() calls into your code on a regular base as your life-saving vest.
A second, even a better hidden trouble is in STOP_ZONE-s and FREEZE_ZONE-s
While not visible directly, any Broker set's in their respective Terms & Conditions these parameters.
In practice,this means, if you instruct { OrderSend() | OrderModify() } to set / move aPriceDOMAIN level to be setup too close to current actual Ask/Bid ( violating a Broker-forbidden STOP_ZONE )orto delete / modify aPriceDOMAIN level of TP or SL, that are already set and is right now, within a Broker-forbidden FREEZE_ZONE distance from actual Ask/Bid,such instruction will not be successfully accepted and executed.
So besides calls to the NormalizeDouble(), always wait a bit longer as the price moves "far" enough and regularly check for not violating forbidden STOP_ + FREEZE_ zones before ordering any modifications in your order-management part of your algotrading projects.
Anyway, Welcome to Wild Worlds of MQL4
Update: while StackOverflow is not a Do-a-Homework site, let me propose a few directions for the solution:
for ( int b = OrdersTotal() - 1; b >= 0; b-- ) // ________________________ // I AM NOT A FAN OF db.Pool-looping, but will keep original approach for context purposes
{ if ( ( OrderSelect( b, SELECT_BY_POS, MODE_TRADES ) ) == true )
{ // YES, HAVE TO OPEN A CODE-BLOCK FOR if()-POSITIVE CASE:
// ------------------------------------------------------
double aBidPRICE = MarketInfo( Symbol(), MODE_BID ); // .UPD
double anOpenPRICE = OrderOpenPrice(); // .SET FROM a db.Pool Current Record
double aNewTpPRICE = OrderTakeProfit(); // .SET FROM a db.Pool Current Record
double aCurrentSlPRICE = OrderStopLoss(); // .SET FROM a db.Pool Current Record
double aNewSlPRICE = anOpenPRICE; // .SET
double pnlPOINTs = ( aBidPRICE - anOpenPRICE )/_Point; // .SET
double stopPOINTs = ( aBidPRICE - aNewSlPRICE )/_Point; // .SET
// ------------------------------------------------------------ // .TEST
if ( OP_BUY == OrderType() )
if ( Period() == OrderMagicNumber() )
if ( stopPOINTa > stopLevel )
if ( pnlPOINTs >= breakeven )
if ( aNewSlPRICE != aCurrentSlPRICE )
{ // YES, HAVE TO OPEN A BLOCK {...}-CODE-BLOCK FOR THE if()if()if()if()-chain's-POSITIVE CASE:
// -------------------------------------------------------------------------------------------
int aBuyMOD = OrderModify( OrderTicket(),
OrderOpenPrice(),
NormalizeDouble( aNewSlPRICE, Digits ),
NormalizeDouble( aNewTpPRICE, Digits ),
0,
buycolor
);
switch( aBuyMOD )
{ case ( NULL ): { ...; break; } // FAIL ( ANALYSE ERROR )
default: { ...; break; } // PASS OrderModify()
}
}
}
The problem is in your call to a built-in OrderModify() function.
OrderStopLoss() == OrderModify() will evaluate as false which in turn will evaluate as 0 since == is a comparison operator.
An OrderStopLoss() is a call to another built-in function (not a variable), you can't save anything to it so OrderStopLoss() = 4 wouldn't work either.
From the MQL4 documentation:
bool OrderModify( int ticket, // ticket
double price, // price
double stoploss, // stop loss
double takeprofit, // take profit
datetime expiration, // expiration
color arrow_color // color
);
In your case that would be the following, assuming ModBuy is already defined somewhere in the code:
ModBuy = OrderModify( OrderTicket(), // <-ticket from record OrderSelect()'d
OrderOpenPrice(), // <-price from current record
OrderOpenPrice(), // <-price from current record
OrderTakeProfit(), // <-TP from current record
0, // ( cannot set P/O expiration for M/O )
buycolor // ( set a color for a GUI marker )
);
Or you could just use any other valid value instead of the second OrderOpenPrice() to set a new stoploss.
I'm really sorry, I'm new to Stackoverflow, this is the revised code I now have based on everyone's comments & recommendation's below
**Local Declarations**
pnlPoints = 0;
point = MarketInfo(Symbol(),MODE_POINT);
stopLevel = int(MarketInfo(Symbol(),MODE_STOPLEVEL)+MarketInfo (Symbol(),MODE_SPREAD));
sl = NormalizeDouble(OrderStopLoss(),Digits);
tp = OrderTakeProfit();
cmd = OrderType();
breakeven = 100;
**Global Variables**
double pnlPoints;
double price,sl,tp;
double point;
int stopLevel;
int cmd;
int breakeven;
double newSL;
for(int b = OrdersTotal()-1; b>=0; b--)
{
if((OrderSelect(b,SELECT_BY_POS,MODE_TRADES))==true)
price = MarketInfo(Symbol(),MODE_BID);
newSL = NormalizeDouble(OrderOpenPrice(),Digits);
pnlPoints = (price - OrderOpenPrice())/point;
{
if(OrderType()==OP_BUY)
if(OrderMagicNumber() == Period())
if((price-newSL)/point>=stopLevel)
if(pnlPoints>=breakeven)
if(sl!=newSL)
ModBuy = OrderModify(OrderTicket(),OrderOpenPrice(),newSL,tp,buycolor);
else if(ModBuy == false)
{
Print("OrderModify failed with error #",GetLastError());
}
}
}

Resources