471 lines
19 KiB
MQL5
471 lines
19 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| TimeRangeBreakOut.mq5 |
|
||
|
//| Copyright 2024, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
||
|
#property link "https://www.mql5.com"
|
||
|
#property version "1.00"
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Include |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#include <Trade\Trade.mqh>
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Inputs |
|
||
|
//+------------------------------------------------------------------+
|
||
|
input group "===== General Inputs ======"
|
||
|
input int InpMagicNumber = 1234; // magicNumber
|
||
|
|
||
|
enum LOT_MODE_ENUM{
|
||
|
LOT_MODE_FIXED, // fixed lots
|
||
|
LOT_MODE_MONEY, // lots based on money
|
||
|
LOT_MODE_PCT_ACCOUNT // lots based on % of account
|
||
|
};
|
||
|
input LOT_MODE_ENUM InpLotMode = LOT_MODE_FIXED; // lot mode
|
||
|
input double InpLots = 0.01; // lots / money / % percent
|
||
|
input int InpStopLoss = 150; // stop loss in % of the range (0 = off)
|
||
|
input int InpTakeProfit = 200; // take profit in % of the range (0 = off)
|
||
|
|
||
|
input group "===== Range Inputs ======"
|
||
|
input int InpRangeStart = 600; // range start time in minutes
|
||
|
input int InpRangeDuration = 120; // range duration in minutes
|
||
|
input int InpRangeClose = 1200; // range close time in minutes (-1 = off)
|
||
|
|
||
|
enum BREAKOUT_MODE_ENUM {
|
||
|
ONE_SIGNAL, // one breakout per range
|
||
|
TWO_SIGNALS, // high and low breakout
|
||
|
};
|
||
|
input BREAKOUT_MODE_ENUM InpBreakoutMode = ONE_SIGNAL; // breakout mode
|
||
|
|
||
|
input group "===== Day of week filter ======"
|
||
|
input bool InpMonday = true; // range on monday
|
||
|
input bool InpTuesday = true; // range on Tuesday
|
||
|
input bool InpWednesday = true; // range on Wednesday
|
||
|
input bool InpThursday = true; // range on Thurday
|
||
|
input bool InpFriday = true; // range on Friday
|
||
|
input bool InpSaturday = true; // range on Saturday
|
||
|
input bool InpSunday = true; // range on Sunday
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Global Variables |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct RANGE_STRUCT{
|
||
|
datetime start_time; //start of the range
|
||
|
datetime end_time; // end of the range
|
||
|
datetime close_time; // close time
|
||
|
double high; // high of the range
|
||
|
double low; // low of the range
|
||
|
bool f_entry; // flag if we are inside the range
|
||
|
bool f_high_breakout; // flag if a high breakout occurred
|
||
|
bool f_low_breakout; // flag if a low breakout occurred
|
||
|
|
||
|
// MQL5 is a OOP language !! now is going to define it
|
||
|
RANGE_STRUCT() : start_time(0), end_time(0),close_time(0),high(0),low(DBL_MAX),f_entry(false),f_high_breakout(false),f_low_breakout(false) {};
|
||
|
};
|
||
|
|
||
|
// make a object for Range_struct, then we can use range.xxxxx to use the function
|
||
|
RANGE_STRUCT range;
|
||
|
MqlTick prevTick, lastTick;
|
||
|
CTrade trade;
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert initialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int OnInit(){
|
||
|
|
||
|
// make sure all the input are correct!! if incorrect it will break the function!!
|
||
|
if(!CheckInputs()){return INIT_PARAMETERS_INCORRECT;}
|
||
|
|
||
|
// set magic number for all the trade
|
||
|
trade.SetExpertMagicNumber(InpMagicNumber);
|
||
|
|
||
|
//calculated new range if inputs changed
|
||
|
if(_UninitReason==REASON_PARAMETERS && countOpenPosition() == 0){
|
||
|
CalculateRange();
|
||
|
}
|
||
|
|
||
|
//draw objects if the timeframe changed it will draw a new object !!
|
||
|
DrawObjects();
|
||
|
|
||
|
return(INIT_SUCCEEDED);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert deinitialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnDeinit(const int reason){
|
||
|
|
||
|
// delete objects
|
||
|
ObjectsDeleteAll(NULL,"range"); // it will delete all object which start with "range"
|
||
|
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert tick function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTick() {
|
||
|
|
||
|
// Get current tick
|
||
|
prevTick = lastTick;
|
||
|
SymbolInfoTick(_Symbol,lastTick);
|
||
|
|
||
|
// range calculation
|
||
|
if(lastTick.time >= range.start_time && lastTick.time < range.end_time){
|
||
|
// set flag
|
||
|
range.f_entry = true;
|
||
|
// new high
|
||
|
if(lastTick.ask > range.high){
|
||
|
range.high = lastTick.ask;
|
||
|
DrawObjects();
|
||
|
}
|
||
|
// new low
|
||
|
if(lastTick.bid < range.low){
|
||
|
range.low = lastTick.bid;
|
||
|
DrawObjects();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// close positions
|
||
|
if(InpRangeClose>=0 && lastTick.time>=range.close_time){
|
||
|
if(!ClosePostions()) {return;}
|
||
|
}
|
||
|
|
||
|
// calculate new range if ...
|
||
|
if((( InpRangeClose>=0 && lastTick.time>=range.close_time) // close time reached
|
||
|
|| ( range.f_high_breakout && range.f_low_breakout) // both breakout flags are true
|
||
|
|| range.end_time == 0 // range not calculate yet
|
||
|
|| (range.end_time != 0 && lastTick.time>range.end_time && !range.f_entry)) // there was a range calculated, but no tick inside
|
||
|
&& countOpenPosition()== 0) {
|
||
|
|
||
|
CalculateRange();
|
||
|
}
|
||
|
|
||
|
// check for breakouts
|
||
|
CheckBreakouts();
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| customer function below |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
// check user inputs
|
||
|
bool CheckInputs(){
|
||
|
|
||
|
if(InpMagicNumber <= 0){
|
||
|
Alert("Magicnumber <= 0");
|
||
|
return false;
|
||
|
}
|
||
|
if(InpLotMode == LOT_MODE_FIXED && (InpLots <= 0 || InpLots > 10)){
|
||
|
Alert("Lots <= 0 or > 10");
|
||
|
return false;
|
||
|
}
|
||
|
if(InpLotMode == LOT_MODE_MONEY && (InpLots <= 0 || InpLots > 1000)){
|
||
|
Alert("Lots by money <= 0 or > 1000 USD");
|
||
|
return false;
|
||
|
}
|
||
|
if(InpLotMode == LOT_MODE_PCT_ACCOUNT && (InpLots <= 0 || InpLots > 9)){
|
||
|
Alert("Lots by account % < 0% or < 5%");
|
||
|
return false;
|
||
|
}
|
||
|
if((InpLotMode == LOT_MODE_MONEY || InpLotMode==LOT_MODE_PCT_ACCOUNT) && (InpStopLoss==0)){
|
||
|
Alert("Selected lot mode needs a stop loss!! you forgot to set the amount in stoploss!!");
|
||
|
return false;
|
||
|
}
|
||
|
if(InpStopLoss<0 || InpStopLoss>1000){
|
||
|
Alert("stoploss error , stoploss = " , InpStopLoss);
|
||
|
return false;
|
||
|
}
|
||
|
if(InpTakeProfit<0 || InpTakeProfit>1000){
|
||
|
Alert("InpTakeProfit error , TakeProfit = " , InpTakeProfit);
|
||
|
return false;
|
||
|
}
|
||
|
if(InpRangeClose<0 && InpStopLoss==0 ){
|
||
|
Alert("Please be alert due to the stoploss or closing time is off!! the orders will never close!!");
|
||
|
return false;
|
||
|
}
|
||
|
if(InpRangeStart < 0 || InpRangeStart >= 1440){
|
||
|
Alert("RangeStart Error " , InpRangeStart);
|
||
|
return false;
|
||
|
}
|
||
|
if(InpRangeDuration <= 0 || InpRangeDuration >= 1440){
|
||
|
Alert("InpRangeDuration Error " , InpRangeDuration);
|
||
|
return false;
|
||
|
}
|
||
|
if( InpRangeClose >= 1440 || InpRangeStart + InpRangeDuration == InpRangeClose){
|
||
|
Alert("InpRangeClose Error " , InpRangeClose);
|
||
|
return false;
|
||
|
}
|
||
|
if(InpMonday+InpTuesday+InpWednesday+InpThursday+InpFriday==0){
|
||
|
Alert("Range is prohibited on all days of the week!!");
|
||
|
return false;
|
||
|
}
|
||
|
// Calculated new range if inputs changed
|
||
|
if(_UninitReason==REASON_PARAMETERS){
|
||
|
CalculateRange();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// calculate a new range
|
||
|
void CalculateRange(){
|
||
|
// reset range variable
|
||
|
range.start_time = 0;
|
||
|
range.end_time = 0;
|
||
|
range.close_time = 0;
|
||
|
range.high = 0.0;
|
||
|
range.low = 99999;
|
||
|
range.f_entry = false;
|
||
|
range.f_high_breakout = false;
|
||
|
range.f_low_breakout = false;
|
||
|
|
||
|
|
||
|
// calculate range start time
|
||
|
int time_cycle = 86400; //second for 1day
|
||
|
range.start_time = (lastTick.time - (lastTick.time % time_cycle)) + InpRangeStart*60; //to make sure the start time is the first second of the day
|
||
|
for( int i=0; i<8; i++){
|
||
|
MqlDateTime tmp;
|
||
|
TimeToStruct(range.start_time,tmp);
|
||
|
int dow = tmp.day_of_week; //day of the week
|
||
|
//to calculate the start time depend on week of the day which turn on
|
||
|
if(lastTick.time>=range.start_time ||
|
||
|
(dow==1 && !InpMonday) || (dow==2 && !InpTuesday) || (dow==3 && !InpWednesday)||
|
||
|
(dow==4 && !InpThursday) || (dow==5 && !InpFriday) || (dow==6 && !InpSaturday)||
|
||
|
(dow==0 && !InpSunday))
|
||
|
|
||
|
{
|
||
|
range.start_time += time_cycle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// calculate range end time
|
||
|
range.end_time = range.start_time + InpRangeDuration*60;
|
||
|
for(int i=0; i<2; i++){
|
||
|
MqlDateTime tmp;
|
||
|
TimeToStruct(range.end_time,tmp);
|
||
|
int dow = tmp.day_of_week;
|
||
|
if(dow==6 || dow==0){
|
||
|
range.end_time += time_cycle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// calculate range close
|
||
|
if(InpRangeClose>=0){
|
||
|
range.close_time = (range.end_time - (range.end_time % time_cycle)) + InpRangeClose*60; //to make sure the start time is the first second of the day
|
||
|
for( int i=0; i<3; i++){
|
||
|
MqlDateTime tmp;
|
||
|
TimeToStruct(range.close_time,tmp);
|
||
|
int dow = tmp.day_of_week; //day of the week
|
||
|
if(range.close_time<=range.end_time || dow==6 || dow==0){ // dow==6(Sat) ==7(Sun)
|
||
|
range.close_time += time_cycle;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// draw objects
|
||
|
DrawObjects();
|
||
|
}
|
||
|
|
||
|
|
||
|
int countOpenPosition(){
|
||
|
|
||
|
int counter = 0;
|
||
|
int total = PositionsTotal();
|
||
|
for(int i =total-1 ; i >=0 ; i--){
|
||
|
ulong ticket = PositionGetTicket(i);
|
||
|
if(ticket<=0){Print("Failed to get position ticket");return -1;}
|
||
|
if(!PositionSelectByTicket(ticket)){Print("Failed to select position by ticket"); return-1;}
|
||
|
ulong magicnumber;
|
||
|
if(!PositionGetInteger(POSITION_MAGIC,magicnumber)){Print("Failed to get position magicnumber"); return-1;}
|
||
|
if(InpMagicNumber==magicnumber){counter++;}
|
||
|
}
|
||
|
|
||
|
return counter;
|
||
|
|
||
|
}
|
||
|
|
||
|
void CheckBreakouts(){
|
||
|
|
||
|
// check if we are after the range end
|
||
|
if(lastTick.time >= range.end_time && range.end_time>0 && range.f_entry){
|
||
|
|
||
|
// check for high breakout
|
||
|
if(!range.f_high_breakout && lastTick.ask >= range.high){
|
||
|
range.f_high_breakout = true;
|
||
|
if(InpBreakoutMode==ONE_SIGNAL){range.f_low_breakout = true;}
|
||
|
|
||
|
// calculate stop loss and take profit for buy order
|
||
|
double sl = (InpStopLoss == 0)?0 :NormalizeDouble((lastTick.bid - ((range.high - range.low) * InpStopLoss * 0.01)),_Digits);
|
||
|
double tp = (InpTakeProfit == 0)?0 :NormalizeDouble((lastTick.ask + ((range.high - range.low) * InpTakeProfit * 0.01)),_Digits);
|
||
|
|
||
|
// calculate lots
|
||
|
double lots;
|
||
|
if(!CalculateLots(lastTick.bid-sl,lots)){return;}
|
||
|
|
||
|
|
||
|
// open buy position
|
||
|
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,lots,lastTick.ask,sl,tp,"Time range EA");
|
||
|
}
|
||
|
// check for low breakout
|
||
|
if(!range.f_low_breakout && lastTick.bid <= range.low){
|
||
|
range.f_low_breakout = true;
|
||
|
if(InpBreakoutMode==ONE_SIGNAL){range.f_high_breakout = true;}
|
||
|
|
||
|
// calculate stop loss and take profit for sell order
|
||
|
double sl = (InpStopLoss == 0)? 0 :NormalizeDouble((lastTick.bid + ((range.high - range.low) * InpStopLoss * 0.01)),_Digits);
|
||
|
double tp = (InpTakeProfit == 0)? 0 :NormalizeDouble((lastTick.ask - ((range.high - range.low) * InpTakeProfit * 0.01)),_Digits);
|
||
|
|
||
|
// calculate lots
|
||
|
double lots;
|
||
|
if(!CalculateLots(sl-lastTick.ask,lots)){return;}
|
||
|
|
||
|
|
||
|
// open sell position
|
||
|
trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lots,lastTick.bid,sl,tp,"Time range EA");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//calculate lots
|
||
|
bool CalculateLots(double slDistance, double &lots){
|
||
|
|
||
|
lots = 0.0;
|
||
|
if(InpLotMode==LOT_MODE_FIXED){
|
||
|
lots = InpLots;
|
||
|
}
|
||
|
else{
|
||
|
double tickSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
|
||
|
double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
|
||
|
double volumeStep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
|
||
|
|
||
|
double riskMoney = InpLotMode==LOT_MODE_MONEY ? InpLots : AccountInfoDouble(ACCOUNT_BALANCE) * InpLots * 0.01;
|
||
|
double moneyVolumeStep = (slDistance / tickSize) * tickValue * volumeStep;
|
||
|
|
||
|
lots = MathFloor(riskMoney/moneyVolumeStep) * volumeStep;
|
||
|
}
|
||
|
|
||
|
// check calculated lots
|
||
|
if(!CheckLots(lots)){return false;}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// check lots for min, max and step
|
||
|
bool CheckLots(double &lots){
|
||
|
|
||
|
double min = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
|
||
|
double max = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
|
||
|
double step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
|
||
|
|
||
|
|
||
|
if(lots < min){
|
||
|
Print("Lots size will be set to the minimum allowable volume!!");
|
||
|
lots = min;
|
||
|
return true;
|
||
|
}
|
||
|
if(lots>max){
|
||
|
Print("Lots size greater than the maximum allowable volume!! Lots: ", lots,"max : ", max);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
lots = (int)MathFloor(lots/step) * step;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
bool ClosePostions(){
|
||
|
Print("Closing all the position");
|
||
|
|
||
|
int total = PositionsTotal();
|
||
|
for (int i = total-1; i >=0 ; i--){
|
||
|
if(total != PositionsTotal()){total=PositionsTotal(); i=total; continue;}
|
||
|
ulong ticket = PositionGetTicket(i); //Select position
|
||
|
if(ticket<=0){Print("Failed to get position ticket"); return false;}
|
||
|
if(!PositionSelectByTicket(ticket)){Print("Failed to select position by ticket"); return false;}
|
||
|
long magicnumber;
|
||
|
if(!PositionGetInteger(POSITION_MAGIC,magicnumber)){Print("Failed to get position magicnumber"); return false;}
|
||
|
if(magicnumber == InpMagicNumber){
|
||
|
trade.PositionClose(ticket);
|
||
|
if(trade.ResultRetcode()!=TRADE_RETCODE_DONE){
|
||
|
Print("Failed to close position. Result: " + (string)trade.ResultRetcode() + ":" + trade.ResultRetcodeDescription() );
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void DrawObjects(){
|
||
|
// start
|
||
|
ObjectDelete(NULL,"range start"); // delete the old vline then make a new vline
|
||
|
if(range.start_time>0){
|
||
|
ObjectCreate(NULL,"range start",OBJ_VLINE,0,range.start_time,0);
|
||
|
ObjectSetString(NULL,"range start",OBJPROP_TOOLTIP,"start of the range \n"+TimeToString(range.start_time,TIME_DATE|TIME_MINUTES));
|
||
|
ObjectSetInteger(NULL,"range start",OBJPROP_COLOR,clrBlue);
|
||
|
ObjectSetInteger(NULL,"range start",OBJPROP_WIDTH,2);
|
||
|
ObjectSetInteger(NULL,"range start",OBJPROP_BACK,true);
|
||
|
}
|
||
|
//end time
|
||
|
ObjectDelete(NULL,"range end"); // delete the old vline then make a new vline
|
||
|
if(range.end_time>0){
|
||
|
ObjectCreate(NULL,"range end",OBJ_VLINE,0,range.end_time,0);
|
||
|
ObjectSetString(NULL,"range end",OBJPROP_TOOLTIP,"end of the range \n"+TimeToString(range.end_time,TIME_DATE|TIME_MINUTES));
|
||
|
ObjectSetInteger(NULL,"range end",OBJPROP_COLOR,clrBlue);
|
||
|
ObjectSetInteger(NULL,"range end",OBJPROP_WIDTH,2);
|
||
|
ObjectSetInteger(NULL,"range end",OBJPROP_BACK,true);
|
||
|
}
|
||
|
//close time
|
||
|
ObjectDelete(NULL,"range close"); // delete the old vline then make a new vline
|
||
|
if(range.close_time>0){
|
||
|
ObjectCreate(NULL,"range close",OBJ_VLINE,0,range.close_time,0);
|
||
|
ObjectSetString(NULL,"range close",OBJPROP_TOOLTIP,"close of the range \n"+TimeToString(range.close_time,TIME_DATE|TIME_MINUTES));
|
||
|
ObjectSetInteger(NULL,"range close",OBJPROP_COLOR,clrRed);
|
||
|
ObjectSetInteger(NULL,"range close",OBJPROP_WIDTH,2);
|
||
|
ObjectSetInteger(NULL,"range close",OBJPROP_BACK,true);
|
||
|
}
|
||
|
//high
|
||
|
ObjectsDeleteAll(NULL,"range high");
|
||
|
if(range.high>0){
|
||
|
// Trend line is a line from 1 time to another 1 time ** not a line in the whole window
|
||
|
ObjectCreate(NULL,"range high",OBJ_TREND,0,range.start_time,range.high,range.end_time,range.high);
|
||
|
ObjectSetString(NULL,"range high",OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
|
||
|
ObjectSetInteger(NULL,"range high",OBJPROP_COLOR,clrRed);
|
||
|
ObjectSetInteger(NULL,"range high",OBJPROP_WIDTH,2);
|
||
|
ObjectSetInteger(NULL,"range high",OBJPROP_BACK,true);
|
||
|
// another line from the end time to close time if rangeclose is off then draw the line all the way
|
||
|
ObjectCreate(NULL,"range high ",OBJ_TREND,0,range.end_time,range.high,InpRangeClose>=0 ? range.close_time : INT_MAX ,range.high);
|
||
|
ObjectSetString(NULL,"range high ",OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
|
||
|
ObjectSetInteger(NULL,"range high ",OBJPROP_COLOR,clrRed);
|
||
|
ObjectSetInteger(NULL,"range high ",OBJPROP_BACK,true);
|
||
|
ObjectSetInteger(NULL,"range high ",OBJPROP_STYLE,STYLE_DOT);
|
||
|
}
|
||
|
//low
|
||
|
ObjectsDeleteAll(NULL,"range low");
|
||
|
if(range.low<999999){
|
||
|
// Trend line is a line from 1 time to another 1 time ** not a line in the whole window
|
||
|
ObjectCreate(NULL,"range low",OBJ_TREND,0,range.start_time,range.low,range.end_time,range.low);
|
||
|
ObjectSetString(NULL,"range low",OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
|
||
|
ObjectSetInteger(NULL,"range low",OBJPROP_COLOR,clrBlue);
|
||
|
ObjectSetInteger(NULL,"range low",OBJPROP_WIDTH,2);
|
||
|
ObjectSetInteger(NULL,"range low",OBJPROP_BACK,true);
|
||
|
// another line from the end time to close time if rangeclose is off then draw the line all the way
|
||
|
ObjectCreate(NULL,"range low ",OBJ_TREND,0,range.end_time,range.low,InpRangeClose>=0 ? range.close_time : INT_MAX ,range.low);
|
||
|
ObjectSetString(NULL,"range low ",OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
|
||
|
ObjectSetInteger(NULL,"range low ",OBJPROP_COLOR,clrBlue);
|
||
|
ObjectSetInteger(NULL,"range low ",OBJPROP_BACK,true);
|
||
|
ObjectSetInteger(NULL,"range low ",OBJPROP_STYLE,STYLE_DOT);
|
||
|
}
|
||
|
|
||
|
//refresh chart
|
||
|
ChartRedraw();
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|