//+------------------------------------------------------------------+ //| MTMonitor.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property version "1.10.1" #include #include "MTUtils.mqh" #include "MTTimer.mqh" input group "Monitor"; input int positions_box = 10; input int positions_balancer = 2; input int long_positions_budget = 5; input int short_positions_budget = 5; input double long_volume_budget = 0.3; input double short_volume_budget = 0.3; input group "Track Positions" input int Positions_Counter = 5; input int winning_closing_trigger = 1000; input int loosing_closing_trigger = 4000; input group "Monitor's Timers" input TimeSlot Balancer_Timer_Step; input bool BalancerTimerON = true; input int TimeWindow_Sec = 3600; input group "Box's Times" input int Close_All_Hour = 17;; // 5pm , time should be in 00-23 as int input int Open_All_Hour = 00;; // 12am, time should be in 00-23 int input bool SweepWhenClosing = false; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class PositionsTracker { private: int pt_positionsCount; CQueue pt_ArrayOfPositions; protected: int getLastPosition(bool is_long=true); public: void Init(); void AddLastPosition(bool is_long=true); int getPositionsTracker(); int getLastPositionsLong(void); int getLastPositionsShort(void); }; //+------------------------------------------------------------------+ int PositionsTracker::getLastPositionsLong(void) { int result = getLastPosition(true); if(result == 0) { return 1; } return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int PositionsTracker::getLastPositionsShort(void) { int result = getLastPosition(false); if(result == 0) { return 1; } return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PositionsTracker::Init(void) { pt_positionsCount = Positions_Counter; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ int PositionsTracker::getLastPosition(bool is_long=true) { int long_count = 0; int short_count = 0; int temp = -1; int pt_Size = pt_ArrayOfPositions.Count(); for(int i=pt_Size; i > 0; i--) { temp = pt_ArrayOfPositions.Dequeue(); if(temp == 1) { long_count++; } else if(temp == 0) { short_count ++; } pt_ArrayOfPositions.Enqueue(temp); } if(is_long) { return long_count; } return short_count; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PositionsTracker::AddLastPosition(bool is_long=true) { if(is_long) { pt_ArrayOfPositions.Enqueue(1); } else { pt_ArrayOfPositions.Enqueue(0); } int pt_Size = pt_ArrayOfPositions.Count(); if(pt_Size > pt_positionsCount) { pt_ArrayOfPositions.Dequeue(); } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class MTMonitor { private: int long_pBudget; int short_pBudget; int leverage; int p_positions_budget; int p_positions_balancer; int p_winning_closing_trigger; int p_cushion; int p_capital; double p_win_percent; double initial_equity; double LS_ratio; double long_vBudget; double short_vBudget; bool p_balancer_window_open; bool p_agent_window_open; PositionsTracker p_position_tracker; MTTimer closing_timer; MTTimer opening_timer; public: double MTMonitor::GetMaximumVolumePossible(void); void MTMonitor::CloseAllWhenWhining(void); void MTMonitor::Init(void); bool MTMonitor::BoxCanPlacePosition(void); bool MTMonitor::BalancerCanPlacePosition(void); void MTMonitor::AssessClosingLimits(void); void MTMonitor::CloseAllWhenLosing(void); bool MTMonitor::CanPlacePositionInDirection(bool isLong=true); void MTMonitor::ResetEquity(void) {initial_equity = AccountInfoDouble(ACCOUNT_EQUITY); }; void MTMonitor::addPositionToTracker(bool is_long=true) { p_position_tracker.AddLastPosition(is_long); }; PositionsTracker* MTMonitor::getPositionTracker(void) { return &p_position_tracker; }; void MTMonitor::UpdateClosingTimer(void); void MTMonitor::UpdateOpeningTimer(void); void MTMonitor::UpdatePositionsAgentTimers(void); bool MTMonitor::IsBalancerWindowOpen() { return p_balancer_window_open; }; bool MTMonitor::IsAgentWindowOpen() { return p_agent_window_open; }; bool MTMonitor::CanPlacePositionInDirectionByVolume(bool isLong=true); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::Init() { p_positions_balancer = positions_balancer; p_positions_budget = positions_box; p_winning_closing_trigger = winning_closing_trigger; initial_equity = AccountInfoDouble(ACCOUNT_EQUITY); p_cushion = 0; p_capital = 0; p_win_percent = 0; LS_ratio = 0; leverage = 0; long_pBudget = long_positions_budget; long_vBudget = long_volume_budget; short_pBudget = short_positions_budget; short_vBudget = short_volume_budget; p_position_tracker.Init(); // Possible correction to enact diff object references datetime wall_init_time = TimeCurrent(); opening_timer = new MTTimer(wall_init_time); closing_timer = new MTTimer(wall_init_time+TimeWindow_Sec); p_agent_window_open = false; p_balancer_window_open = false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::UpdateClosingTimer() { if(closing_timer.has_set_alert()) { if(closing_timer.has_triggered()) { p_balancer_window_open = false; closing_timer.reset_alert_set(); closing_timer.roll_base_time(); } } else { switch(Balancer_Timer_Step) { case TS_every_4_hrs: closing_timer.set_alert_from_base_4hrs(); break; case TS_every_12_hrs: closing_timer.set_alert_from_base_12hrs(); break; case TS_every_24_hrs: closing_timer.set_alert_from_base_24hrs(); break; default: Print("No Timer Set : Closing"); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::UpdateOpeningTimer() { if(opening_timer.has_set_alert()) { if(opening_timer.has_triggered()) { p_balancer_window_open = true; opening_timer.reset_alert_set(); opening_timer.roll_base_time(); } } else { switch(Balancer_Timer_Step) { case TS_every_4_hrs: opening_timer.set_alert_from_base_4hrs(); break; case TS_every_12_hrs: opening_timer.set_alert_from_base_12hrs(); break; case TS_every_24_hrs: opening_timer.set_alert_from_base_24hrs(); break; default: Print("No Timer Set: Opening"); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double MTMonitor::GetMaximumVolumePossible(void) { double capital_distributed = p_capital / LS_ratio; double capital_per_direction = capital_distributed * leverage; return (capital_per_direction*PRICE); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool MTMonitor::BalancerCanPlacePosition(void) { // Timers need to be updated in here to open/close the window correctly UpdateOpeningTimer(); UpdateClosingTimer(); // Positions Budget Check that allows to determine if slots avail for positions int open_positions = PositionsTotal(); int total_position_budget = p_positions_budget + p_positions_balancer; int actionable_difference = total_position_budget - open_positions; if(BalancerTimerON) { bool window = IsBalancerWindowOpen(); if(window) { int check = 1; } return (actionable_difference > 0 && window); } else { return (actionable_difference > 0); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool MTMonitor::BoxCanPlacePosition(void) { if(!IsAgentWindowOpen()) { return false; } int open_positions = PositionsTotal(); int actionable_difference = (p_positions_budget) - open_positions; return actionable_difference > 0; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::CloseAllWhenWhining(void) { double profit = AccountInfoDouble(ACCOUNT_EQUITY)- initial_equity; if(profit >= winning_closing_trigger && profit > 0) { close_all_positions(); MTMonitor::ResetEquity(); } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::CloseAllWhenLosing(void) { double profit = initial_equity - AccountInfoDouble(ACCOUNT_EQUITY); if(profit >= loosing_closing_trigger && profit > 0) { close_all_positions(); MTMonitor::ResetEquity(); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::AssessClosingLimits(void) { MTMonitor::CloseAllWhenLosing(); MTMonitor::CloseAllWhenWhining(); MTMonitor::UpdatePositionsAgentTimers(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool MTMonitor::CanPlacePositionInDirection(bool isLong=true) { if(isLong) { return CountPositionsByType(isLong) < long_pBudget; } else { return (CountPositionsByType(isLong) < short_pBudget); } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool MTMonitor::CanPlacePositionInDirectionByVolume(bool isLong=true) { if(isLong) { return GetVolumeInLong() < long_vBudget; } else { return GetVolumeInShort() < short_vBudget; } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void MTMonitor::UpdatePositionsAgentTimers() { int closing_set_hour = Close_All_Hour; int opening_set_hour = Open_All_Hour; MqlDateTime current_time; TimeCurrent(current_time); if(current_time.hour == closing_set_hour && PositionsTotal() > 0) { if(SweepWhenClosing) { close_all_positions(); } p_agent_window_open = false; } else if(current_time.hour >= opening_set_hour && current_time.hour < closing_set_hour) { p_agent_window_open = true; } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+