Compare commits

...
11 Commits
19 changed files with 705 additions and 252 deletions
+35 -7
View File
@@ -52,24 +52,45 @@ namespace MTApiService
#endregion #endregion
} }
public enum LogLevel
{
Off,
Debug,
Info
}
public class LogConfigurator public class LogConfigurator
{ {
private const string LogFileNameExtension = "log"; private const string LogFileNameExtension = "log";
public static void Setup(string profileName) public static void Setup(string profileName)
{ {
#if (DEBUG)
const LogLevel logLevel = LogLevel.Debug;
#else
const LogLevel logLevel = LogLevel.Info;
#endif
Setup(profileName, logLevel);
}
public static void Setup(string profileName, LogLevel logLevel)
{
if (string.IsNullOrEmpty(profileName)) if (string.IsNullOrEmpty(profileName))
throw new ArgumentNullException(); throw new ArgumentNullException();
var hierarchy = (Hierarchy) LogManager.GetRepository(); var hierarchy = (Hierarchy) LogManager.GetRepository();
//check if logger is already configurated to avoid creation many empty logs files
if (hierarchy.Configured)
return;
var patternLayout = new PatternLayout var patternLayout = new PatternLayout
{ {
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline" ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
}; };
patternLayout.ActivateOptions(); patternLayout.ActivateOptions();
string filename = $"{DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss")}-{Process.GetCurrentProcess().Id}.{LogFileNameExtension}"; var filename = $"{DateTime.Now:yyyy-dd-M--HH-mm-ss}-{Process.GetCurrentProcess().Id}.{LogFileNameExtension}";
var roller = new RollingFileAppender var roller = new RollingFileAppender
{ {
@@ -84,12 +105,7 @@ namespace MTApiService
}; };
roller.ActivateOptions(); roller.ActivateOptions();
hierarchy.Root.AddAppender(roller); hierarchy.Root.AddAppender(roller);
hierarchy.Root.Level = ConvertLogLevel(logLevel);
#if (DEBUG)
hierarchy.Root.Level = Level.Debug;
#else
hierarchy.Root.Level = Level.Info;
#endif
hierarchy.Configured = true; hierarchy.Configured = true;
} }
@@ -100,5 +116,17 @@ namespace MTApiService
return new MtLog(type); return new MtLog(type);
} }
private static Level ConvertLogLevel(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Debug: return Level.Debug;
case LogLevel.Info: return Level.Info;
case LogLevel.Off: return Level.Off;
default:
throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
}
}
} }
} }
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.32.0")] [assembly: AssemblyVersion("1.0.33.0")]
[assembly: AssemblyFileVersion("1.0.32.0")] [assembly: AssemblyFileVersion("1.0.33.0")]
@@ -10,8 +10,13 @@ namespace MtApi.Monitors
Opened = opened; Opened = opened;
Closed = closed; Closed = closed;
} }
/// <summary>
/// Contains all newly opened orders since the last time the monitor checked the open orders.
/// </summary>
public List<MtOrder> Opened { get; private set; } public List<MtOrder> Opened { get; private set; }
/// <summary>
/// Contains all newly closed orders since the last time the monitor checked the open orders.
/// </summary>
public List<MtOrder> Closed { get; private set; } public List<MtOrder> Closed { get; private set; }
} }
} }
+113
View File
@@ -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
/// <summary>
/// ApiClient
/// </summary>
protected MtApiClient ApiClient { get; }
/// <summary>
/// Returns true if the <see cref="ApiClient"/> is connected.
/// </summary>
public bool IsMtConnected => ApiClient.ConnectionState == MtConnectionState.Connected;
/// <summary>
/// Returns the trigger which will be used to raise the monitoring call.
/// </summary>
public IMonitorTrigger MonitorTrigger { get; }
/// <summary>
/// Returns true if the Monitor is started.
/// </summary>
public bool IsStarted { get => _isStarted; }
/// <summary>
/// If true, the <see cref="MonitorTrigger"/> will be stopped or started automatically when <see cref="Start"/> or <see cref="Stop"/> will be called.
/// <para>CAUTION: If you use the MonitorTrigger for different Monitors, this will stop all monitors if you call stop and <see cref="SyncTrigger"/> is <c>true</c>.</para>
/// </summary>
public bool SyncTrigger { get => _syncTrigger; set => _syncTrigger = value; }
#endregion
#region ctor
/// <summary>
/// Default constructor for Monitors
/// </summary>
/// <param name="apiClient">The apiClient which will be used to work with.</param>
/// <param name="monitorTrigger">The trigger which lead this Monitor to do his work.</param>
/// <param name="syncTrigger">See property <see cref="SyncTrigger"/>.</param>
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
/// <summary>
/// Let the monitor listen to the <see cref="MonitorTrigger"/>.
/// </summary>
public virtual void Start()
{
if (!_isStarted)
{
ApiClient.ConnectionStateChanged += ApiClientConnectionStateChanged;
MonitorTrigger.Raised += MonitorTriggerRaised;
_isStarted = true;
OnStart();
if (SyncTrigger)
MonitorTrigger.Start();
}
}
/// <summary>
/// Let the monitor stop listening to the <see cref="MonitorTrigger"/>.
/// </summary>
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();
}
/// <summary>
/// Will be called when <see cref="Start"/> will be called.
/// </summary>
protected virtual void OnStart() { }
/// <summary>
/// Will be called when <see cref="Stop"/> will be called.
/// </summary>
protected virtual void OnStop() { }
/// <summary>
/// Will be called when the <see cref="ApiClient"/> is successfully connected.
/// </summary>
protected virtual void OnMtConnected() { }
/// <summary>
/// Will be called when <see cref="ApiClient"/> is disconnected.
/// </summary>
protected virtual void OnMtDisconnected() { }
/// <summary>
/// Will be called when the <see cref="MonitorTrigger"/> raised.
/// </summary>
protected abstract void OnTriggerRaised();
#endregion
}
}
@@ -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
{
/// <summary>
/// Returns a list of all modified orders
/// </summary>
public List<MtModifiedOrder> ModifiedOrders { get; }
public ModifiedOrdersEventArgs(List<MtModifiedOrder> modifiedOrders)
{
ModifiedOrders = modifiedOrders;
}
}
}
@@ -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<MtOrder> _lastOrders = null;
#endregion
#region Properties
/// <summary>
/// Define on which types of modification this monitor should raise <see cref="OrdersModified"/>
/// </summary>
public OrderModifiedTypes OrderModifiedTypes { get; set; }
#endregion
#region Events
/// <summary>
/// Will be raised when this monitor detects changes on open orders
/// </summary>
public event EventHandler<ModifiedOrdersEventArgs> 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
/// <summary>
/// Requests all current open orders
/// </summary>
/// <returns></returns>
private List<MtOrder> GetOrders() => IsMtConnected ? ApiClient.GetOrders(OrderSelectSource.MODE_TRADES) : null;
protected override void OnTriggerRaised()
{
if(_lastOrders == null)
{
_lastOrders = GetOrders();
return;
}
List<MtOrder> currentOrders = GetOrders();
OrderModifiedTypes omt = OrderModifiedTypes;
var mtModifiedOrders = currentOrders
.Select(co => new MtModifiedOrder(_lastOrders.FirstOrDefault(x => x.Ticket == co.Ticket), co))
.ToList();
List<MtModifiedOrder> modifiedOrders = new List<MtModifiedOrder>();
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<MtModifiedOrder> GetMtModifiedOrdersWithModType(IEnumerable<MtModifiedOrder> orders, OrderModifiedTypes globalSearchFlag, OrderModifiedTypes modifiedType)
=> globalSearchFlag.HasFlag(modifiedType) ? orders.Where(o => o.ModifyType.HasFlag(modifiedType)) : new List<MtModifiedOrder>();
}
}
@@ -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
{
/// <summary>
/// The order in its old state (before the changes)
/// </summary>
public MtOrder OldOrder { get; }
/// <summary>
/// The order in its new state (after the changes)
/// </summary>
public MtOrder NewOrder { get; }
/// <summary>
/// The changes found by this instance
/// </summary>
public OrderModifiedTypes ModifyType { get; private set; }
/// <summary>
/// Initializes an instance and compare the order in its old and new state
/// </summary>
/// <param name="oldOrder">The order in its old state (before the changes)</param>
/// <param name="newOrder">The order in its new state (after the changes)</param>
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;
}
}
}
}
@@ -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
}
}
+9 -47
View File
@@ -1,56 +1,18 @@
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors namespace MtApi.Monitors
{ {
public class TimeframeTradeMonitor : TradeMonitor public class TimeframeTradeMonitor : TradeMonitor
{ {
#region Fields /// <summary>
private volatile bool _isStarted; /// Constructor for initializing a new instance with a trigger instance of <see cref="NewBarTrigger"/>.
#endregion /// <para>SyncTrigger is set to true by default</para>
/// </summary>
#region ctor /// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
public TimeframeTradeMonitor(MtApiClient apiClient) public TimeframeTradeMonitor(MtApiClient apiClient)
: base(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
} }
} }
+27 -70
View File
@@ -1,89 +1,46 @@
using System.Timers; using System;
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors namespace MtApi.Monitors
{ {
public class TimerTradeMonitor : TradeMonitor public class TimerTradeMonitor : TradeMonitor
{ {
#region Fields #region Fields
private readonly Timer _timer = new Timer(); private readonly TimeElapsedTrigger _timeElapsedTrigger;
#endregion #endregion
#region ctor #region Properties
public TimerTradeMonitor(MtApiClient apiClient) /// <summary>
: base(apiClient) /// Interval for raising the trigger
{ /// </summary>
_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.
public double Interval public double Interval
{ {
get { return _timer.Interval; } get => _timeElapsedTrigger.Interval.TotalMilliseconds;
set { _timer.Interval = value; } 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
{
get { return _timer.Enabled; }
} }
#endregion #endregion
#region Protected Methods #region ctors
protected override void OnStart() /// <summary>
/// Constructor for initializing a new instance with a default <see cref="Interval"/> of 10 seconds.
/// <para>SyncTrigger is set to true by default</para>
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
public TimerTradeMonitor(MtApiClient apiClient)
: this(apiClient, new TimeElapsedTrigger(TimeSpan.FromSeconds(10)))
{ {
if (IsMtConnected) SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
{
_timer.Start();
}
} }
/// <summary>
protected override void OnStop() /// Constructor for initializing a new instance with a custom instance of <see cref="TimeElapsedTrigger"/>.
/// <para>SyncTrigger is set to false by default</para>
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
/// <param name="timeElapsedTrigger">The custom instance of <see cref="TimeElapsedTrigger"/> which will be used to trigger this instance of <see cref="TradeMonitor"/>.</param>
public TimerTradeMonitor(MtApiClient apiClient, TimeElapsedTrigger timeElapsedTrigger)
: base(apiClient, timeElapsedTrigger)
{ {
_timer.Stop(); _timeElapsedTrigger = timeElapsedTrigger;
}
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 #endregion
} }
+42 -114
View File
@@ -1,63 +1,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors namespace MtApi.Monitors
{ {
public abstract class TradeMonitor public class TradeMonitor : MtMonitorBase
{ {
#region Fields #region Fields
private readonly MtApiClient _apiClient;
private List<MtOrder> _prevOrders; private List<MtOrder> _prevOrders;
private readonly object _locker = new object(); private readonly object _locker = new object();
#endregion #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 #region Events
// //
// Summary: // Summary:
@@ -65,17 +20,34 @@ namespace MtApi.Monitors
public event EventHandler<AvailabilityOrdersEventArgs> AvailabilityOrdersChanged; public event EventHandler<AvailabilityOrdersEventArgs> AvailabilityOrdersChanged;
#endregion #endregion
#region Protected Methods #region ctor
/// <summary>
/// Constructor for initializing an instance of <see cref="TradeMonitor"/>.
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
/// <param name="monitorTrigger">The custom instance of <see cref="IMonitorTrigger"/> which will be used to trigger this instance of <see cref="TradeMonitor"/>.</param>
public TradeMonitor(MtApiClient apiClient, IMonitorTrigger monitorTrigger) : base(apiClient, monitorTrigger) { }
#endregion
protected abstract void OnStart(); protected override void OnMtConnected()
protected abstract void OnStop(); {
InitialCheck();
base.OnMtConnected();
}
protected override void OnStart()
{
if (IsMtConnected)
InitialCheck();
base.OnStart();
}
protected abstract void OnMtConnected(); protected override void OnTriggerRaised()
protected abstract void OnMtDisconnected(); {
if (IsMtConnected)
Check();
}
public bool IsMtConnected => _apiClient.ConnectionState == MtConnectionState.Connected; private void Check()
protected void Check()
{ {
try try
{ {
@@ -90,92 +62,48 @@ namespace MtApi.Monitors
//TODO: write error to log //TODO: write error to log
} }
} }
#endregion private void InitialCheck()
{
lock (_locker)
_prevOrders = null;
#region Private Methods Task.Factory.StartNew(Check);
}
private void CheckOrders() private void CheckOrders()
{ {
var openedOrders = new List<MtOrder>(); var openedOrders = new List<MtOrder>();
var closedOrders = new List<MtOrder>(); var closedOrders = new List<MtOrder>();
List<MtOrder> prevOrders;
// get current orders from MetaTrader // get current orders from MetaTrader
var tradesOrders = _apiClient.GetOrders(OrderSelectSource.MODE_TRADES); var tradesOrders = ApiClient.GetOrders(OrderSelectSource.MODE_TRADES);
List<MtOrder> prevOrders; lock (_locker)
lock(_locker)
{
prevOrders = _prevOrders; prevOrders = _prevOrders;
}
if (prevOrders != null) //skip checking on first load orders if (prevOrders != null) //skip checking on first load orders
{ {
//check open orders //check open orders
foreach (var order in tradesOrders) openedOrders = tradesOrders.Where(to => prevOrders.Find(a => a.Ticket == to.Ticket) == null).ToList();
{
if (prevOrders.Find(a => a.Ticket == order.Ticket) == null)
{
openedOrders.Add(order);
}
}
//check closed orders //check closed orders
var closeOrdersTemp = new List<MtOrder>(); var closeOrdersTemp = prevOrders.Where(po => tradesOrders.Find(a => a.Ticket == po.Ticket) == null).ToList();
foreach (var order in prevOrders)
{
if (tradesOrders.Find(a => a.Ticket == order.Ticket) == null)
{
closeOrdersTemp.Add(order);
}
}
if (closeOrdersTemp.Count > 0) if (closeOrdersTemp.Count > 0)
{ {
//get closed orders from history with actual values //get closed orders from history with actual values
var historyOrders = _apiClient.GetOrders(OrderSelectSource.MODE_HISTORY); var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
foreach (var order in closeOrdersTemp) closedOrders = closeOrdersTemp.Where(cot => historyOrders.Find(a => a.Ticket == cot.Ticket) != null).ToList();
{
var closedOrder = historyOrders.Find(a => a.Ticket == order.Ticket);
if (closedOrder != null)
{
closedOrders.Add(closedOrder);
}
}
} }
} }
lock(_locker) lock (_locker)
{
_prevOrders = tradesOrders; _prevOrders = tradesOrders;
}
if (openedOrders.Count > 0 || closedOrders.Count > 0) if (openedOrders.Count > 0 || closedOrders.Count > 0)
{ {
AvailabilityOrdersChanged?.Invoke(this, new AvailabilityOrdersEventArgs(openedOrders, closedOrders)); 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
} }
} }
@@ -0,0 +1,27 @@
using System;
namespace MtApi.Monitors.Triggers
{
/// <summary>
/// Interface for triggers which can be used to trigger a <see cref="MtMonitorBase"/>.
/// </summary>
public interface IMonitorTrigger
{
/// <summary>
/// Event will be called if the trigger raised.
/// </summary>
event EventHandler Raised;
/// <summary>
/// Returns whether the trigger is started
/// </summary>
bool IsStarted { get; }
/// <summary>
/// Stops the trigger and prevents further calls of the <see cref="Raised"/> event.
/// </summary>
void Stop();
/// <summary>
/// Starts the trigger.
/// </summary>
void Start();
}
}
+68
View File
@@ -0,0 +1,68 @@
using System;
namespace MtApi.Monitors.Triggers
{
/// <summary>
/// Raises the <see cref="Raised"/> event if a bar is closed and a new one started.
/// </summary>
public class NewBarTrigger : IMonitorTrigger
{
#region Fields
private volatile bool _isStarted;
private readonly MtApiClient _apiClient;
#endregion
#region Properties
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public bool IsStarted => _isStarted;
#endregion
#region Events
/// <summary>
/// Event will be called if the trigger raised.
/// </summary>
public event EventHandler Raised;
#endregion
#region ctor
public NewBarTrigger(MtApiClient apiClient)
{
_apiClient = apiClient;
_apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
}
#endregion
#region Public methods
/// <summary>
/// Starts the trigger
/// </summary>
public void Start() => SetIsStarted(true);
/// <summary>
/// Stops the trigger
/// </summary>
public void Stop() => SetIsStarted(false);
#endregion
#region Private methods
private void _apiClient_OnLastTimeBar(object sender, TimeBarArgs e)
{
if (_isStarted)
Raised?.Invoke(this, EventArgs.Empty);
}
private void SetIsStarted(bool value)
{
if (value != _isStarted)
{
_isStarted = value;
if (value)
_apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
else
_apiClient.OnLastTimeBar -= _apiClient_OnLastTimeBar;
}
}
#endregion
}
}
@@ -0,0 +1,74 @@
using System;
using System.Timers;
namespace MtApi.Monitors.Triggers
{
public class TimeElapsedTrigger : IMonitorTrigger
{
#region Fields
readonly Timer _timer;
#endregion
#region Properties
/// <summary>
/// Interval for raising the trigger
/// </summary>
public TimeSpan Interval
{
get => TimeSpan.FromMilliseconds(_timer.Interval);
set => _timer.Interval = value.TotalMilliseconds;
}
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public bool IsStarted => _timer.Enabled;
/// <summary>
/// If true, the trigger will raise continuosly after elapsed <see cref="Interval"/>, otherwise the trigger will raise only once after elapsed <see cref="Interval"/>.
/// </summary>
public bool AutoReset { get => _timer.AutoReset; set => _timer.AutoReset = value; }
#endregion
#region Events
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public event EventHandler Raised;
#endregion
#region ctor
/// <summary>
/// Constructor for initializing TimeElapsedTrigger
/// </summary>
/// <param name="time">Defines the interval for raising the event.</param>
/// <param name="autoReset">If true, the trigger will raise continuosly after elapsed <see cref="Interval"/>, otherwise the trigger will raise only once after elapsed <see cref="Interval"/>.</param>
public TimeElapsedTrigger(TimeSpan time, bool autoReset = true)
{
_timer = new Timer(time.TotalMilliseconds);
_timer.Elapsed += _timer_Elapsed;
AutoReset = autoReset;
}
#endregion
#region Public methods
/// <summary>
/// Starts the trigger
/// </summary>
public void Start() => _timer.Start();
/// <summary>
/// Stops the trigger
/// </summary>
public void Stop() => _timer.Stop();
#endregion
#region private methods
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Elapsed -= _timer_Elapsed;
Raised?.Invoke(this, EventArgs.Empty);
_timer.Elapsed += _timer_Elapsed;
}
#endregion
}
}
+66
View File
@@ -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.
4. `Operation` would cause observing trades which changed from a stop / limit order to an open order.
5. `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
}
```
+8
View File
@@ -76,6 +76,14 @@
<Compile Include="EnumTerminalInfoInteger.cs" /> <Compile Include="EnumTerminalInfoInteger.cs" />
<Compile Include="FlagFontStyle.cs" /> <Compile Include="FlagFontStyle.cs" />
<Compile Include="Monitors\AvailabilityOrdersEventArgs.cs" /> <Compile Include="Monitors\AvailabilityOrdersEventArgs.cs" />
<Compile Include="Monitors\OrderModification\ModifiedOrdersEventArgs.cs" />
<Compile Include="Monitors\OrderModification\ModifiedOrdersMonitor.cs" />
<Compile Include="Monitors\OrderModification\MtModifiedOrder.cs" />
<Compile Include="Monitors\MtMonitorBase.cs" />
<Compile Include="Monitors\OrderModification\OrderModifiedTypes.cs" />
<Compile Include="Monitors\Triggers\IMonitorTrigger.cs" />
<Compile Include="Monitors\Triggers\NewBarTrigger.cs" />
<Compile Include="Monitors\Triggers\TimeElapsedTrigger.cs" />
<Compile Include="MqlRates.cs" /> <Compile Include="MqlRates.cs" />
<Compile Include="MqlTick.cs" /> <Compile Include="MqlTick.cs" />
<Compile Include="MtChartEvent.cs" /> <Compile Include="MtChartEvent.cs" />
+62 -1
View File
@@ -26,6 +26,8 @@ namespace MtApi
#endregion #endregion
#region Private Fields #region Private Fields
private static readonly MtLog Log = LogConfigurator.GetLogger(typeof(MtApiClient));
private MtClient _client; private MtClient _client;
private readonly object _locker = new object(); private readonly object _locker = new object();
private MtConnectionState _connectionState = MtConnectionState.Disconnected; private MtConnectionState _connectionState = MtConnectionState.Disconnected;
@@ -37,7 +39,12 @@ namespace MtApi
public MtApiClient() public MtApiClient()
{ {
LogConfigurator.Setup(LogProfileName); #if (DEBUG)
const LogLevel logLevel = LogLevel.Debug;
#else
const LogLevel logLevel = LogLevel.Info;
#endif
LogConfigurator.Setup(LogProfileName, logLevel);
} }
#endregion #endregion
@@ -49,6 +56,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param> ///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(string host, int port) public void BeginConnect(string host, int port)
{ {
Log.Info($"BeginConnect: host = {host}, port = {port}");
Task.Factory.StartNew(() => Connect(host, port)); Task.Factory.StartNew(() => Connect(host, port));
} }
@@ -58,6 +66,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param> ///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(int port) public void BeginConnect(int port)
{ {
Log.Info($"BeginConnect: port = {port}");
Task.Factory.StartNew(() => Connect(port)); Task.Factory.StartNew(() => Connect(port));
} }
@@ -66,6 +75,7 @@ namespace MtApi
///</summary> ///</summary>
public void BeginDisconnect() public void BeginDisconnect()
{ {
Log.Info("BeginDisconnect called.");
Task.Factory.StartNew(() => Disconnect(false)); Task.Factory.StartNew(() => Disconnect(false));
} }
@@ -251,6 +261,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic, DateTime expiration, Color arrowColor) , string comment, int magic, DateTime expiration, Color arrowColor)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}, expiration = {expiration}, arrowColor = {arrowColor}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -271,6 +283,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic, DateTime expiration) , string comment, int magic, DateTime expiration)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}, expiration = {expiration}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -290,6 +304,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic) , string comment, int magic)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -308,6 +324,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment) , string comment)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -324,6 +342,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit) public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -339,6 +359,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, string price, int slippage, double stoploss, double takeprofit) public int OrderSend(string symbol, TradeOperation cmd, double volume, string price, int slippage, double stoploss, double takeprofit)
{ {
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
double dPrice; double dPrice;
return double.TryParse(price, out dPrice) ? return double.TryParse(price, out dPrice) ?
OrderSend(symbol, cmd, volume, dPrice, slippage, stoploss, takeprofit) : 0; OrderSend(symbol, cmd, volume, dPrice, slippage, stoploss, takeprofit) : 0;
@@ -346,6 +368,8 @@ namespace MtApi
public int OrderSendBuy(string symbol, double volume, int slippage) public int OrderSendBuy(string symbol, double volume, int slippage)
{ {
Log.Debug($"OrderSendBuy: symbol = {symbol}, volume = {volume}, slippage = {slippage}");
return OrderSendBuy(symbol, volume, slippage, 0, 0, null, 0); return OrderSendBuy(symbol, volume, slippage, 0, 0, null, 0);
} }
@@ -366,6 +390,8 @@ namespace MtApi
public int OrderSendBuy(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic) public int OrderSendBuy(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic)
{ {
Log.Debug($"OrderSendBuy: symbol = {symbol}, volume = {volume}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -382,6 +408,8 @@ namespace MtApi
public int OrderSendSell(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic) public int OrderSendSell(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic)
{ {
Log.Debug($"OrderSendSell: symbol = {symbol}, volume = {volume}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{ {
Symbol = symbol, Symbol = symbol,
@@ -398,6 +426,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, double price, int slippage, Color color) public bool OrderClose(int ticket, double lots, double price, int slippage, Color color)
{ {
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, price = {price}, slippage = {slippage}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest var response = SendRequest<ResponseBase>(new OrderCloseRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -411,6 +441,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, double price, int slippage) public bool OrderClose(int ticket, double lots, double price, int slippage)
{ {
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, price = {price}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest var response = SendRequest<ResponseBase>(new OrderCloseRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -423,6 +455,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, int slippage) public bool OrderClose(int ticket, double lots, int slippage)
{ {
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest var response = SendRequest<ResponseBase>(new OrderCloseRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -434,6 +468,8 @@ namespace MtApi
public bool OrderClose(int ticket, int slippage) public bool OrderClose(int ticket, int slippage)
{ {
Log.Debug($"OrderClose: ticket = {ticket}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest var response = SendRequest<ResponseBase>(new OrderCloseRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -444,6 +480,8 @@ namespace MtApi
public bool OrderCloseBy(int ticket, int opposite, Color color) public bool OrderCloseBy(int ticket, int opposite, Color color)
{ {
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderCloseByRequest var response = SendRequest<ResponseBase>(new OrderCloseByRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -455,6 +493,8 @@ namespace MtApi
public bool OrderCloseBy(int ticket, int opposite) public bool OrderCloseBy(int ticket, int opposite)
{ {
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}");
var response = SendRequest<ResponseBase>(new OrderCloseByRequest var response = SendRequest<ResponseBase>(new OrderCloseByRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -465,6 +505,8 @@ namespace MtApi
public bool OrderDelete(int ticket, Color color) public bool OrderDelete(int ticket, Color color)
{ {
Log.Debug($"OrderDelete: ticket = {ticket}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderDeleteRequest var response = SendRequest<ResponseBase>(new OrderDeleteRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -475,6 +517,8 @@ namespace MtApi
public bool OrderDelete(int ticket) public bool OrderDelete(int ticket)
{ {
Log.Debug($"OrderDelete: ticket = {ticket}");
var response = SendRequest<ResponseBase>(new OrderDeleteRequest var response = SendRequest<ResponseBase>(new OrderDeleteRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -484,6 +528,8 @@ namespace MtApi
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration, Color arrowColor) public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration, Color arrowColor)
{ {
Log.Debug($"OrderModify: ticket = {ticket}, price = {price}, stoploss = {stoploss}, takeprofit = {takeprofit}, expiration = {expiration}, arrowColor = {arrowColor}");
var response = SendRequest<ResponseBase>(new OrderModifyRequest var response = SendRequest<ResponseBase>(new OrderModifyRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -498,6 +544,8 @@ namespace MtApi
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration) public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration)
{ {
Log.Debug($"OrderModify: ticket = {ticket}, price = {price}, stoploss = {stoploss}, takeprofit = {takeprofit}, expiration = {expiration}");
var response = SendRequest<ResponseBase>(new OrderModifyRequest var response = SendRequest<ResponseBase>(new OrderModifyRequest
{ {
Ticket = ticket, Ticket = ticket,
@@ -516,6 +564,8 @@ namespace MtApi
public bool OrderSelect(int index, OrderSelectMode select, OrderSelectSource pool) public bool OrderSelect(int index, OrderSelectMode select, OrderSelectSource pool)
{ {
Log.Debug($"OrderSelect: index = {index}, select = {select}, pool = {pool}");
var commandParameters = new ArrayList { index, (int)select, (int)pool }; var commandParameters = new ArrayList { index, (int)select, (int)pool };
return SendCommand<bool>(MtCommandType.OrderSelect, commandParameters); return SendCommand<bool>(MtCommandType.OrderSelect, commandParameters);
} }
@@ -2894,6 +2944,8 @@ namespace MtApi
{ {
client.Dispose(); client.Dispose();
message = string.IsNullOrEmpty(client.Host) ? $"Failed connection to localhost:{client.Port}. {e.Message}" : $"Failed connection to {client.Host}:{client.Port}. {e.Message}"; message = string.IsNullOrEmpty(client.Host) ? $"Failed connection to localhost:{client.Port}. {e.Message}" : $"Failed connection to {client.Host}:{client.Port}. {e.Message}";
Log.Warn(message);
} }
if (state == MtConnectionState.Connected) if (state == MtConnectionState.Connected)
@@ -2906,6 +2958,8 @@ namespace MtApi
_client.ServerFailed += _client_ServerFailed; _client.ServerFailed += _client_ServerFailed;
_client.MtEventReceived += _client_MtEventReceived; _client.MtEventReceived += _client_MtEventReceived;
message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}"; message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}";
Log.Info(message);
} }
_connectionState = state; _connectionState = state;
@@ -2973,6 +3027,7 @@ namespace MtApi
_connectionState = state; _connectionState = state;
} }
Log.Info(message);
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message)); ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message));
} }
@@ -2984,6 +3039,7 @@ namespace MtApi
var client = Client; var client = Client;
if (client == null) if (client == null)
{ {
Log.Warn("SendCommand: No connection");
throw new MtConnectionException("No connection"); throw new MtConnectionException("No connection");
} }
@@ -2993,16 +3049,19 @@ namespace MtApi
} }
catch (CommunicationException ex) catch (CommunicationException ex)
{ {
Log.Warn($"SendCommand: {ex.Message}");
throw new MtConnectionException(ex.Message, ex); throw new MtConnectionException(ex.Message, ex);
} }
if (response == null) if (response == null)
{ {
Log.Warn("SendCommand: Response from MetaTrader is null");
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null"); throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
} }
if (response.ErrorCode != 0) if (response.ErrorCode != 0)
{ {
Log.Warn($"SendCommand: ErrorCode = {response.ErrorCode}. {response}");
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ToString()); throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ToString());
} }
@@ -3026,12 +3085,14 @@ namespace MtApi
if (res == null) if (res == null)
{ {
Log.Warn("SendRequest: Response from MetaTrader is null");
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null"); throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
} }
var response = JsonConvert.DeserializeObject<T>(res); var response = JsonConvert.DeserializeObject<T>(res);
if (response.ErrorCode != 0) if (response.ErrorCode != 0)
{ {
Log.Warn($"SendRequest: ErrorCode = {response.ErrorCode}. {response}");
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ErrorMessage); throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ErrorMessage);
} }
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.41.0")] [assembly: AssemblyVersion("1.0.42.0")]
[assembly: AssemblyFileVersion("1.0.41.0")] [assembly: AssemblyFileVersion("1.0.42.0")]