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);
}
//+------------------------------------------------------------------+
Related
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"
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.
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));
}
}
}
}
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());
}
}
}
I have a list of items (potentially large) from which the user must select one. I'd like to allow the user to type the first few letters of the desired item to jump to the correct place in the list. By default, each keypress jumps to the first item starting with that letter, so you can't type the first several letters. Is there any straightforward way to do this? Any CodeProject or other such example?
I've looked for hours, and found any number of samples for IAutocomplete, but that won't help here because I need to guarantee that the result is in the list.
The only way I can think to do this is to derive from CListBox, capture the keystrokes myself, find the item, run a timer so that new keystrokes after a sufficient pause will start a new search... since I'm not an MFC jock, this is daunting. Any tips much appreciated.
One clarifying note: my ultimate goal is actually to get this keyboard behavior for a ComboBox of DropDownList style (i.e. no edit box). The lack of an edit box rules out most autocomplete code, and the need for ComboBox functionality means I can't use CListCtrl by itself.
After much unnecessary pain, I've discovered that the real correct answer is simply to use LBS_SORT. Simply by specifying this style, the basic vanilla listbox supports the incremental search keyboard shortcut style I wanted. Without LBS_SORT (or CBS_SORT for a combobox), you get the irritating and almost-useless jump-to-first-letter-only behavior. I didn't try LBS_SORT because my list contents were added in sorted order anyway.
So the dozen or so hours of investigating custom controls, etc., all for naught because the Microsoft documentation makes no mention of this important behavioral difference in the description of LBS_SORT!!
Thanks to everyone who contributed.
I've implemented such a functionality in core Win32. Heres the code.
Somewhere in your message loop that processes the list box insert:
switch(message)
{
case WM_CHAR:
if(HandleListBoxKeyStrokes(hwnd, wParam) == FALSE)
return FALSE;
....
Heres the code (propably not fully complete):
/* ======================================================================== */
/* ======================================================================== */
#define RETURNr(a, b) // homegrown asserts
BOOLEAN HandleListBoxKeyStrokes(HWND hwnd, UINT theKey)
{
#define MAXCHARCACHEINTERVALL 600.0 // Max. milisecs time offset to consider as typed 'at once'
static char sgLastChars[255] = {'0'};
static double sgLastCharTime = 0.;
static HWND sgLasthwnd = NULL;
if(GetSecs() - sgLastCharTime > MAXCHARCACHEINTERVALL ||
sgLasthwnd != hwnd)
*sgLastChars = 0;
if(theKey == ' ' && *sgLastChars == 0)
return TRUE;
sgLastCharTime = GetSecs();
sgLasthwnd = hwnd;
AppendChar(sgLastChars, toupper(theKey));
if(strlen(sgLastChars) > 1)
{
LONG l = GetWindowLong(hwnd, GWL_STYLE);
Char255 tx;
GetClassName(hwnd, tx, sizeof(tx));
if( (! stricmp(tx, "Listbox") &&
! (l & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) ) ||
(! stricmp(tx, "ComboBox") && // combo Box support
l & CBS_DROPDOWNLIST &&
! (l & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) )
{
long Count, l, BestMatch = - 1, BestMatchOff = 0;
long LBcmdSet[] = {LB_GETCOUNT, LB_GETTEXTLEN , LB_GETTEXT};
long CBcmdSet[] = {CB_GETCOUNT, CB_GETLBTEXTLEN, CB_GETLBTEXT};
long *cmdSet = (! stricmp(tx, "ComboBox")) ? CBcmdSet : LBcmdSet;
RETURNr((Count = SendMessage(hwnd, cmdSet[0], 0, 0)) != LB_ERR, 0);
for(int i = 0; i < Count; i++)
{
RETURNr((l = SendMessage(hwnd, cmdSet[1], i, 0)) != LB_ERR, TRUE);
RETURNr( l < sizeof(tx), TRUE);
RETURNr((l = SendMessage(hwnd, cmdSet[2], i, (LPARAM)&tx)) != LB_ERR, TRUE);
strupr(tx);
if(! strncmp(tx, sgLastChars, strlen(sgLastChars)))
{
SelListBoxAndNotify(hwnd, i);
return FALSE;
}
char *p;
if(p = strstr(tx, sgLastChars))
{
int off = p - tx;
if(BestMatch == -1 || off < BestMatchOff)
{
BestMatch = i;
BestMatchOff = off;
}
}
}
// If text not found at start of string see if it matches some part inside the string
if(BestMatch != -1)
SelListBoxAndNotify(hwnd, BestMatch);
// Nothing found - dont process
return FALSE;
}
}
return TRUE;
}
/* ======================================================================== */
/* ======================================================================== */
void SelListBoxAndNotify(HWND hwnd, int index)
{
// i am sorry here - this is some XVT-toolkit specific code.
// it has to be replaced with something similar for native Win32
WINDOW win = xvtwi_hwnd_to_window(hwnd);
WINDOW parent = xvt_vobj_get_parent(win);
xvt_list_set_sel(win, index, 1);
EVENT evt;
memset(&evt, 0, sizeof(evt));
evt.type = E_CONTROL;
evt.v.ctl.id = GetDlgCtrlID(hwnd);
evt.v.ctl.ci.v.lbox.dbl_click = FALSE;
xvt_win_dispatch_event(parent, &evt);
}
/* ======================================================================== */
/* ======================================================================== */
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}
/* ======================================================================== */
/* ======================================================================== */
char AppendChar(char *tx, char C)
{ int i;
i = strlen(tx);
tx[i ] = C;
tx[i + 1] = 0;
return(C);
}
Can you use a CListView CListCtrl instead? They work like that by default.