From 833ce1f19216d24c654bbc3630c47161ed3a708a Mon Sep 17 00:00:00 2001 From: Mitja Date: Sun, 18 Oct 2020 11:05:18 +0200 Subject: [PATCH] Added ModifiedOrdersMonitor, added some more doc --- .../ModifiedOrdersEventArgs.cs | 20 ++++++ .../ModifiedOrdersMonitor.cs | 68 +++++++++++++++++++ .../OrderModification/MtModifiedOrder.cs | 50 ++++++++++++++ .../OrderModification/OrderModifiedTypes.cs | 18 +++++ MtApi/Monitors/readme.md | 66 ++++++++++++++++++ MtApi/MtApi.csproj | 4 ++ 6 files changed, 226 insertions(+) create mode 100644 MtApi/Monitors/OrderModification/ModifiedOrdersEventArgs.cs create mode 100644 MtApi/Monitors/OrderModification/ModifiedOrdersMonitor.cs create mode 100644 MtApi/Monitors/OrderModification/MtModifiedOrder.cs create mode 100644 MtApi/Monitors/OrderModification/OrderModifiedTypes.cs create mode 100644 MtApi/Monitors/readme.md diff --git a/MtApi/Monitors/OrderModification/ModifiedOrdersEventArgs.cs b/MtApi/Monitors/OrderModification/ModifiedOrdersEventArgs.cs new file mode 100644 index 00000000..d803ea8d --- /dev/null +++ b/MtApi/Monitors/OrderModification/ModifiedOrdersEventArgs.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MtApi.Monitors +{ + public class ModifiedOrdersEventArgs : EventArgs + { + /// + /// Returns a list of all modified orders + /// + public List ModifiedOrders { get; } + public ModifiedOrdersEventArgs(List modifiedOrders) + { + ModifiedOrders = modifiedOrders; + } + } +} diff --git a/MtApi/Monitors/OrderModification/ModifiedOrdersMonitor.cs b/MtApi/Monitors/OrderModification/ModifiedOrdersMonitor.cs new file mode 100644 index 00000000..5a4618f6 --- /dev/null +++ b/MtApi/Monitors/OrderModification/ModifiedOrdersMonitor.cs @@ -0,0 +1,68 @@ +using MtApi.Monitors.Triggers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MtApi.Monitors +{ + public class ModifiedOrdersMonitor : MtMonitorBase + { + #region Fields + private List _lastOrders = null; + + #endregion + + #region Properties + /// + /// Define on which types of modification this monitor should raise + /// + public OrderModifiedTypes OrderModifiedTypes { get; set; } + #endregion + + #region Events + /// + /// Will be raised when this monitor detects changes on open orders + /// + public event EventHandler OrdersModified; + #endregion + + #region ctor + public ModifiedOrdersMonitor(MtApiClient apiClient, IMonitorTrigger monitorTrigger, OrderModifiedTypes orderModifiedTypes = OrderModifiedTypes.All, bool syncTrigger = false) + : base(apiClient, monitorTrigger, syncTrigger) + { + _lastOrders = GetOrders(); + OrderModifiedTypes = orderModifiedTypes; + } + #endregion + + /// + /// Requests all current open orders + /// + /// + private List GetOrders() => IsMtConnected ? ApiClient.GetOrders(OrderSelectSource.MODE_TRADES) : null; + protected override void OnTriggerRaised() + { + if(_lastOrders == null) + { + _lastOrders = GetOrders(); + return; + } + List currentOrders = GetOrders(); + OrderModifiedTypes omt = OrderModifiedTypes; + var mtModifiedOrders = currentOrders + .Select(co => new MtModifiedOrder(_lastOrders.FirstOrDefault(x => x.Ticket == co.Ticket), co)) + .ToList(); + List modifiedOrders = new List(); + modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.TakeProfit)); //If the takeprofit were changed between both calls + modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.StopLoss)); //If the stoploss were changed between both calls + modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.Operation)); //If an order changed from limit / stop order to an open order + if (modifiedOrders.Count > 0) + OrdersModified?.Invoke(this, new ModifiedOrdersEventArgs(modifiedOrders)); + _lastOrders = currentOrders; + } + private static IEnumerable GetMtModifiedOrdersWithModType(IEnumerable orders, OrderModifiedTypes globalSearchFlag, OrderModifiedTypes modifiedType) + => globalSearchFlag.HasFlag(modifiedType) ? orders.Where(o => o.ModifyType.HasFlag(modifiedType)) : new List(); + } +} \ No newline at end of file diff --git a/MtApi/Monitors/OrderModification/MtModifiedOrder.cs b/MtApi/Monitors/OrderModification/MtModifiedOrder.cs new file mode 100644 index 00000000..7bb82d0c --- /dev/null +++ b/MtApi/Monitors/OrderModification/MtModifiedOrder.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MtApi.Monitors +{ + public class MtModifiedOrder + { + /// + /// The order in its old state (before the changes) + /// + public MtOrder OldOrder { get; } + /// + /// The order in its new state (after the changes) + /// + public MtOrder NewOrder { get; } + /// + /// The changes found by this instance + /// + public OrderModifiedTypes ModifyType { get; private set; } + /// + /// Initializes an instance and compare the order in its old and new state + /// + /// The order in its old state (before the changes) + /// The order in its new state (after the changes) + public MtModifiedOrder(MtOrder oldOrder, MtOrder newOrder) + { + if (oldOrder != null && newOrder != null && oldOrder.Ticket != newOrder.Ticket) + throw new ArgumentException(nameof(oldOrder) + " and " + nameof(newOrder) + " need to have the same ticket id"); + OldOrder = oldOrder; + NewOrder = newOrder; + ModifyType = OrderModifiedTypes.None; + Compare(); + } + private void Compare() + { + if(NewOrder != null && OldOrder != null) + { + if (OldOrder.StopLoss != NewOrder.StopLoss) + ModifyType |= OrderModifiedTypes.StopLoss; + if (OldOrder.TakeProfit != NewOrder.TakeProfit) + ModifyType |= OrderModifiedTypes.TakeProfit; + if (OldOrder.Operation != NewOrder.Operation) + ModifyType |= OrderModifiedTypes.Operation; + } + } + } +} diff --git a/MtApi/Monitors/OrderModification/OrderModifiedTypes.cs b/MtApi/Monitors/OrderModification/OrderModifiedTypes.cs new file mode 100644 index 00000000..74c351b8 --- /dev/null +++ b/MtApi/Monitors/OrderModification/OrderModifiedTypes.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MtApi.Monitors +{ + [Flags] + public enum OrderModifiedTypes + { + None = 0x0, + TakeProfit = 1 << 0, + StopLoss = 1 << 1, + Operation = 1 << 2, + All = 7 + } +} diff --git a/MtApi/Monitors/readme.md b/MtApi/Monitors/readme.md new file mode 100644 index 00000000..e351d883 --- /dev/null +++ b/MtApi/Monitors/readme.md @@ -0,0 +1,66 @@ +## Monitors + +Monitors can be used to monitor different changes on Mt4 structs. + +## MtMonitorBase +This is the base class for monitoring extensions. If inherited `MtMonitorBase` needs an instance of `MtApiClient` and `IMonitorTrigger`. + +`SyncTrigger` (which can be set in the constructor or as Property) can be used to define whether the trigger should be started and stopped as well if `Start()` or `Stop()` will be called on an instance of a child class of `MtMonitorBase`. +Keep in mind: If an `IMonitorTrigger` will be used for several monitors, `SyncTrigger` set to `true` would cause that all monitors related to this trigger would stop: + +``` +var fooTrigger = new FooTrigger(); +var fooMonitor = new FooMonitor(apiClient, fooTrigger, true); +var barMonitor = new FooMonitor(apiClient, fooTrigger, false); + +fooTrigger.Start(); +barMonitor.Start(); +fooMonitor.Start(); + +fooMonitor.Stop(); //Because of SyncTrigger = true in the constructor of FooMonitor, fooTrigger.Stop() were triggered as well. Therefore barMonitor will not get any further triggers. +``` + +## IMonitorTrigger +An `IMonitorTrigger` is for defining when the monitor should check whether his conditions are met for invoking his event. + +There are already two `IMonitorTrigger`s which can be used: +### NewBarTrigger +Triggers when a new bar starts +### TimeElapsedTrigger +Triggers when a defined time elapsed + +## Default monitors: +There are already two different monitors defined. You can extend them or define new ones by inheriting from `MtMonitorBase`. + +### TradeMonitor +Can be used to get updates on new opened trades or closed trades. + +## ModifiedOrdersMonitor +Can be used to get updates on modified trades (takeprofit, stoploss, operation). + +`OrderModifiedTypes` defines which modifications should be monitored: + +1. `None` would cause no monitoring. But please use `Start()` and `Stop()` instead. +2. `TakeProfit` would cause observing whether the TakeProfit were changed. +3. `StopLoss` would cause observing whether the StopLoss were changed. +`Operation` would cause observing trades which changed from a stop / limit order to an open order. +4. `All` would cause observing all above defined. + +Because `OrderModifiedTypes` is defined with the Flag-Attribute, you can combine the above monitoring types with a pipe: `OrderModifiedTypes.TakeProfit | OrderModifiedTypes.StopLoss`. + +### Example +``` +var orderModifyMonitor = new ModifiedOrdersMonitor( + _apiClient, + new MtApi.Monitors.Triggers.TimeElapsedTrigger(TimeSpan.FromSeconds(1)), + OrderModifiedTypes.All, + true +); +orderModifyMonitor.OrdersModified += OrderModifyMonitor_OrdersModified; +orderModifyMonitor.Start(); + +private void OrderModifyMonitor_OrdersModified(object sender, ModifiedOrdersEventArgs e) +{ + //Receives the event +} +``` diff --git a/MtApi/MtApi.csproj b/MtApi/MtApi.csproj index 21130cc6..92bc2804 100755 --- a/MtApi/MtApi.csproj +++ b/MtApi/MtApi.csproj @@ -76,7 +76,11 @@ + + + +