first push all - just my code
This commit is contained in:
@@ -0,0 +1,278 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/TimeZones.mqh>
|
||||||
|
#include <MyLibs/Myfunctions.mqh>
|
||||||
|
|
||||||
|
class CalculatePositionData : public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CTrade trade;
|
||||||
|
TimeZones tz;
|
||||||
|
CPositionInfo position;
|
||||||
|
MyFunctions mf;
|
||||||
|
|
||||||
|
bool check_lots(double &lots, string symbol);
|
||||||
|
bool normalise_price(double price, double &normalizedPrice, string symbol);
|
||||||
|
// double adjusted_point(string symbol);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
double calculate_stoploss(string symbol, double price, int order_side, string _sl_mode, double sl_var, ENUM_TIMEFRAMES atr_period);
|
||||||
|
double calculate_take_profit(string symbol, double price, double stoploss, int order_side, string mode_tp, double tp_var, ENUM_TIMEFRAMES atr_period);
|
||||||
|
double calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var);
|
||||||
|
double calculate_trading_cost(string symbol, ulong position_ticket);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
double CalculatePositionData::calculate_stoploss(string symbol, double price, int order_side, string mode_sl, double sl_var, ENUM_TIMEFRAMES atr_period){
|
||||||
|
// order_side int must be 1 for BUY or 2 for
|
||||||
|
|
||||||
|
double sl=0;
|
||||||
|
|
||||||
|
if(mode_sl=="NO_STOPLOSS"){
|
||||||
|
sl=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_sl=="SL_BREAKEVEN"){
|
||||||
|
// https://www.youtube.com/watch?v=idPulZ3_iR0
|
||||||
|
Alert("Not implemented yet yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_sl=="SL_FIXED_PIPS"){
|
||||||
|
// pips/poins = https://www.mql5.com/en/forum/187757
|
||||||
|
double adj_point = mf.adjusted_point(symbol);
|
||||||
|
|
||||||
|
if(order_side == 1){
|
||||||
|
sl = price - sl_var * adj_point;
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
sl = price + sl_var * adj_point;
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_sl=="SL_FIXED_PERCENT"){
|
||||||
|
if(order_side == 1){
|
||||||
|
sl = (-1.0 * sl_var * price / 100.00) + price;
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
sl = sl_var * price / 100.00 + price;
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_sl=="SL_ATR_MULTIPLE"){
|
||||||
|
|
||||||
|
int atr_handle = iATR(symbol,atr_period,14);
|
||||||
|
double atr[];
|
||||||
|
ArraySetAsSeries(atr,true);
|
||||||
|
CopyBuffer(atr_handle,MAIN_LINE,1,1,atr);
|
||||||
|
|
||||||
|
if(order_side == 1){
|
||||||
|
sl = price - (atr[0] * sl_var);
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
sl = price + (atr[0] * sl_var);
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_sl=="SL_SPECIFIED_VALUE"){
|
||||||
|
|
||||||
|
double adj_point = mf.adjusted_point(symbol);
|
||||||
|
|
||||||
|
if(order_side == 1){
|
||||||
|
|
||||||
|
double pip_50_sl = price - 10 * adj_point;
|
||||||
|
if(sl_var >= pip_50_sl){
|
||||||
|
sl = pip_50_sl;
|
||||||
|
}
|
||||||
|
else sl = sl_var;
|
||||||
|
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
double pip_50_sl = price + 10 * adj_point;
|
||||||
|
if(sl_var <= pip_50_sl){
|
||||||
|
sl = pip_50_sl;
|
||||||
|
}
|
||||||
|
else sl = sl_var;
|
||||||
|
|
||||||
|
sl = sl = sl_var;
|
||||||
|
if(!normalise_price(sl,sl,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CalculatePositionData::calculate_take_profit(string symbol, double price, double stoploss, int order_side, string mode_tp, double _tp_var, ENUM_TIMEFRAMES atr_period){
|
||||||
|
// order_side int must be 1 for BUY or 2 for SELL
|
||||||
|
|
||||||
|
double tp=0;
|
||||||
|
|
||||||
|
if(mode_tp=="NO_TAKE_PROFIT"){
|
||||||
|
tp=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_tp=="TP_FIXED_PIPS"){
|
||||||
|
|
||||||
|
double adj_point = mf.adjusted_point(symbol);
|
||||||
|
if(order_side == 1){
|
||||||
|
tp = price + _tp_var * adj_point;
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
tp = price - _tp_var * adj_point;
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_tp=="TP_FIXED_PERCENT"){
|
||||||
|
if(order_side == 1){
|
||||||
|
tp = _tp_var * price / 100.00 + price;
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
tp = (-1 * _tp_var * price / 100.00) + price;
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_tp=="TP_ATR_MULTIPLE"){
|
||||||
|
|
||||||
|
int atr_handle = iATR(symbol,atr_period,14);
|
||||||
|
double atr[];
|
||||||
|
ArraySetAsSeries(atr,true);
|
||||||
|
CopyBuffer(atr_handle,MAIN_LINE,1,1,atr);
|
||||||
|
|
||||||
|
if(order_side == 1){
|
||||||
|
tp = price + (atr[0] * _tp_var);
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
tp = price - (atr[0] * _tp_var);
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_tp=="TP_SL_MULTIPLE"){
|
||||||
|
if(order_side == 1){
|
||||||
|
double sl_size = price - stoploss;
|
||||||
|
tp = price + (_tp_var * sl_size);
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
double sl_size = stoploss - price;
|
||||||
|
tp = price - (_tp_var * sl_size);
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_tp=="TP_SPECIFIED_VALUE"){
|
||||||
|
|
||||||
|
if(_tp_var!=0){
|
||||||
|
double adj_point = mf.adjusted_point(symbol);
|
||||||
|
|
||||||
|
if(order_side == 1){
|
||||||
|
double pip_limit = price + 10 * adj_point;
|
||||||
|
if(_tp_var <= pip_limit){
|
||||||
|
tp = pip_limit;
|
||||||
|
}
|
||||||
|
else tp = _tp_var;
|
||||||
|
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
if(order_side == 2){
|
||||||
|
double pip_limit = price - 10 * adj_point;
|
||||||
|
if(_tp_var >= pip_limit){
|
||||||
|
tp = pip_limit;
|
||||||
|
}
|
||||||
|
else tp = _tp_var;
|
||||||
|
tp = tp = _tp_var;
|
||||||
|
if(!normalise_price(tp,tp,symbol)){return false;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double CalculatePositionData::calculate_lots(string symbol, double sl_distance, double price, string mode_lot, double lot_var){
|
||||||
|
|
||||||
|
double lots = 0;
|
||||||
|
double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
||||||
|
double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
||||||
|
double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||||
|
|
||||||
|
double account_value = fmin(fmin(AccountInfoDouble(ACCOUNT_EQUITY),AccountInfoDouble(ACCOUNT_BALANCE)),AccountInfoDouble(ACCOUNT_MARGIN_FREE));
|
||||||
|
double risk_money = account_value * lot_var / 100;
|
||||||
|
|
||||||
|
if(mode_lot=="LOT_MODE_FIXED"){
|
||||||
|
lots = lot_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_lot=="LOT_MODE_PCT_RISK"){
|
||||||
|
double money_lot_step = (sl_distance / tick_size) * tick_value * volume_step;
|
||||||
|
lots = MathFloor(risk_money/money_lot_step) * volume_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode_lot=="LOT_MODE_PCT_ACCOUNT"){
|
||||||
|
double money_lot_step = (price / tick_size) * tick_value * volume_step;
|
||||||
|
lots = MathFloor(risk_money/money_lot_step) * volume_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!check_lots(lots, symbol)){return false;}
|
||||||
|
return lots;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CalculatePositionData::check_lots(double &lots, string symbol){
|
||||||
|
|
||||||
|
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("Lot size will be set to minimum allowed volume");
|
||||||
|
lots = min;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lots>max){
|
||||||
|
Print("Lot size greater than maximum allowed volume. lots:",lots,"max:",max);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lots = (int)MathFloor(lots/step) * step;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CalculatePositionData::normalise_price(double price, double &normalizedPrice, string symbol){
|
||||||
|
double tickSize;
|
||||||
|
if(!SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE,tickSize)){
|
||||||
|
Print("Failed to get tick size");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||||
|
normalizedPrice = NormalizeDouble(MathRound(price/tickSize)*tickSize, symbol_digits);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CalculatePositionData::calculate_trading_cost(string symbol, ulong position_ticket){
|
||||||
|
|
||||||
|
position.SelectByTicket(position_ticket);
|
||||||
|
|
||||||
|
double swap = PositionGetDouble(POSITION_SWAP);
|
||||||
|
double commission = PositionGetDouble(POSITION_COMMISSION);
|
||||||
|
double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
||||||
|
double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
||||||
|
double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||||
|
double lots = PositionGetDouble(POSITION_VOLUME);
|
||||||
|
double trading_cost = -1 * ((commission + swap) / tick_value * tick_size / lots);
|
||||||
|
|
||||||
|
return trading_cost;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
|
||||||
|
enum CUSTOM_MAX_TYPE{
|
||||||
|
CM_WIN_LOSS_RATIO,
|
||||||
|
CM_WIN_PERCENT,
|
||||||
|
CM_WIN_PERCENT_200T
|
||||||
|
};
|
||||||
|
|
||||||
|
class CustomMax : public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double custom_criteria;
|
||||||
|
|
||||||
|
double CustomMax::win_loss_ratio();
|
||||||
|
double CustomMax::win_percent();
|
||||||
|
double CustomMax::win_percent_min_trades_200();
|
||||||
|
|
||||||
|
public:
|
||||||
|
double CustomMax::calculate_custom_criteria(CUSTOM_MAX_TYPE cm_type);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// CM_WIN_LOSS_RATIO,
|
||||||
|
// CM_WIN_PERCENT
|
||||||
|
double CustomMax::calculate_custom_criteria(CUSTOM_MAX_TYPE cm_type){
|
||||||
|
if(cm_type==CM_WIN_LOSS_RATIO){
|
||||||
|
custom_criteria = win_loss_ratio();
|
||||||
|
}
|
||||||
|
if(cm_type==CM_WIN_PERCENT){
|
||||||
|
custom_criteria = win_percent();
|
||||||
|
}
|
||||||
|
if(cm_type==CM_WIN_PERCENT_200T){
|
||||||
|
custom_criteria = win_percent_min_trades_200();
|
||||||
|
}
|
||||||
|
return custom_criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CustomMax::win_loss_ratio(){
|
||||||
|
double wins = TesterStatistics(STAT_PROFIT_TRADES);
|
||||||
|
double losses = TesterStatistics(STAT_LOSS_TRADES);
|
||||||
|
return wins/losses;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CustomMax::win_percent(){
|
||||||
|
double wins = TesterStatistics(STAT_PROFIT_TRADES);
|
||||||
|
double total_trades = TesterStatistics(STAT_TRADES);
|
||||||
|
return wins / total_trades * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CustomMax::win_percent_min_trades_200(){
|
||||||
|
double wins = TesterStatistics(STAT_PROFIT_TRADES);
|
||||||
|
double total_trades = TesterStatistics(STAT_TRADES);
|
||||||
|
|
||||||
|
if(total_trades<200){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return wins / total_trades * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,205 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/MyFunctions.mqh>
|
||||||
|
|
||||||
|
class DrawdownControl : public CObject {
|
||||||
|
protected:
|
||||||
|
CTrade trade;
|
||||||
|
MyFunctions mf;
|
||||||
|
|
||||||
|
string data_file;
|
||||||
|
double daily_max_dd_per;
|
||||||
|
string daily_reset_time;
|
||||||
|
bool print_statments;
|
||||||
|
|
||||||
|
double acc_max_dd_per;
|
||||||
|
double equaty_control_high;
|
||||||
|
double equaty_control_low;
|
||||||
|
|
||||||
|
|
||||||
|
double daily_equity_start;
|
||||||
|
double daily_max_dd_target;
|
||||||
|
bool daily_dd_limit_reached;
|
||||||
|
|
||||||
|
bool write_global_var_data();
|
||||||
|
bool print_messages();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void init_dd_control(string inp_data_file, double inp_acc_max_dd_per, double inp_daily_max_dd_per, string inp_daily_reset_time, bool inp_print_statments = true);
|
||||||
|
bool determine_daily_dd_limit();
|
||||||
|
double lot_correction_factor(double acc_equity_start, double min_lot_factor, double max_lot_factor, bool dynm_lot_factor=false, double dlf_trail_per=20);
|
||||||
|
double lot_correction_dynamic(double acc_dd_percent, double min_lot_factor, double max_lot_factor);
|
||||||
|
};
|
||||||
|
|
||||||
|
void DrawdownControl::init_dd_control(string inp_data_file, double inp_acc_max_dd_per, double inp_daily_max_dd_per, string inp_daily_reset_time, bool inp_print_statments = true) {
|
||||||
|
|
||||||
|
data_file = inp_data_file;
|
||||||
|
acc_max_dd_per = inp_acc_max_dd_per;
|
||||||
|
daily_max_dd_per = inp_daily_max_dd_per;
|
||||||
|
daily_reset_time = inp_daily_reset_time;
|
||||||
|
print_statments = inp_print_statments;
|
||||||
|
|
||||||
|
// If no data file exisits, create one and set global vairiables:
|
||||||
|
if(FileIsExist(data_file) == false) {
|
||||||
|
daily_equity_start = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||||
|
daily_max_dd_target = daily_equity_start - (daily_equity_start * (daily_max_dd_per / 100));
|
||||||
|
daily_dd_limit_reached = false;
|
||||||
|
equaty_control_high = 9999999;
|
||||||
|
equaty_control_low = 0;
|
||||||
|
write_global_var_data();
|
||||||
|
}
|
||||||
|
// If file exisits read file:
|
||||||
|
if(FileIsExist(data_file) == true) {
|
||||||
|
|
||||||
|
int file_handle = FileOpen(data_file, FILE_READ | FILE_ANSI | FILE_TXT);
|
||||||
|
if(file_handle == INVALID_HANDLE) {
|
||||||
|
Print("Error opening file: ", data_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If data file is older than 24h 10min create a new file and reset global vars:
|
||||||
|
long modifided_date = FileGetInteger(file_handle, FILE_MODIFY_DATE);
|
||||||
|
long time_delta = ((long)TimeCurrent() - modifided_date) / 60;
|
||||||
|
|
||||||
|
if(time_delta >= 1450) {
|
||||||
|
daily_equity_start = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||||
|
daily_max_dd_target = daily_equity_start - (daily_equity_start * (daily_max_dd_per / 100));
|
||||||
|
daily_dd_limit_reached = false;
|
||||||
|
equaty_control_high = equaty_control_high;
|
||||||
|
equaty_control_low = equaty_control_low;
|
||||||
|
write_global_var_data();
|
||||||
|
Print(data_file, " is older than 24h and 10min; global vars reset!");
|
||||||
|
}
|
||||||
|
// If data file is younger than 24h+10 min read data and set global vars:
|
||||||
|
else {
|
||||||
|
daily_equity_start = (double)FileReadString(file_handle, 0);
|
||||||
|
daily_max_dd_target = (double)FileReadString(file_handle, 1);
|
||||||
|
daily_dd_limit_reached = FileReadBool(file_handle);
|
||||||
|
equaty_control_high = (double)FileReadString(file_handle, 3);
|
||||||
|
equaty_control_low = (double)FileReadString(file_handle, 4);;
|
||||||
|
}
|
||||||
|
FileClose(file_handle);
|
||||||
|
}
|
||||||
|
print_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DrawdownControl::determine_daily_dd_limit() {
|
||||||
|
|
||||||
|
// Reset max equity at the start of each day:
|
||||||
|
string ct = TimeToString(TimeCurrent(), TIME_MINUTES);
|
||||||
|
if(ct == daily_reset_time) {
|
||||||
|
daily_equity_start = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||||
|
daily_max_dd_target = (daily_equity_start - (daily_equity_start * (daily_max_dd_per / 100)));
|
||||||
|
daily_dd_limit_reached = false;
|
||||||
|
write_global_var_data();
|
||||||
|
print_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If in drawdown close all positions and delete orders
|
||||||
|
if(daily_dd_limit_reached || AccountInfoDouble(ACCOUNT_EQUITY) <= daily_max_dd_target) {
|
||||||
|
|
||||||
|
if(daily_dd_limit_reached == false) {
|
||||||
|
daily_dd_limit_reached = true;
|
||||||
|
write_global_var_data();
|
||||||
|
print_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = PositionsTotal() - 1; i >= 0; i--) {
|
||||||
|
ulong ticket = PositionGetTicket(i);
|
||||||
|
trade.PositionClose(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = OrdersTotal() - 1; i >= 0; i--) {
|
||||||
|
ulong ticket = OrderGetTicket(i);
|
||||||
|
trade.OrderDelete(ticket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return daily_dd_limit_reached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduces lot size as account apporchaes max allowed drawdown limit.
|
||||||
|
double DrawdownControl::lot_correction_factor(double acc_equity_start, double min_lot_factor, double max_lot_factor, bool dynm_lot_factor=false, double dlf_trail_per=20) {
|
||||||
|
|
||||||
|
double account_value = fmin(AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE));
|
||||||
|
double lot_factor;
|
||||||
|
|
||||||
|
// Interpolate to find lot factor between given min and max values.
|
||||||
|
if (account_value < acc_equity_start){
|
||||||
|
|
||||||
|
double acc_equity_min = acc_equity_start - (acc_equity_start * (acc_max_dd_per / 100));
|
||||||
|
double y1 = min_lot_factor;
|
||||||
|
double y2 = max_lot_factor;
|
||||||
|
double x1 = acc_equity_min;
|
||||||
|
double x = account_value;
|
||||||
|
double x2 = acc_equity_start;
|
||||||
|
lot_factor = y1 + (x - x1) * ((y2 - y1) / (x2 - x1));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(account_value >= acc_equity_start) {
|
||||||
|
|
||||||
|
if(dynm_lot_factor=true){
|
||||||
|
lot_factor = lot_correction_dynamic(dlf_trail_per, min_lot_factor, max_lot_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
lot_factor = max_lot_factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_lot_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double DrawdownControl::lot_correction_dynamic(double acc_dd_percent, double min_lot_factor, double max_lot_factor) {
|
||||||
|
|
||||||
|
double account_value = fmin(AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE));
|
||||||
|
double trail_point = account_value - (account_value * (acc_dd_percent / 100));
|
||||||
|
|
||||||
|
if(equaty_control_low < trail_point){
|
||||||
|
equaty_control_low = trail_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(equaty_control_high < account_value){
|
||||||
|
equaty_control_high = account_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(account_value < equaty_control_low){
|
||||||
|
equaty_control_low = account_value;
|
||||||
|
equaty_control_high = account_value + (account_value * (acc_dd_percent / 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
// back-up to file every hour:
|
||||||
|
if(mf.is_new_bar(_Symbol, PERIOD_H1) == true){
|
||||||
|
write_global_var_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linear interpolation:
|
||||||
|
double y1 = min_lot_factor;
|
||||||
|
double y2 = max_lot_factor;
|
||||||
|
double x1 = equaty_control_low;
|
||||||
|
double x = account_value;
|
||||||
|
double x2 = equaty_control_high;
|
||||||
|
|
||||||
|
double y = y1 + (x - x1) * ((y2 - y1) / (x2 - x1));
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DrawdownControl::write_global_var_data() {
|
||||||
|
int file_handle = FileOpen(data_file, FILE_WRITE | FILE_ANSI | FILE_TXT);
|
||||||
|
FileWrite(file_handle, daily_equity_start);
|
||||||
|
FileWrite(file_handle, daily_max_dd_target);
|
||||||
|
FileWrite(file_handle, daily_dd_limit_reached);
|
||||||
|
FileClose(file_handle);
|
||||||
|
Print(data_file, " written");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DrawdownControl::print_messages() {
|
||||||
|
if(print_statments == true) {
|
||||||
|
Print("TimeCurrent(): ", TimeToString(TimeCurrent()));
|
||||||
|
Print("Daily Equity Start: ", (int)daily_equity_start);
|
||||||
|
Print("Current Equity: ", (int)AccountInfoDouble(ACCOUNT_EQUITY));
|
||||||
|
Print("Daily Drawdown Limit: ", (int)daily_max_dd_target, " (", daily_max_dd_per, "%) of DES");
|
||||||
|
Print("Daily Drawdown Limit Hit: ", daily_dd_limit_reached);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#property library
|
||||||
|
|
||||||
|
enum LOT_MODE{
|
||||||
|
LOT_MODE_FIXED, // Fixed Lot Size
|
||||||
|
LOT_MODE_PCT_ACCOUNT, // Percent of Account (fixed)
|
||||||
|
LOT_MODE_PCT_RISK // Percent of Account at Risk (from SL)
|
||||||
|
};
|
||||||
|
enum SL_MODE{
|
||||||
|
SL_FIXED_PIPS, // Fixed Pips
|
||||||
|
SL_FIXED_PERCENT, // Fixed Percent
|
||||||
|
SL_ATR_MULTIPLE, // ATR Multiple
|
||||||
|
SL_SPECIFIED_VALUE, // Bespoke calculation in code
|
||||||
|
NO_STOPLOSS, // No Stop-loss
|
||||||
|
SL_BREAKEVEN, // Breakeven
|
||||||
|
};
|
||||||
|
enum TP_MODE{
|
||||||
|
TP_FIXED_PIPS, // Fixed Pips
|
||||||
|
TP_FIXED_PERCENT, // Fixed Percent
|
||||||
|
TP_ATR_MULTIPLE, // ATR Multiple
|
||||||
|
TP_SL_MULTIPLE, // Multiple of Risk (from sl)
|
||||||
|
TP_SPECIFIED_VALUE, // Bespoke calculation in code
|
||||||
|
NO_TAKE_PROFIT, // No Take-Profit
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TIME_ZONES{
|
||||||
|
NY, // New York
|
||||||
|
Lon, // London
|
||||||
|
Ffm, // Frankfurt
|
||||||
|
Syd, // Sidney
|
||||||
|
Mosc, // Moscow
|
||||||
|
Tok, // Tokyo - no DST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MULTI_SYM_MODE{
|
||||||
|
MULTI_SYM_CHART, // Chart Symbol only
|
||||||
|
MULTI_SYM_FX_B5, // FX Benchmark 5
|
||||||
|
MULTI_SYM_FX_28 // FX 28 Majors
|
||||||
|
};
|
||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/TradingWindow.mqh>
|
||||||
|
|
||||||
|
class MyFunctions : public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CTrade trade;
|
||||||
|
TradingWindow tw;
|
||||||
|
datetime previousTime;
|
||||||
|
datetime bar_open_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_new_daily_bar(string symbol, datetime start_time);
|
||||||
|
double period_high(string symbol, int periods, int shift);
|
||||||
|
double period_low(string symbol, int periods, int shift);
|
||||||
|
void draw_line(double value, string name,color clr);
|
||||||
|
bool check_indicator_handles(int &indicator_handles[]);
|
||||||
|
double adjusted_point(string symbol);
|
||||||
|
double get_bid_ask_price(string symbol, int price_side);
|
||||||
|
bool is_new_bar(string symbol, ENUM_TIMEFRAMES time_frame);
|
||||||
|
bool trade_window(string t1, string t2, string time_zone, bool plot_range_inp=true);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MyFunctions::trade_window(string t1, string t2, string time_zone="Broker", bool plot_range_inp=true){
|
||||||
|
bool in_window = tw.define_window(t1, t2, time_zone, plot_range_inp);
|
||||||
|
return in_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(!mf.is_new_daily_bar(symbol, PERIOD_M1)){return;}
|
||||||
|
bool MyFunctions::is_new_bar(string symbol, ENUM_TIMEFRAMES time_frame){
|
||||||
|
bar_open_time = iTime(symbol,time_frame,0);
|
||||||
|
if(previousTime!=bar_open_time){
|
||||||
|
previousTime=bar_open_time;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. if(!mf.is_new_daily_bar(symbol, StringToTime("00:06"))){return;}
|
||||||
|
bool MyFunctions::is_new_daily_bar(string symbol, datetime start_time){
|
||||||
|
// https://www.youtube.com/watch?v=9BdnTcGrlUM (m-25:00)
|
||||||
|
bar_open_time = iTime(symbol,PERIOD_D1,0);
|
||||||
|
if(previousTime!=bar_open_time && TimeCurrent() > start_time){
|
||||||
|
previousTime=bar_open_time;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double MyFunctions::period_high(string symbol, int periods, int shift){
|
||||||
|
|
||||||
|
double highs[];
|
||||||
|
ArraySetAsSeries(highs,true);
|
||||||
|
CopyHigh(symbol,PERIOD_CURRENT,1,periods+1,highs);
|
||||||
|
|
||||||
|
double high = 0;
|
||||||
|
high=highs[shift];
|
||||||
|
for(int i=shift; i<shift+periods; i++){
|
||||||
|
if(high<highs[i]){
|
||||||
|
high=highs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(high);
|
||||||
|
}
|
||||||
|
|
||||||
|
double MyFunctions::period_low(string symbol, int periods, int shift){
|
||||||
|
|
||||||
|
double lows[];
|
||||||
|
ArraySetAsSeries(lows,true);
|
||||||
|
CopyLow(symbol,PERIOD_CURRENT,1,periods+1,lows);
|
||||||
|
|
||||||
|
double low = 0;
|
||||||
|
low=lows[shift];
|
||||||
|
for(int i=shift; i<shift+periods; i++){
|
||||||
|
if(low>lows[i]){
|
||||||
|
low=lows[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(low);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFunctions::draw_line(double value, string name,color clr){
|
||||||
|
// EG:
|
||||||
|
// ArrayResize(bar,1000);
|
||||||
|
// ArraySetAsSeries(bar, true);
|
||||||
|
// CopyRates(symbol,PERIOD_CURRENT,1,1000,bar);
|
||||||
|
// double close = bar[0].close;
|
||||||
|
// draw_line(close,"CLOSE",clrBlue);
|
||||||
|
|
||||||
|
if(ObjectFind(0,name)<0){
|
||||||
|
ResetLastError();
|
||||||
|
|
||||||
|
if(!ObjectCreate(0,name,OBJ_HLINE,0,0,value)){
|
||||||
|
Print(__FUNCTION__,": failed to create a horizontal line! Error code = ",GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
|
||||||
|
ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
|
||||||
|
ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetLastError();
|
||||||
|
|
||||||
|
if(!ObjectMove(0,name,0,0,value)){
|
||||||
|
Print(__FUNCTION__,": failed to move the horizontal line! Error code = ",GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartRedraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyFunctions::check_indicator_handles(int &indicator_handles[]){
|
||||||
|
// TODO check if working before implementaion:
|
||||||
|
// e.g. call via:
|
||||||
|
// int indicator_handles[] = {handle1, handle2, handle..};
|
||||||
|
// check_indicator_handles(indicator_handles);
|
||||||
|
|
||||||
|
for(int i =0; i < ArraySize(indicator_handles); i++){
|
||||||
|
|
||||||
|
if(indicator_handles[i] == INVALID_HANDLE){
|
||||||
|
Alert("Failed to create handle"); return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double MyFunctions::adjusted_point(string symbol){
|
||||||
|
|
||||||
|
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||||
|
int digits_adjust=1;
|
||||||
|
if(symbol_digits==3 || symbol_digits==5){
|
||||||
|
digits_adjust=10;
|
||||||
|
}
|
||||||
|
|
||||||
|
double symbol_point_val = SymbolInfoDouble(symbol,SYMBOL_POINT);
|
||||||
|
double m_adjusted_point;
|
||||||
|
m_adjusted_point = symbol_point_val * digits_adjust;
|
||||||
|
|
||||||
|
return m_adjusted_point;
|
||||||
|
|
||||||
|
}
|
||||||
|
// price side - 1 for the ask price and 2 for the bid price
|
||||||
|
double MyFunctions::get_bid_ask_price(string symbol, int price_side){
|
||||||
|
|
||||||
|
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||||
|
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||||
|
|
||||||
|
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
|
||||||
|
ask = NormalizeDouble(ask, symbol_digits);
|
||||||
|
|
||||||
|
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
|
||||||
|
bid = NormalizeDouble(bid, symbol_digits);
|
||||||
|
|
||||||
|
double price = 0;
|
||||||
|
|
||||||
|
if(price_side==1){
|
||||||
|
price = ask;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(price_side==2){
|
||||||
|
price = bid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return price;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/TimeZones.mqh>
|
||||||
|
#include <MyLibs/CalculatePositionData.mqh>
|
||||||
|
#include <Trade/PositionInfo.mqh>
|
||||||
|
#include <Trade/OrderInfo.mqh>
|
||||||
|
|
||||||
|
class OrderManagment : public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CTrade trade;
|
||||||
|
TimeZones tz;
|
||||||
|
CalculatePositionData cpd;
|
||||||
|
CPositionInfo m_position;
|
||||||
|
COrderInfo m_order;
|
||||||
|
|
||||||
|
double stop_loss;
|
||||||
|
double take_profit;
|
||||||
|
ulong posTicket;
|
||||||
|
int time_difference;
|
||||||
|
int total_open_buy_orders;
|
||||||
|
int total_open_sell_orders;
|
||||||
|
double current_price;
|
||||||
|
int total_pos;
|
||||||
|
long position_open_time;
|
||||||
|
long first_allowed_close_time;
|
||||||
|
datetime current_bar_open_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number);
|
||||||
|
bool open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number);
|
||||||
|
bool open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number);
|
||||||
|
bool open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number);
|
||||||
|
bool close_buy_orders(string symbol, bool buy_out, int close_bars, ENUM_TIMEFRAMES close_bar_period, long magic_number);
|
||||||
|
bool close_sell_orders(string symbol, bool sell_out, int close_bars, ENUM_TIMEFRAMES close_bar_period, long magic_number);
|
||||||
|
bool first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long magic_number);
|
||||||
|
bool daily_timed_exit(string symbol, datetime exit_time, int delay_days, long magic_number);
|
||||||
|
bool daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, string tz, int delay_days, long magic_number);
|
||||||
|
int count_all_positions(string symbol, long magic_number);
|
||||||
|
int count_pending_orders(string symbol, ENUM_ORDER_TYPE pendingType, long magic);
|
||||||
|
double sl_specified_value_switch(string _sl_mode, double _inp_sl_var, double value);
|
||||||
|
double tp_specified_value_switch(string _tp_mode, double _inp_tp_var, double value);
|
||||||
|
int count_open_positions(string symbol,int order_side, long magic_number);
|
||||||
|
void break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool OrderManagment::open_buy_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var, long magic_number){
|
||||||
|
|
||||||
|
if(condition == true){
|
||||||
|
current_price = SymbolInfoDouble(symbol, SYMBOL_ASK); // ask for buy side
|
||||||
|
|
||||||
|
total_open_buy_orders = count_open_positions(symbol, 1, magic_number);
|
||||||
|
if(total_open_buy_orders == 0){
|
||||||
|
|
||||||
|
stop_loss = cpd.calculate_stoploss(symbol, current_price, 1, _sl_mode, sl_var, atr_period);
|
||||||
|
take_profit = cpd.calculate_take_profit(symbol, current_price, stop_loss, 1, _tp_mode, tp_var, atr_period);
|
||||||
|
|
||||||
|
double sl_distance = current_price-stop_loss;
|
||||||
|
double lots = cpd.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
|
||||||
|
|
||||||
|
trade.SetExpertMagicNumber(magic_number);
|
||||||
|
string comment = "Magic Number: " + IntegerToString(magic_number);
|
||||||
|
trade.PositionOpen(symbol,ORDER_TYPE_BUY,lots,current_price,stop_loss,take_profit,comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OrderManagment::open_sell_orders(string symbol, bool condition, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number){
|
||||||
|
|
||||||
|
if(condition == true){
|
||||||
|
|
||||||
|
// if(!SymbolInfoTick(symbol,currentTick)){Print("FAILED TO GET TICK:", symbol);return false;}
|
||||||
|
current_price = SymbolInfoDouble(symbol, SYMBOL_BID); // bid for sell side
|
||||||
|
|
||||||
|
total_open_sell_orders = count_open_positions(symbol, 2, magic_number);
|
||||||
|
if(total_open_sell_orders == 0){
|
||||||
|
|
||||||
|
stop_loss = cpd.calculate_stoploss(symbol, current_price, 2, _sl_mode, sl_var, atr_period);
|
||||||
|
take_profit = cpd.calculate_take_profit(symbol, current_price, stop_loss, 2, _tp_mode, tp_var, atr_period);
|
||||||
|
|
||||||
|
double sl_distance = stop_loss-current_price;
|
||||||
|
double lots = cpd.calculate_lots(symbol, sl_distance, current_price, _lot_mode, lot_var);
|
||||||
|
|
||||||
|
trade.SetExpertMagicNumber(magic_number);
|
||||||
|
string comment = "Magic Number: " + IntegerToString(magic_number);
|
||||||
|
trade.PositionOpen(symbol,ORDER_TYPE_SELL,lots,current_price,stop_loss,take_profit,comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some usfull comment here
|
||||||
|
bool OrderManagment::open_buy_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var,string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number){
|
||||||
|
|
||||||
|
if(condition == true){
|
||||||
|
|
||||||
|
total_open_buy_orders = count_open_positions(symbol, 1, magic_number);
|
||||||
|
if(total_open_buy_orders == 0){
|
||||||
|
|
||||||
|
stop_loss = cpd.calculate_stoploss(symbol, entry_price, 1, _sl_mode, sl_var, atr_period);
|
||||||
|
take_profit = cpd.calculate_take_profit(symbol, entry_price, stop_loss, 1, _tp_mode, tp_var, atr_period);
|
||||||
|
|
||||||
|
double sl_distance = entry_price-stop_loss;
|
||||||
|
double lots = cpd.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
|
||||||
|
|
||||||
|
trade.SetExpertMagicNumber(magic_number);
|
||||||
|
string comment = "Magic Number: " + IntegerToString(magic_number);
|
||||||
|
trade.BuyStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OrderManagment::open_sell_stop_order(string symbol, bool condition, double entry_price, datetime experation, ENUM_TIMEFRAMES atr_period, string _sl_mode, double sl_var, string _tp_mode, double tp_var, string _lot_mode, double lot_var,long magic_number){
|
||||||
|
|
||||||
|
if(condition == true){
|
||||||
|
|
||||||
|
total_open_sell_orders = count_open_positions(symbol, 2, magic_number);
|
||||||
|
if(total_open_sell_orders == 0){
|
||||||
|
|
||||||
|
stop_loss = cpd.calculate_stoploss(symbol, entry_price, 2, _sl_mode, sl_var, atr_period);
|
||||||
|
take_profit = cpd.calculate_take_profit(symbol, entry_price, stop_loss, 2, _tp_mode, tp_var, atr_period);
|
||||||
|
|
||||||
|
double sl_distance = stop_loss-entry_price;
|
||||||
|
double lots = cpd.calculate_lots(symbol, sl_distance, entry_price, _lot_mode, lot_var);
|
||||||
|
|
||||||
|
trade.SetExpertMagicNumber(magic_number);
|
||||||
|
string comment = "Magic Number: " + IntegerToString(magic_number);
|
||||||
|
trade.SellStop(lots, entry_price, symbol, stop_loss, take_profit, ORDER_TIME_SPECIFIED, experation, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OrderManagment::close_buy_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long magic_number){
|
||||||
|
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
posTicket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
|
||||||
|
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
|
||||||
|
|
||||||
|
if(condition){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(close_bars > 0){
|
||||||
|
if(time_difference >= close_bars){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OrderManagment::close_sell_orders(string symbol, bool condition, int close_bars, ENUM_TIMEFRAMES close_bar_period, long magic_number){
|
||||||
|
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
posTicket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
time_difference = Bars(symbol, close_bar_period, PositionGetInteger(POSITION_TIME), TimeCurrent()) - 1;
|
||||||
|
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
|
||||||
|
|
||||||
|
if(condition){trade.PositionClose(posTicket);}
|
||||||
|
|
||||||
|
if(close_bars > 0){
|
||||||
|
if(time_difference >= close_bars){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// order_side int must be 1 for BUY or 2 for SELL
|
||||||
|
int OrderManagment::count_open_positions(string symbol,int order_side, long magic_number){
|
||||||
|
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
bool match = (PositionGetInteger(POSITION_MAGIC)==magic_number);
|
||||||
|
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
ulong ticket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC)==magic_number){
|
||||||
|
|
||||||
|
// Count only Buy orders:
|
||||||
|
if(order_side == 1){
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count only Sell orders:
|
||||||
|
if(order_side == 2){
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OrderManagment::count_all_positions(string symbol, long magic_number){
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
ulong ticket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC)==magic_number){
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OrderManagment::daily_timed_exit(string symbol, datetime exit_time, int delay_days, long magic_number){
|
||||||
|
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
posTicket = PositionGetTicket(i);
|
||||||
|
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||||
|
|
||||||
|
if((int)position_open_time>0){
|
||||||
|
|
||||||
|
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||||
|
if(TimeCurrent() > first_allowed_close_time){
|
||||||
|
|
||||||
|
// datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker");
|
||||||
|
if(TimeCurrent()>= exit_time){
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sell orders:
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OrderManagment::daily_timed_profit_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, string exit_time, string cw_tzone, int delay_days, long magic_number){
|
||||||
|
|
||||||
|
// om.daily_timed_profit_exit(_Symbol, PERIOD_CURRENT, "16:45", "17:00", "NY", 1, inp_magic);
|
||||||
|
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
posTicket = PositionGetTicket(i);
|
||||||
|
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||||
|
|
||||||
|
if((int)position_open_time>0){
|
||||||
|
|
||||||
|
first_allowed_close_time = position_open_time + (delay_days * PeriodSeconds(PERIOD_D1));
|
||||||
|
if(TimeCurrent() > first_allowed_close_time){
|
||||||
|
|
||||||
|
|
||||||
|
datetime broker_close_time = tz.timezone_conversions(cw_tzone, StringToTime(exit_time), "Broker");
|
||||||
|
if(TimeCurrent()>= broker_close_time){
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||||
|
double spread = SymbolInfoDouble(symbol,SYMBOL_ASK) - SymbolInfoDouble(symbol,SYMBOL_BID);
|
||||||
|
double bar_close = iClose(_Symbol, close_bar_period, 1); // shift 1 because 0 = live candle.
|
||||||
|
double trading_cost = cpd.calculate_trading_cost(symbol, posTicket);
|
||||||
|
|
||||||
|
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
|
||||||
|
if(bar_close > (position_open_price + spread + trading_cost)){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sell orders:
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
|
||||||
|
if(bar_close < position_open_price - spread - trading_cost){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OrderManagment::first_profitable_close_exit(string symbol, ENUM_TIMEFRAMES close_bar_period, long magic_number){
|
||||||
|
// om.first_profitable_close_exit(_Symbol, PERIOD_CURRENT, inp_magic);
|
||||||
|
|
||||||
|
position_open_time = PositionGetInteger(POSITION_TIME);
|
||||||
|
first_allowed_close_time = position_open_time + PeriodSeconds(close_bar_period);
|
||||||
|
|
||||||
|
if((int)position_open_time>0){
|
||||||
|
|
||||||
|
if(TimeCurrent() > first_allowed_close_time){
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
posTicket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||||
|
double spread = SymbolInfoDouble(symbol,SYMBOL_ASK) - SymbolInfoDouble(symbol,SYMBOL_BID);
|
||||||
|
double bar_close = iClose(_Symbol,close_bar_period, 1); // shift 1 because 0 = live candle.
|
||||||
|
double trading_cost = cpd.calculate_trading_cost(symbol, posTicket);
|
||||||
|
|
||||||
|
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){
|
||||||
|
if(bar_close > (position_open_price + spread + trading_cost)){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sell orders:
|
||||||
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){
|
||||||
|
if(bar_close < position_open_price - spread - trading_cost){
|
||||||
|
trade.PositionClose(posTicket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. int buy_stop_count = om.count_pending_orders(symbol, ORDER_TYPE_BUY_STOP, inp_magic);
|
||||||
|
// order types: ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT, ORDER_TYPE_BUY_STOP, ORDER_TYPE_SELL_STOP
|
||||||
|
int OrderManagment::count_pending_orders(string symbol, ENUM_ORDER_TYPE order_type, long magic){
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for(int i=OrdersTotal()-1;i>=0;i--) {
|
||||||
|
|
||||||
|
if(m_order.SelectByIndex(i)){
|
||||||
|
if( OrderGetInteger(ORDER_MAGIC) == magic && OrderGetString(ORDER_SYMBOL) == symbol){
|
||||||
|
|
||||||
|
if(m_order.OrderType()==order_type){
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OrderManagment::break_even_stop(string symbol, ulong magic_number, int be_trigger_points, int be_puffer){
|
||||||
|
|
||||||
|
if(PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == magic_number){
|
||||||
|
|
||||||
|
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
||||||
|
double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||||||
|
|
||||||
|
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
|
||||||
|
ask = NormalizeDouble(ask, symbol_digits);
|
||||||
|
|
||||||
|
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
|
||||||
|
bid = NormalizeDouble(bid, symbol_digits);
|
||||||
|
|
||||||
|
if(be_trigger_points !=0){
|
||||||
|
for(int i = PositionsTotal()-1; i >=0; i--){
|
||||||
|
|
||||||
|
ulong ticket = PositionGetTicket(i);
|
||||||
|
if(PositionSelectByTicket(ticket)){
|
||||||
|
|
||||||
|
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||||
|
double position_volume = PositionGetDouble(POSITION_VOLUME);
|
||||||
|
double position_sl = PositionGetDouble(POSITION_SL);
|
||||||
|
double position_tp = PositionGetDouble(POSITION_TP);
|
||||||
|
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||||
|
|
||||||
|
if(position_type == POSITION_TYPE_BUY){
|
||||||
|
|
||||||
|
if(bid > position_open_price + be_trigger_points * symbol_point){
|
||||||
|
|
||||||
|
double sl = position_open_price + be_puffer * symbol_point;
|
||||||
|
sl = NormalizeDouble(sl, symbol_digits);
|
||||||
|
if(sl > position_sl){
|
||||||
|
|
||||||
|
if(trade.PositionModify(ticket, sl, position_tp)){
|
||||||
|
Print("-----------------------------------Stop moved to break even");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(position_type == POSITION_TYPE_SELL){
|
||||||
|
|
||||||
|
if(ask < position_open_price - be_trigger_points * symbol_point){
|
||||||
|
|
||||||
|
double sl = position_open_price - be_puffer * symbol_point;
|
||||||
|
sl = NormalizeDouble(sl, symbol_digits);
|
||||||
|
if(sl < position_sl){
|
||||||
|
|
||||||
|
if(trade.PositionModify(ticket, sl, position_tp)){
|
||||||
|
Print("-----------------------------------Stop moved to break even");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double OrderManagment::sl_specified_value_switch(string _sl_mode, double _inp_sl_var, double value){
|
||||||
|
double sl = 0;
|
||||||
|
if(_sl_mode=="SL_SPECIFIED_VALUE"){sl = value;}
|
||||||
|
if(_sl_mode!="SL_SPECIFIED_VALUE"){sl = _inp_sl_var;}
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
double OrderManagment::tp_specified_value_switch(string _tp_mode, double _inp_tp_var, double value){
|
||||||
|
double tp = 0;
|
||||||
|
if(_tp_mode=="SL_SPECIFIED_VALUE"){tp = value;}
|
||||||
|
if(_tp_mode!="SL_SPECIFIED_VALUE"){tp = _inp_tp_var;}
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+168
@@ -0,0 +1,168 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/DealingWithTime.mqh>
|
||||||
|
|
||||||
|
class TimeZones: public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
string dt_s;
|
||||||
|
int len;
|
||||||
|
string dt_string;
|
||||||
|
datetime tC, tGMT, tNY, tLon, tFfm, tMosc, tSyd, tTok;
|
||||||
|
datetime tz_time;
|
||||||
|
string tz_date;
|
||||||
|
datetime time_start;
|
||||||
|
datetime time_end;
|
||||||
|
bool is_time;
|
||||||
|
datetime tGIVEN;
|
||||||
|
datetime tREQ;
|
||||||
|
datetime tzt;
|
||||||
|
datetime tz_req;
|
||||||
|
double ny_daily_close_protected(string symbol, int shift_days, bool print_data=false);
|
||||||
|
double required_close;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string get_date_string_from_datetime(datetime dt);
|
||||||
|
datetime get_timezone_time(string time_zone, bool print_time);
|
||||||
|
datetime timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required);
|
||||||
|
double ny_daily_close(string symbol, int shift_days, bool print_data=false);
|
||||||
|
};
|
||||||
|
|
||||||
|
string TimeZones::get_date_string_from_datetime(datetime dt){
|
||||||
|
dt_s = TimeToString(dt);
|
||||||
|
len = StringLen(dt_s);
|
||||||
|
dt_string = StringSubstr(dt_s, 0, len-5);
|
||||||
|
return dt_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool TimeZones::trading_window(string time_zone, string start_time, string end_time){
|
||||||
|
// // https://www.youtube.com/watch?v=V_qh7sTbl80
|
||||||
|
// // e.g:
|
||||||
|
// // bool trade_window = trading_window(x,x,x);
|
||||||
|
// // bool long_in = trade_window
|
||||||
|
// // && close < ma[0];
|
||||||
|
|
||||||
|
// tz_time = get_timezone_time(time_zone, false);
|
||||||
|
// Print(tz_time);
|
||||||
|
|
||||||
|
// // Get the current date for the required time zone:
|
||||||
|
// tz_date = get_date_string_from_datetime(tz_time);
|
||||||
|
|
||||||
|
// // Define the start and end times on correct date:
|
||||||
|
// time_start = StringToTime(tz_date + start_time);
|
||||||
|
// time_end = StringToTime(tz_date + end_time);
|
||||||
|
|
||||||
|
// if(time_start>time_end){
|
||||||
|
// time_start = time_start - PeriodSeconds(PERIOD_D1);
|
||||||
|
// }
|
||||||
|
// is_time = tz_time >= time_start && tz_time < time_end;
|
||||||
|
|
||||||
|
// return is_time;
|
||||||
|
// }
|
||||||
|
|
||||||
|
datetime TimeZones::get_timezone_time(string time_zone, bool print_time){
|
||||||
|
// https://www.mql5.com/en/code/45287
|
||||||
|
// https://www.mql5.com/en/articles/9926
|
||||||
|
// https://www.mql5.com/en/articles/9929
|
||||||
|
|
||||||
|
checkTimeOffset(TimeCurrent()); // check changes of DST
|
||||||
|
// cto();
|
||||||
|
|
||||||
|
tC = TimeCurrent();
|
||||||
|
tGMT = TimeCurrent() + OffsetBroker.actOffset; // GMT
|
||||||
|
tNY = tGMT - (NYShift+DST_USD); // time in New York (EST)
|
||||||
|
tLon = tGMT - (LondonShift+DST_EUR); // time in London
|
||||||
|
tFfm = tGMT - (FfmShift+DST_EUR); // time in Frankfurt
|
||||||
|
tSyd = tGMT - (SidneyShift+DST_AUD); // time in Sidney
|
||||||
|
tMosc = tGMT - (MoskwaShift+DST_RUS); // time in Moscow
|
||||||
|
tTok = tGMT - (TokyoShift); // time in Tokyo - no DST
|
||||||
|
|
||||||
|
if(print_time==true){
|
||||||
|
Print("----------------------------------");
|
||||||
|
Print("Broker: ", tC);
|
||||||
|
Print("GMT: ", tGMT);
|
||||||
|
Print("time in New York: ", tNY);
|
||||||
|
Print("time in London: ", tLon);
|
||||||
|
Print("time in Frankfurt: ", tFfm);
|
||||||
|
Print("time in Sidney: ", tSyd);
|
||||||
|
Print("time in Moscow: ", tMosc);
|
||||||
|
Print("time in Tokyo: ", tTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(time_zone=="NY"){return tNY;}
|
||||||
|
if(time_zone=="Lon"){return tLon;}
|
||||||
|
if(time_zone=="Ffm"){return tFfm;}
|
||||||
|
if(time_zone=="Syd"){return tSyd;}
|
||||||
|
if(time_zone=="Mosc"){return tMosc;}
|
||||||
|
if(time_zone=="Tok"){return tTok;}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
datetime TimeZones::timezone_conversions(string time_zone_known, datetime time_given, string time_zone_required){
|
||||||
|
// https://www.mql5.com/en/code/45287
|
||||||
|
// https://www.mql5.com/en/articles/9926
|
||||||
|
// https://www.mql5.com/en/articles/9929
|
||||||
|
|
||||||
|
tGIVEN = time_given; //StringToTime(time_given);
|
||||||
|
|
||||||
|
checkTimeOffset(tGIVEN); // check changes of DST
|
||||||
|
|
||||||
|
// Get GMT:
|
||||||
|
if(time_zone_known=="GMT" ){tGMT = tGIVEN;}
|
||||||
|
if(time_zone_known=="Broker" ){tGMT = tGIVEN + OffsetBroker.actOffset;}
|
||||||
|
if(time_zone_known=="NY" ){tGMT = tGIVEN + (NYShift+DST_USD);}
|
||||||
|
if(time_zone_known=="Lon" ){tGMT = tGIVEN + (LondonShift+DST_EUR);}
|
||||||
|
if(time_zone_known=="Ffm" ){tGMT = tGIVEN + (FfmShift+DST_EUR);}
|
||||||
|
if(time_zone_known=="Syd" ){tGMT = tGIVEN + (SidneyShift+DST_AUD);}
|
||||||
|
if(time_zone_known=="Mosc" ){tGMT = tGIVEN + (MoskwaShift+DST_RUS);}
|
||||||
|
if(time_zone_known=="Tok" ){tGMT = tGIVEN + (TokyoShift);}
|
||||||
|
|
||||||
|
// define the required time:
|
||||||
|
tREQ = NULL;
|
||||||
|
if(time_zone_required=="GMT" ){tREQ = tGMT;}
|
||||||
|
if(time_zone_required=="Broker" ){tREQ = tGMT - OffsetBroker.actOffset;}
|
||||||
|
if(time_zone_required=="NY" ){tREQ = tGMT - (NYShift+DST_USD);}
|
||||||
|
if(time_zone_required=="Lon" ){tREQ = tGMT - (LondonShift+DST_EUR);}
|
||||||
|
if(time_zone_required=="Ffm" ){tREQ = tGMT - (FfmShift+DST_EUR);}
|
||||||
|
if(time_zone_required=="Syd" ){tREQ = tGMT - (SidneyShift+DST_AUD) ;}
|
||||||
|
if(time_zone_required=="Mosc" ){tREQ = tGMT - (MoskwaShift+DST_RUS);}
|
||||||
|
if(time_zone_required=="Tok" ){tREQ = tGMT - (TokyoShift);}
|
||||||
|
|
||||||
|
return tREQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculte NY close time:
|
||||||
|
double TimeZones::ny_daily_close(string symbol, int shift_days, bool print_data=false){
|
||||||
|
required_close = ny_daily_close_protected(symbol, shift_days, print_data);
|
||||||
|
return required_close;
|
||||||
|
}
|
||||||
|
double TimeZones::ny_daily_close_protected(string symbol, int shift_days, bool print_data=false){
|
||||||
|
|
||||||
|
// Get the brokers times for when NY openend today and tomorrow:
|
||||||
|
datetime time_5pm = iTime(symbol, PERIOD_D1 , 0) - (PeriodSeconds(PERIOD_H1) * 7);
|
||||||
|
datetime ny_close_in_brokers_time = timezone_conversions("NY", time_5pm, "Broker");
|
||||||
|
datetime ny_close_time = ny_close_in_brokers_time + PeriodSeconds(PERIOD_D1); // ny close tomorrow
|
||||||
|
|
||||||
|
if(TimeCurrent()<ny_close_time){
|
||||||
|
ny_close_time = ny_close_time - PeriodSeconds(PERIOD_D1); // ny close today
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of hours since NY closed:
|
||||||
|
int shift = iBarShift(symbol, PERIOD_H1, ny_close_time, false) + 1;
|
||||||
|
shift = shift + (24 * (shift_days - 1)); // shift days if required:
|
||||||
|
|
||||||
|
double ny_close = iClose(symbol,PERIOD_H1, shift);
|
||||||
|
double br_close = iClose(symbol,PERIOD_H1, 1);
|
||||||
|
|
||||||
|
if(print_data==true){
|
||||||
|
Print("shift ",shift);
|
||||||
|
Print("time_5pm ",time_5pm);
|
||||||
|
Print("ny_close_in_brokers_time ",ny_close_in_brokers_time);
|
||||||
|
Print("ny_close_time ",ny_close_time);
|
||||||
|
Print("ny_close ", ny_close);
|
||||||
|
Print("br_close ",br_close);
|
||||||
|
}
|
||||||
|
return ny_close;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#property library
|
||||||
|
#include <Trade/Trade.mqh>
|
||||||
|
#include <MyLibs/TimeZones.mqh>
|
||||||
|
|
||||||
|
class TradingWindow : public CObject{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TimeZones tz;
|
||||||
|
bool in_window;
|
||||||
|
datetime start_time;
|
||||||
|
datetime end_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool define_window(string t1, string t2, string time_zone, bool plot_range_inp=true);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool TradingWindow::define_window(string t1, string t2, string time_zone, bool plot_range=true){
|
||||||
|
|
||||||
|
datetime _t1 = StringToTime(t1);
|
||||||
|
datetime _t2 = StringToTime(t2);
|
||||||
|
if(_t1 > _t2){
|
||||||
|
_t2 = _t2 + PeriodSeconds(PERIOD_D1);
|
||||||
|
}
|
||||||
|
int w_duration = (int)(_t2 - _t1);
|
||||||
|
|
||||||
|
// window flag
|
||||||
|
if(TimeCurrent() >= start_time && TimeCurrent() <= end_time){
|
||||||
|
in_window = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// define new window
|
||||||
|
if(TimeCurrent() >= end_time){
|
||||||
|
|
||||||
|
in_window = false;
|
||||||
|
start_time = tz.timezone_conversions(time_zone, StringToTime(t1), "Broker");
|
||||||
|
|
||||||
|
if(TimeCurrent()>=start_time){
|
||||||
|
start_time += PeriodSeconds(PERIOD_D1);
|
||||||
|
}
|
||||||
|
|
||||||
|
end_time = start_time + w_duration;
|
||||||
|
|
||||||
|
if(plot_range){
|
||||||
|
|
||||||
|
string name = "Start Time" + (string)start_time;
|
||||||
|
if(start_time>0){
|
||||||
|
ObjectCreate(NULL, name, OBJ_VLINE, 0, start_time, 0);
|
||||||
|
ObjectSetInteger(NULL, name,OBJPROP_COLOR, clrBlue);
|
||||||
|
ObjectSetInteger(NULL, name,OBJPROP_BACK, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
name = "End Time" + (string)end_time;
|
||||||
|
if(end_time>0){
|
||||||
|
ObjectCreate(NULL, name, OBJ_VLINE, 0, end_time, 0);
|
||||||
|
ObjectSetInteger(NULL, name,OBJPROP_COLOR, C'56,108,26');
|
||||||
|
ObjectSetInteger(NULL, name,OBJPROP_BACK, true);
|
||||||
|
}
|
||||||
|
ChartRedraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return in_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user