415 lines
13 KiB
Plaintext
415 lines
13 KiB
Plaintext
#property library
|
|
#include <Trade/Trade.mqh>
|
|
#include <MyLibs/TimeZones.mqh>
|
|
|
|
class RangeCalculator : public CObject{
|
|
|
|
protected:
|
|
TimeZones tz;
|
|
|
|
bool days_initlised;
|
|
bool range_initlised;
|
|
string symbol;
|
|
ENUM_TIMEFRAMES calc_period;
|
|
|
|
string inp_r_start_string;
|
|
int r_duration;
|
|
int r_expire;
|
|
int r_close;
|
|
string inp_timezone;
|
|
|
|
bool sun;
|
|
bool mon;
|
|
bool tue;
|
|
bool wed;
|
|
bool thu;
|
|
bool fri;
|
|
bool sat;
|
|
bool plot_range;
|
|
datetime start_time; // Start of the range
|
|
datetime end_time; // end of the range
|
|
datetime order_expire_time; // end of the range
|
|
datetime close_time; // Close time
|
|
double high; // high of the range
|
|
double low; // low of the range
|
|
double mid; // mid of the range
|
|
bool f_entry; // flag if we are inside of the range
|
|
bool f_high_breakout; // flag if a high breakout occurred
|
|
bool f_low_breakout; // flag if a low breakout occurred
|
|
bool above_last;
|
|
bool above_current;
|
|
bool below_last;
|
|
bool below_current;
|
|
|
|
// private functions
|
|
void update_objects();
|
|
void draw_objects();
|
|
void define_new_range();
|
|
bool convert_input_time_strings(string t1, string t2, string t3, string t4);
|
|
|
|
|
|
public:
|
|
void calculate_range();
|
|
|
|
double get_range_high();
|
|
double get_range_low();
|
|
double get_range_mid();
|
|
datetime get_range_start();
|
|
datetime get_range_end();
|
|
datetime get_order_expire_time();
|
|
datetime get_range_close();
|
|
bool get_range_high_breakout();
|
|
bool get_range_low_breakout();
|
|
bool initilise_range(string inp_symbol, ENUM_TIMEFRAMES _calc_period, string t0, string t1, string t2, string t3, string time_zone, bool plot_range_inp);
|
|
void range_days(bool _inp_sun, bool _inp_mon, bool _inp_tue, bool _inp_wed, bool _inp_thu, bool _inp_fri, bool _inp_sat);
|
|
|
|
};
|
|
|
|
void RangeCalculator::range_days(bool _inp_sun, bool _inp_mon, bool _inp_tue, bool _inp_wed, bool _inp_thu, bool _inp_fri, bool _inp_sat){
|
|
sun = _inp_sun;
|
|
mon = _inp_mon;
|
|
tue = _inp_tue;
|
|
wed = _inp_wed;
|
|
thu = _inp_thu;
|
|
fri = _inp_fri;
|
|
sat = _inp_sat;
|
|
days_initlised = true;
|
|
}
|
|
|
|
bool RangeCalculator::initilise_range(string inp_symbol, ENUM_TIMEFRAMES _calc_period, string t1, string t2, string t3, string t4, string time_zone, bool plot_range_inp){
|
|
inp_r_start_string = t1;
|
|
inp_timezone = time_zone;
|
|
symbol = inp_symbol;
|
|
calc_period =_calc_period;
|
|
plot_range = plot_range_inp;
|
|
start_time = 0;
|
|
end_time = 0;
|
|
close_time = 0;
|
|
high = 0;
|
|
low = DBL_MAX;
|
|
mid = 0;
|
|
f_entry = false;
|
|
f_high_breakout = false;
|
|
f_low_breakout = false;
|
|
above_last = false;
|
|
above_current= false;
|
|
below_last= false;
|
|
below_current= false;
|
|
if(!days_initlised){
|
|
sun = true;
|
|
mon = true;
|
|
tue = true;
|
|
wed = true;
|
|
thu = true;
|
|
fri = true;
|
|
sat = true;
|
|
}
|
|
range_initlised = true;
|
|
|
|
bool corret_inputs = convert_input_time_strings(t1, t2, t3, t4);
|
|
if(corret_inputs = false){
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool RangeCalculator::convert_input_time_strings(string t1, string t2, string t3, string t4){
|
|
|
|
datetime _t1 = StringToTime(t1);
|
|
datetime _t2 = StringToTime(t2);
|
|
datetime _t3 = StringToTime(t3);
|
|
datetime _t4 = StringToTime(t4);
|
|
|
|
|
|
if(_t1 > _t2){
|
|
_t2 = _t2 + PeriodSeconds(PERIOD_D1);
|
|
_t3 = _t3 + PeriodSeconds(PERIOD_D1);
|
|
_t4 = _t4 + PeriodSeconds(PERIOD_D1);
|
|
}
|
|
|
|
if(_t2 > _t3){
|
|
_t3 = _t3 + PeriodSeconds(PERIOD_D1);
|
|
_t4 = _t4 + PeriodSeconds(PERIOD_D1);
|
|
}
|
|
|
|
if(_t3 > _t4){
|
|
_t4 = _t4 + PeriodSeconds(PERIOD_D1);
|
|
}
|
|
|
|
r_duration = (int)(_t2 - _t1);
|
|
r_expire = (int)(_t3 - _t1);
|
|
r_close = (int)(_t4 - _t1);
|
|
|
|
if(_t4 - _t1 >= PeriodSeconds(PERIOD_D1)){
|
|
Alert("INCORRECT RANGE INPUTS!");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// high of the range
|
|
double RangeCalculator::get_range_high(){
|
|
return high;
|
|
};
|
|
|
|
// low of the range
|
|
double RangeCalculator::get_range_low(){
|
|
return low;
|
|
};
|
|
|
|
// mid of the range
|
|
double RangeCalculator::get_range_mid(){
|
|
return mid;
|
|
};
|
|
|
|
|
|
datetime RangeCalculator::get_range_start(){
|
|
return start_time;
|
|
};
|
|
|
|
datetime RangeCalculator::get_range_end(){
|
|
return end_time;
|
|
};
|
|
|
|
datetime RangeCalculator::get_order_expire_time(){
|
|
return order_expire_time;
|
|
};
|
|
|
|
datetime RangeCalculator::get_range_close(){
|
|
return close_time;
|
|
};
|
|
|
|
// flag if a high breakout occurred
|
|
bool RangeCalculator::get_range_high_breakout(){
|
|
return f_high_breakout;
|
|
};
|
|
|
|
// flag if a low breakout occurred
|
|
bool RangeCalculator::get_range_low_breakout(){
|
|
return f_low_breakout;
|
|
};
|
|
|
|
|
|
void RangeCalculator::calculate_range(){
|
|
|
|
f_high_breakout = false;
|
|
f_low_breakout = false;
|
|
|
|
double last_bar_high = iHigh(symbol, calc_period, 1); // shift 1 because 0 = live candle:
|
|
double last_bar_low = iLow(symbol, calc_period, 1); // shift 1 because 0 = live candle:
|
|
|
|
// range calculation
|
|
if(TimeCurrent() >= start_time && TimeCurrent() <= end_time){
|
|
|
|
// set flag
|
|
f_entry = true;
|
|
|
|
// new high
|
|
if(last_bar_high > high){
|
|
high = last_bar_high;
|
|
mid = (high + low)/2;
|
|
if(plot_range){
|
|
update_objects();
|
|
}
|
|
}
|
|
|
|
// new low
|
|
if(last_bar_low < low){
|
|
low = last_bar_low;
|
|
mid = (high + low)/2;
|
|
if(plot_range){
|
|
update_objects();
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate new reange if
|
|
if( (TimeCurrent() >= close_time) // close time reached
|
|
|| (end_time == 0) // range not calculated yet
|
|
|| (end_time !=0 && TimeCurrent() > end_time && !f_entry) // there was a range calculated but no tick inside.
|
|
){
|
|
define_new_range();
|
|
}
|
|
|
|
// check if we are after the range end
|
|
if(TimeCurrent() >= end_time && end_time > 0 && f_entry){
|
|
|
|
if(!f_high_breakout && last_bar_high >= high){
|
|
above_last = above_current;
|
|
above_current= true;
|
|
|
|
if(above_last==false && above_current == true){
|
|
f_high_breakout = true;
|
|
}
|
|
else(f_high_breakout = false);
|
|
}
|
|
|
|
if(!f_low_breakout && last_bar_low >= low){
|
|
below_last = below_current;
|
|
below_current = true;
|
|
if(below_last == false && below_current == true){
|
|
f_low_breakout = true;
|
|
}
|
|
else(f_low_breakout = false);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void RangeCalculator::define_new_range(){
|
|
|
|
// reset range vars
|
|
start_time = 0;
|
|
end_time = 0;
|
|
order_expire_time = 0;
|
|
close_time = 0;
|
|
high = 0;
|
|
low = INT_MAX;
|
|
mid = 0;
|
|
f_entry = false;
|
|
|
|
// calculate range start time:
|
|
datetime r_st = StringToTime(inp_r_start_string);
|
|
start_time = tz.timezone_conversions(inp_timezone, r_st, "Broker");
|
|
|
|
|
|
for(int i=0; i<8; i++){
|
|
|
|
MqlDateTime tmp;
|
|
TimeToStruct(start_time,tmp);
|
|
int dow = tmp.day_of_week;
|
|
|
|
if(TimeCurrent()>=start_time
|
|
|| (dow==0 && !sun)
|
|
|| (dow==1 && !mon)
|
|
|| (dow==2 && !tue)
|
|
|| (dow==3 && !wed)
|
|
|| (dow==4 && !thu)
|
|
|| (dow==5 && !fri)
|
|
|| (dow==6 && !sat)
|
|
){
|
|
start_time += PeriodSeconds(PERIOD_D1);
|
|
}
|
|
}
|
|
|
|
|
|
end_time = start_time + r_duration;
|
|
order_expire_time = start_time + r_expire;
|
|
close_time = start_time + r_close;
|
|
|
|
if(plot_range){
|
|
draw_objects();
|
|
}
|
|
}
|
|
|
|
void RangeCalculator::update_objects(){
|
|
|
|
string name = "Range Mid " + (string)start_time;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, mid);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, mid);
|
|
// ObjectSetString(NULL, name , OBJPROP_TOOLTIP, "Range Mid");
|
|
|
|
name = "Order expire " + (string)order_expire_time;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
|
|
name = "Range start " + (string)start_time;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
|
|
name = "Range end " + (string)end_time;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
|
|
datetime rct = r_close>=0 ? close_time : INT_MAX;
|
|
name = "Range close " + (string)rct;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
|
|
name = "Range High " + (string)rct;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, high);
|
|
|
|
name = "Range Low " + (string)rct;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, low);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
|
|
name = "range box "+ (string)start_time;
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name, OBJPROP_PRICE,1, low);
|
|
ObjectSetDouble(NULL, name +" ", OBJPROP_PRICE,0, high);
|
|
ObjectSetDouble(NULL, name +" ", OBJPROP_PRICE,1, low);
|
|
|
|
}
|
|
|
|
void RangeCalculator::draw_objects(){
|
|
|
|
datetime rct = r_close>=0 ? close_time : INT_MAX;
|
|
|
|
// Range mid line
|
|
string name = "Range Mid " + (string)start_time;;
|
|
ObjectCreate(NULL, name, OBJ_TREND, 0, start_time, mid, rct, mid);
|
|
ObjectSetString(NULL, name , OBJPROP_TOOLTIP, "Range Mid" + (string)mid);
|
|
ObjectSetInteger(NULL, name, OBJPROP_COLOR, clrGray);
|
|
ObjectSetInteger(NULL, name, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(NULL, name, OBJPROP_STYLE, STYLE_DOT);
|
|
|
|
// order lines
|
|
string name2 = "Order expire " + (string)order_expire_time;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, order_expire_time, low, order_expire_time, high);
|
|
ObjectSetString(NULL, name2, OBJPROP_TOOLTIP, "start of the range \n" + TimeToString(order_expire_time,TIME_DATE|TIME_MINUTES));
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, C'139,41,41');
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2,OBJPROP_BACK, true);
|
|
|
|
name2 = "Range start " + (string)start_time;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, start_time, low, start_time, high);
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2,OBJPROP_BACK, true);
|
|
|
|
name2 = "Range end " + (string)end_time;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, end_time, low, end_time, high);
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2,OBJPROP_BACK, true);
|
|
|
|
name2 = "Range close " + (string)rct;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, rct, low, rct, high);
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2,OBJPROP_BACK, true);
|
|
|
|
name2 = "Range High " + (string)rct;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, start_time, high, rct, high);
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2,OBJPROP_BACK, true);
|
|
|
|
name2 = "Range Low " + (string)rct;
|
|
ObjectCreate(NULL, name2, OBJ_TREND, 0, start_time, low, rct, low);
|
|
ObjectSetInteger(NULL, name2, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(NULL, name2 ,OBJPROP_BACK, true);
|
|
|
|
// Box
|
|
name = "range box " + (string)start_time;
|
|
ObjectCreate(NULL, name, OBJ_RECTANGLE, 0, start_time, high, end_time, low);
|
|
ObjectSetString(NULL,name,OBJPROP_TOOLTIP,"\n");
|
|
ObjectSetInteger(NULL, name,OBJPROP_COLOR, C'128,177,173');
|
|
ObjectSetInteger(NULL, name,OBJPROP_FILL, true);
|
|
ObjectSetInteger(NULL, name,OBJPROP_BACK, true);
|
|
|
|
ObjectCreate(NULL, name + " ", OBJ_RECTANGLE, 0, end_time, high, rct, low);
|
|
ObjectSetString(NULL, name+ " ", OBJPROP_TOOLTIP, "\n");
|
|
ObjectSetInteger(NULL, name + " ",OBJPROP_FILL, true);
|
|
ObjectSetInteger(NULL, name + " ",OBJPROP_COLOR, C'165,220,215' );
|
|
ObjectSetInteger(NULL, name + " ",OBJPROP_BACK, true);
|
|
|
|
ChartRedraw();
|
|
}
|
|
|
|
|