diff --git a/MtApi/Monitors/MtMonitorBase.cs b/MtApi/Monitors/MtMonitorBase.cs
new file mode 100644
index 00000000..8f5c0407
--- /dev/null
+++ b/MtApi/Monitors/MtMonitorBase.cs
@@ -0,0 +1,113 @@
+using System;
+using MtApi.Monitors.Triggers;
+
+namespace MtApi.Monitors
+{
+ public abstract class MtMonitorBase
+ {
+ #region Fields
+ private volatile bool _isStarted = false;
+ private bool _syncTrigger;
+ #endregion
+
+ #region Properties
+ ///
+ /// ApiClient
+ ///
+ protected MtApiClient ApiClient { get; }
+ ///
+ /// Returns true if the is connected.
+ ///
+ public bool IsMtConnected => ApiClient.ConnectionState == MtConnectionState.Connected;
+ ///
+ /// Returns the trigger which will be used to raise the monitoring call.
+ ///
+ public IMonitorTrigger MonitorTrigger { get; }
+ ///
+ /// Returns true if the Monitor is started.
+ ///
+ public bool IsStarted { get => _isStarted; }
+ ///
+ /// If true, the will be stopped or started automatically when or will be called.
+ /// CAUTION: If you use the MonitorTrigger for different Monitors, this will stop all monitors if you call stop and is true.
+ ///
+ public bool SyncTrigger { get => _syncTrigger; set => _syncTrigger = value; }
+ #endregion
+
+ #region ctor
+ ///
+ /// Default constructor for Monitors
+ ///
+ /// The apiClient which will be used to work with.
+ /// The trigger which lead this Monitor to do his work.
+ /// See property .
+ public MtMonitorBase(MtApiClient apiClient, IMonitorTrigger monitorTrigger, bool syncTrigger = false)
+ {
+ ApiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
+ MonitorTrigger = monitorTrigger ?? throw new ArgumentNullException(nameof(monitorTrigger));
+ SyncTrigger = syncTrigger;
+ }
+ #endregion
+
+ #region Methods
+ ///
+ /// Let the monitor listen to the .
+ ///
+ public virtual void Start()
+ {
+ if (!_isStarted)
+ {
+ ApiClient.ConnectionStateChanged += ApiClientConnectionStateChanged;
+ MonitorTrigger.Raised += MonitorTriggerRaised;
+ _isStarted = true;
+ OnStart();
+ if (SyncTrigger)
+ MonitorTrigger.Start();
+ }
+ }
+ ///
+ /// Let the monitor stop listening to the .
+ ///
+ public virtual void Stop()
+ {
+ if (_isStarted)
+ {
+ MonitorTrigger.Raised -= MonitorTriggerRaised;
+ ApiClient.ConnectionStateChanged -= ApiClientConnectionStateChanged;
+ _isStarted = false;
+ OnStop();
+ if (SyncTrigger)
+ MonitorTrigger.Stop();
+ }
+ }
+ private void MonitorTriggerRaised(object sender, EventArgs e) => OnTriggerRaised();
+ private void ApiClientConnectionStateChanged(object sender, MtConnectionEventArgs e)
+ {
+ if (e.Status == MtConnectionState.Connected)
+ OnMtConnected();
+ else if (e.Status == MtConnectionState.Failed || e.Status == MtConnectionState.Disconnected)
+ OnMtDisconnected();
+ }
+ ///
+ /// Will be called when will be called.
+ ///
+ protected virtual void OnStart() { }
+ ///
+ /// Will be called when will be called.
+ ///
+ protected virtual void OnStop() { }
+ ///
+ /// Will be called when the is successfully connected.
+ ///
+ protected virtual void OnMtConnected() { }
+ ///
+ /// Will be called when is disconnected.
+ ///
+ protected virtual void OnMtDisconnected() { }
+ ///
+ /// Will be called when the raised.
+ ///
+ protected abstract void OnTriggerRaised();
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/MtApi/Monitors/TimeframeTradeMonitor.cs b/MtApi/Monitors/TimeframeTradeMonitor.cs
index 41663663..e76306d8 100644
--- a/MtApi/Monitors/TimeframeTradeMonitor.cs
+++ b/MtApi/Monitors/TimeframeTradeMonitor.cs
@@ -1,56 +1,13 @@
-
+using MtApi.Monitors.Triggers;
+
namespace MtApi.Monitors
{
public class TimeframeTradeMonitor : TradeMonitor
{
- #region Fields
- private volatile bool _isStarted;
- #endregion
-
- #region ctor
- public TimeframeTradeMonitor(MtApiClient apiClient)
- : base(apiClient)
+ public TimeframeTradeMonitor(MtApiClient apiClient)
+ : base(apiClient, new NewBarTrigger(apiClient))
{
- apiClient.OnLastTimeBar += ApiClient_OnLastTimeBar;
+ SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
}
- #endregion
-
- #region Public Methods
- //
- // Summary:
- // Gets a value indicating whether the TimeframeTradeMonitor should raise checking orders
- //
- // Returns:
- // true if PositionMonitor should check orders
- // otherwise, false.
- public override bool IsStarted => _isStarted;
-
- #endregion
-
- #region Protected Methods
- protected override void OnMtConnected() {}
-
- protected override void OnMtDisconnected() {}
-
- protected override void OnStart()
- {
- _isStarted = true;
- }
-
- protected override void OnStop()
- {
- _isStarted = false;
- }
- #endregion
-
- #region Private Methods
- private void ApiClient_OnLastTimeBar(object sender, TimeBarArgs e)
- {
- if (_isStarted)
- {
- Check();
- }
- }
- #endregion
}
-}
+}
\ No newline at end of file
diff --git a/MtApi/Monitors/TimerTradeMonitor.cs b/MtApi/Monitors/TimerTradeMonitor.cs
index c8b430f2..4d52c746 100644
--- a/MtApi/Monitors/TimerTradeMonitor.cs
+++ b/MtApi/Monitors/TimerTradeMonitor.cs
@@ -1,90 +1,27 @@
-using System.Timers;
+using System;
+using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
public class TimerTradeMonitor : TradeMonitor
{
- #region Fields
- private readonly Timer _timer = new Timer();
- #endregion
-
- #region ctor
- public TimerTradeMonitor(MtApiClient apiClient)
- : base(apiClient)
- {
- _timer.Interval = 10000; //default interval 10 sec
- _timer.Elapsed += _timer_Elapsed;
-
- }
- #endregion
-
- #region Public Methods
- //
- // Summary:
- // Gets or sets the interval, expressed in milliseconds, at which to check orders
- //
- // Returns:
- // The time, in milliseconds, between checking events. The value
- // must be greater than zero, and less than or equal to System.Int32.MaxValue.
- // The default is 10000 milliseconds.
- //
- // Exceptions:
- // T:System.ArgumentException:
- // The interval is less than or equal to zero.-or-The interval is greater than System.Int32.MaxValue,
- // and the PositionMonitor is currently started.
+ private readonly TimeElapsedTrigger _timeElapsedTrigger;
public double Interval
{
- get { return _timer.Interval; }
- set { _timer.Interval = value; }
+ get => _timeElapsedTrigger.Interval.TotalMilliseconds;
+ set => _timeElapsedTrigger.Interval = TimeSpan.FromMilliseconds(value);
}
- //
- // Summary:
- // Gets a value indicating whether the PositionMonitor should raise checking orders
- //
- // Returns:
- // true if TimerTradeMonitor should check orders
- // otherwise, false.
- public override bool IsStarted
+ public TimerTradeMonitor(MtApiClient apiClient)
+ : this(apiClient, new TimeElapsedTrigger(TimeSpan.FromSeconds(10)))
{
- get { return _timer.Enabled; }
- }
- #endregion
- #region Protected Methods
- protected override void OnStart()
+ }
+ public TimerTradeMonitor(MtApiClient apiClient, TimeElapsedTrigger timeElapsedTrigger)
+ : base(apiClient, timeElapsedTrigger)
{
- if (IsMtConnected)
- {
- _timer.Start();
- }
+ SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
+ _timeElapsedTrigger = timeElapsedTrigger;
}
-
- protected override void OnStop()
- {
- _timer.Stop();
- }
-
- protected override void OnMtConnected()
- {
- _timer.Start();
- }
-
- protected override void OnMtDisconnected()
- {
- _timer.Stop();
- }
- #endregion
-
- #region Private Methods
- private void _timer_Elapsed(object sender, ElapsedEventArgs e)
- {
- _timer.Elapsed -= _timer_Elapsed; //unregister from events to prevent rise condition during work with orders
-
- Check();
-
- _timer.Elapsed += _timer_Elapsed; //register again
- }
- #endregion
}
-}
+}
\ No newline at end of file
diff --git a/MtApi/Monitors/TradeMonitor.cs b/MtApi/Monitors/TradeMonitor.cs
index fc746339..d1e498ca 100644
--- a/MtApi/Monitors/TradeMonitor.cs
+++ b/MtApi/Monitors/TradeMonitor.cs
@@ -1,63 +1,18 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
+using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
- public abstract class TradeMonitor
+ public class TradeMonitor : MtMonitorBase
{
#region Fields
- private readonly MtApiClient _apiClient;
private List _prevOrders;
private readonly object _locker = new object();
#endregion
- #region ctor
- protected TradeMonitor(MtApiClient apiClient)
- {
- if (apiClient == null)
- throw new ArgumentNullException(nameof(apiClient));
-
- _apiClient = apiClient;
- }
- #endregion
-
- #region Public Methods
- //
- // Summary:
- // Gets a value indicating whether the TradeMonitor should raise checking orders
- //
- // Returns:
- // true if TradeMonitor should check orders
- // otherwise, false.
- public abstract bool IsStarted { get; }
-
- //
- // Summary:
- // Start checking orders.
- //
- public void Start()
- {
- _apiClient.ConnectionStateChanged += _apiClient_ConnectionStateChanged;
- if (IsMtConnected)
- {
- InitialCheck();
- }
-
- OnStart();
- }
-
- //
- // Summary:
- // Stop checking orders.
- //
- public void Stop()
- {
- _apiClient.ConnectionStateChanged -= _apiClient_ConnectionStateChanged;
- OnStop();
- }
- #endregion
-
#region Events
//
// Summary:
@@ -65,17 +20,23 @@ namespace MtApi.Monitors
public event EventHandler AvailabilityOrdersChanged;
#endregion
- #region Protected Methods
+ #region ctor
+ public TradeMonitor(MtApiClient apiClient, IMonitorTrigger monitorTrigger) : base(apiClient, monitorTrigger) { }
+ #endregion
- protected abstract void OnStart();
- protected abstract void OnStop();
-
- protected abstract void OnMtConnected();
- protected abstract void OnMtDisconnected();
-
- public bool IsMtConnected => _apiClient.ConnectionState == MtConnectionState.Connected;
-
- protected void Check()
+ protected override void OnMtConnected()
+ {
+ InitialCheck();
+ base.OnMtConnected();
+ }
+ protected override void OnStart()
+ {
+ if (IsMtConnected)
+ InitialCheck();
+ base.OnStart();
+ }
+ protected override void OnTriggerRaised() => Check();
+ private void Check()
{
try
{
@@ -90,92 +51,48 @@ namespace MtApi.Monitors
//TODO: write error to log
}
}
- #endregion
+ private void InitialCheck()
+ {
+ lock (_locker)
+ _prevOrders = null;
- #region Private Methods
+ Task.Factory.StartNew(Check);
+ }
private void CheckOrders()
{
var openedOrders = new List();
var closedOrders = new List();
+ List prevOrders;
// get current orders from MetaTrader
- var tradesOrders = _apiClient.GetOrders(OrderSelectSource.MODE_TRADES);
+ var tradesOrders = ApiClient.GetOrders(OrderSelectSource.MODE_TRADES);
- List prevOrders;
- lock(_locker)
- {
+ lock (_locker)
prevOrders = _prevOrders;
- }
if (prevOrders != null) //skip checking on first load orders
{
//check open orders
- foreach (var order in tradesOrders)
- {
- if (prevOrders.Find(a => a.Ticket == order.Ticket) == null)
- {
- openedOrders.Add(order);
- }
- }
+ openedOrders = tradesOrders.Where(to => prevOrders.Find(a => a.Ticket == to.Ticket) == null).ToList();
//check closed orders
- var closeOrdersTemp = new List();
- foreach (var order in prevOrders)
- {
- if (tradesOrders.Find(a => a.Ticket == order.Ticket) == null)
- {
- closeOrdersTemp.Add(order);
- }
- }
+ var closeOrdersTemp = prevOrders.Where(po => tradesOrders.Find(a => a.Ticket == po.Ticket) == null).ToList();
if (closeOrdersTemp.Count > 0)
{
//get closed orders from history with actual values
- var historyOrders = _apiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
- foreach (var order in closeOrdersTemp)
- {
- var closedOrder = historyOrders.Find(a => a.Ticket == order.Ticket);
- if (closedOrder != null)
- {
- closedOrders.Add(closedOrder);
- }
- }
+ var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
+ closedOrders = closeOrdersTemp.Where(cot => historyOrders.Find(a => a.Ticket == cot.Ticket) != null).ToList();
}
}
- lock(_locker)
- {
+ lock (_locker)
_prevOrders = tradesOrders;
- }
if (openedOrders.Count > 0 || closedOrders.Count > 0)
{
AvailabilityOrdersChanged?.Invoke(this, new AvailabilityOrdersEventArgs(openedOrders, closedOrders));
}
}
-
- private void _apiClient_ConnectionStateChanged(object sender, MtConnectionEventArgs e)
- {
- if (e.Status == MtConnectionState.Connected)
- {
- InitialCheck();
- OnMtConnected();
- }
- else if (e.Status == MtConnectionState.Failed || e.Status == MtConnectionState.Disconnected)
- {
- OnMtDisconnected();
- }
- }
-
- private void InitialCheck()
- {
- lock (_locker)
- {
- _prevOrders = null;
- }
-
- Task.Factory.StartNew(Check);
- }
- #endregion
}
-}
\ No newline at end of file
+}
diff --git a/MtApi/Monitors/Triggers/IMonitorTrigger.cs b/MtApi/Monitors/Triggers/IMonitorTrigger.cs
new file mode 100644
index 00000000..54e268d8
--- /dev/null
+++ b/MtApi/Monitors/Triggers/IMonitorTrigger.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace MtApi.Monitors.Triggers
+{
+ ///
+ /// Interface for triggers which can be used to trigger a .
+ ///
+ public interface IMonitorTrigger
+ {
+ ///
+ /// Event will be called if the trigger raised.
+ ///
+ event EventHandler Raised;
+ ///
+ /// Returns whether the trigger is started
+ ///
+ bool IsStarted { get; }
+ ///
+ /// Stops the trigger and prevents further calls of the event.
+ ///
+ void Stop();
+ ///
+ /// Starts the trigger.
+ ///
+ void Start();
+ }
+}
diff --git a/MtApi/Monitors/Triggers/NewBarTrigger.cs b/MtApi/Monitors/Triggers/NewBarTrigger.cs
new file mode 100644
index 00000000..2c4cdc4e
--- /dev/null
+++ b/MtApi/Monitors/Triggers/NewBarTrigger.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace MtApi.Monitors.Triggers
+{
+ ///
+ /// Raises the event if a bar is closed and a new one started.
+ ///
+ public class NewBarTrigger : IMonitorTrigger
+ {
+ #region Fields
+ private volatile bool _isStarted;
+ private readonly MtApiClient _apiClient;
+ #endregion
+
+ public bool IsStarted => _isStarted;
+ public event EventHandler Raised;
+ public NewBarTrigger(MtApiClient apiClient)
+ {
+ _apiClient = apiClient;
+ _apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
+ }
+
+ private void _apiClient_OnLastTimeBar(object sender, TimeBarArgs e)
+ {
+ if (_isStarted)
+ Raised?.Invoke(this, EventArgs.Empty);
+ }
+
+ public void Start() => SetIsStarted(true);
+ public void Stop() => SetIsStarted(false);
+ private void SetIsStarted(bool value)
+ {
+ if (value != _isStarted)
+ {
+ _isStarted = value;
+ if (value)
+ _apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
+ else
+ _apiClient.OnLastTimeBar -= _apiClient_OnLastTimeBar;
+ }
+ }
+ }
+}
diff --git a/MtApi/Monitors/Triggers/TimeElapsedTrigger.cs b/MtApi/Monitors/Triggers/TimeElapsedTrigger.cs
new file mode 100644
index 00000000..ba085fd1
--- /dev/null
+++ b/MtApi/Monitors/Triggers/TimeElapsedTrigger.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Timers;
+
+namespace MtApi.Monitors.Triggers
+{
+ public class TimeElapsedTrigger : IMonitorTrigger
+ {
+ readonly Timer _timer;
+
+ public event EventHandler Raised;
+ ///
+ /// Interval for raising the trigger
+ ///
+ public TimeSpan Interval
+ {
+ get => TimeSpan.FromMilliseconds(_timer.Interval);
+ set => _timer.Interval = value.TotalMilliseconds;
+ }
+ public bool IsStarted => _timer.Enabled;
+
+ public bool AutoReset { get => _timer.AutoReset; set => _timer.AutoReset = value; }
+
+ public TimeElapsedTrigger(TimeSpan time, bool autoReset = true)
+ {
+ _timer = new Timer(time.TotalMilliseconds);
+ _timer.Elapsed += _timer_Elapsed;
+ AutoReset = autoReset;
+ }
+
+ private void _timer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ _timer.Elapsed -= _timer_Elapsed;
+ Raised?.Invoke(this, EventArgs.Empty);
+ _timer.Elapsed += _timer_Elapsed;
+ }
+ public void Stop() => _timer.Stop();
+
+ public void Start() => _timer.Start();
+ }
+}
diff --git a/MtApi/MtApi.csproj b/MtApi/MtApi.csproj
index 3a7b9699..92296139 100755
--- a/MtApi/MtApi.csproj
+++ b/MtApi/MtApi.csproj
@@ -76,6 +76,10 @@
+
+
+
+
diff --git a/TestClients/TestApiClientUI/Form1.cs b/TestClients/TestApiClientUI/Form1.cs
index dcf7cef9..ccb12183 100644
--- a/TestClients/TestApiClientUI/Form1.cs
+++ b/TestClients/TestApiClientUI/Form1.cs
@@ -212,8 +212,8 @@ namespace TestApiClientUI
foreach (var quote in quotes)
{
AddNewQuote(quote);
- }
- }
+ }
+ }
}
private void OnDisconnected()
@@ -456,7 +456,7 @@ namespace TestApiClientUI
ticket = (int)listBoxSendedOrders.SelectedItems[0];
else if (listBoxClosedOrders.SelectedItems.Count > 0)
ticket = (int)listBoxClosedOrders.SelectedItems[0];
-
+
if (ticket >= 0)
{
var result = _apiClient.OrderSelect(ticket, OrderSelectMode.SELECT_BY_POS);