mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 02:57:56 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9eedf15e9e | |||
| 373bfe4997 | |||
| 0cd8edb933 | |||
| a66f18c2b3 | |||
| 71964c3303 | |||
| 4e7f8b93f4 | |||
| 5715e7e2b8 | |||
| 833ce1f192 | |||
| 724162f29d | |||
| 739567d871 | |||
| a12ddba765 | |||
| 9a5acac2db | |||
| 7a776de8d3 | |||
| ce7953eee0 | |||
| 93aed4e44c | |||
| 4c8c3b8766 | |||
| 73ebde8b6b | |||
| e33ba5b51f | |||
| a0a4263e24 | |||
| 5d18dd4ad3 | |||
| 03ff1f9176 | |||
| f376b4e0e5 | |||
| fc54b5dd4a | |||
| dd05804082 | |||
| 4349eb3538 | |||
| e0daf9a82e | |||
| 3997b6df74 | |||
| abfe1a281a |
@@ -208,6 +208,16 @@ _DLLAPI int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates value
|
||||
}, err, 0);
|
||||
}
|
||||
|
||||
_DLLAPI bool _stdcall sendErrorResponse(int expertHandle, int code, wchar_t* message, wchar_t* err)
|
||||
{
|
||||
return Execute<bool>([&expertHandle, &code, message]() {
|
||||
MtResponseString^ res = gcnew MtResponseString(gcnew String(message));
|
||||
res->ErrorCode = code;
|
||||
MtAdapter::GetInstance()->SendResponse(expertHandle, res);
|
||||
return true;
|
||||
}, err, false);
|
||||
}
|
||||
|
||||
//----------- get values -------------------------------
|
||||
|
||||
_DLLAPI int _stdcall getCommandType(int expertHandle, int* res, wchar_t* err)
|
||||
|
||||
@@ -52,24 +52,45 @@ namespace MTApiService
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
Off,
|
||||
Debug,
|
||||
Info
|
||||
}
|
||||
|
||||
public class LogConfigurator
|
||||
{
|
||||
private const string LogFileNameExtension = "log";
|
||||
|
||||
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))
|
||||
throw new ArgumentNullException();
|
||||
|
||||
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
|
||||
{
|
||||
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
|
||||
};
|
||||
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
|
||||
{
|
||||
@@ -84,12 +105,7 @@ namespace MTApiService
|
||||
};
|
||||
roller.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(roller);
|
||||
|
||||
#if (DEBUG)
|
||||
hierarchy.Root.Level = Level.Debug;
|
||||
#else
|
||||
hierarchy.Root.Level = Level.Info;
|
||||
#endif
|
||||
hierarchy.Root.Level = ConvertLogLevel(logLevel);
|
||||
hierarchy.Configured = true;
|
||||
}
|
||||
|
||||
@@ -100,5 +116,17 @@ namespace MTApiService
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.31.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.31.0")]
|
||||
[assembly: AssemblyVersion("1.0.33.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.33.0")]
|
||||
@@ -10,8 +10,13 @@ namespace MtApi.Monitors
|
||||
Opened = opened;
|
||||
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; }
|
||||
/// <summary>
|
||||
/// Contains all newly closed orders since the last time the monitor checked the open orders.
|
||||
/// </summary>
|
||||
public List<MtOrder> Closed { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,18 @@
|
||||
|
||||
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)
|
||||
/// <summary>
|
||||
/// Constructor for initializing a new instance with a trigger instance of <see cref="NewBarTrigger"/>.
|
||||
/// <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 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +1,47 @@
|
||||
using System.Timers;
|
||||
using System;
|
||||
using MtApi.Monitors.Triggers;
|
||||
|
||||
namespace MtApi.Monitors
|
||||
{
|
||||
public class TimerTradeMonitor : TradeMonitor
|
||||
{
|
||||
#region Fields
|
||||
private readonly Timer _timer = new Timer();
|
||||
private readonly TimeElapsedTrigger _timeElapsedTrigger;
|
||||
#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.
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Interval for raising the trigger
|
||||
/// </summary>
|
||||
public double Interval
|
||||
{
|
||||
get { return _timer.Interval; }
|
||||
set { _timer.Interval = 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; }
|
||||
get => _timeElapsedTrigger.Interval.TotalMilliseconds;
|
||||
set => _timeElapsedTrigger.Interval = TimeSpan.FromMilliseconds(value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
protected override void OnStart()
|
||||
#region ctors
|
||||
/// <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)
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
/// <summary>
|
||||
/// 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();
|
||||
}
|
||||
|
||||
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
|
||||
_timeElapsedTrigger = timeElapsedTrigger;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-116
@@ -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<MtOrder> _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,34 @@ namespace MtApi.Monitors
|
||||
public event EventHandler<AvailabilityOrdersEventArgs> AvailabilityOrdersChanged;
|
||||
#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 abstract void OnStop();
|
||||
protected override void OnMtConnected()
|
||||
{
|
||||
InitialCheck();
|
||||
base.OnMtConnected();
|
||||
}
|
||||
protected override void OnStart()
|
||||
{
|
||||
if (IsMtConnected)
|
||||
InitialCheck();
|
||||
base.OnStart();
|
||||
}
|
||||
|
||||
protected abstract void OnMtConnected();
|
||||
protected abstract void OnMtDisconnected();
|
||||
|
||||
public bool IsMtConnected => _apiClient.ConnectionState == MtConnectionState.Connected;
|
||||
|
||||
protected void Check()
|
||||
protected override void OnTriggerRaised()
|
||||
{
|
||||
if (IsMtConnected)
|
||||
Check();
|
||||
}
|
||||
|
||||
private void Check()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -90,92 +62,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<MtOrder>();
|
||||
var closedOrders = new List<MtOrder>();
|
||||
List<MtOrder> prevOrders;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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<MtOrder>();
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
@@ -76,6 +76,14 @@
|
||||
<Compile Include="EnumTerminalInfoInteger.cs" />
|
||||
<Compile Include="FlagFontStyle.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="MqlTick.cs" />
|
||||
<Compile Include="MtChartEvent.cs" />
|
||||
|
||||
+62
-1
@@ -26,6 +26,8 @@ namespace MtApi
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private static readonly MtLog Log = LogConfigurator.GetLogger(typeof(MtApiClient));
|
||||
|
||||
private MtClient _client;
|
||||
private readonly object _locker = new object();
|
||||
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
|
||||
@@ -37,7 +39,12 @@ namespace MtApi
|
||||
|
||||
public MtApiClient()
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
#if (DEBUG)
|
||||
const LogLevel logLevel = LogLevel.Debug;
|
||||
#else
|
||||
const LogLevel logLevel = LogLevel.Info;
|
||||
#endif
|
||||
LogConfigurator.Setup(LogProfileName, logLevel);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -49,6 +56,7 @@ namespace MtApi
|
||||
///<param name="port">Port of host connection (default 8222) </param>
|
||||
public void BeginConnect(string host, int port)
|
||||
{
|
||||
Log.Info($"BeginConnect: host = {host}, port = {port}");
|
||||
Task.Factory.StartNew(() => Connect(host, port));
|
||||
}
|
||||
|
||||
@@ -58,6 +66,7 @@ namespace MtApi
|
||||
///<param name="port">Port of host connection (default 8222) </param>
|
||||
public void BeginConnect(int port)
|
||||
{
|
||||
Log.Info($"BeginConnect: port = {port}");
|
||||
Task.Factory.StartNew(() => Connect(port));
|
||||
}
|
||||
|
||||
@@ -66,6 +75,7 @@ namespace MtApi
|
||||
///</summary>
|
||||
public void BeginDisconnect()
|
||||
{
|
||||
Log.Info("BeginDisconnect called.");
|
||||
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
|
||||
, 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
|
||||
{
|
||||
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
|
||||
, 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
|
||||
{
|
||||
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
|
||||
, 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
|
||||
{
|
||||
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
|
||||
, 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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
|
||||
|
||||
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
|
||||
|
||||
double dPrice;
|
||||
return double.TryParse(price, out dPrice) ?
|
||||
OrderSend(symbol, cmd, volume, dPrice, slippage, stoploss, takeprofit) : 0;
|
||||
@@ -346,6 +368,8 @@ namespace MtApi
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -366,6 +390,8 @@ namespace MtApi
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log.Debug($"OrderSendSell: symbol = {symbol}, volume = {volume}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
|
||||
|
||||
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
|
||||
{
|
||||
Symbol = symbol,
|
||||
@@ -398,6 +426,8 @@ namespace MtApi
|
||||
|
||||
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
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -411,6 +441,8 @@ namespace MtApi
|
||||
|
||||
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
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -423,6 +455,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderClose(int ticket, double lots, int slippage)
|
||||
{
|
||||
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, slippage = {slippage}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderCloseRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -434,6 +468,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderClose(int ticket, int slippage)
|
||||
{
|
||||
Log.Debug($"OrderClose: ticket = {ticket}, slippage = {slippage}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderCloseRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -444,6 +480,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderCloseBy(int ticket, int opposite, Color color)
|
||||
{
|
||||
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}, color = {color}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderCloseByRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -455,6 +493,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderCloseBy(int ticket, int opposite)
|
||||
{
|
||||
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderCloseByRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -465,6 +505,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderDelete(int ticket, Color color)
|
||||
{
|
||||
Log.Debug($"OrderDelete: ticket = {ticket}, color = {color}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderDeleteRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -475,6 +517,8 @@ namespace MtApi
|
||||
|
||||
public bool OrderDelete(int ticket)
|
||||
{
|
||||
Log.Debug($"OrderDelete: ticket = {ticket}");
|
||||
|
||||
var response = SendRequest<ResponseBase>(new OrderDeleteRequest
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -484,6 +528,8 @@ namespace MtApi
|
||||
|
||||
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
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -498,6 +544,8 @@ namespace MtApi
|
||||
|
||||
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
|
||||
{
|
||||
Ticket = ticket,
|
||||
@@ -516,6 +564,8 @@ namespace MtApi
|
||||
|
||||
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 };
|
||||
return SendCommand<bool>(MtCommandType.OrderSelect, commandParameters);
|
||||
}
|
||||
@@ -2894,6 +2944,8 @@ namespace MtApi
|
||||
{
|
||||
client.Dispose();
|
||||
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)
|
||||
@@ -2906,6 +2958,8 @@ namespace MtApi
|
||||
_client.ServerFailed += _client_ServerFailed;
|
||||
_client.MtEventReceived += _client_MtEventReceived;
|
||||
message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}";
|
||||
|
||||
Log.Info(message);
|
||||
}
|
||||
|
||||
_connectionState = state;
|
||||
@@ -2973,6 +3027,7 @@ namespace MtApi
|
||||
_connectionState = state;
|
||||
}
|
||||
|
||||
Log.Info(message);
|
||||
|
||||
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message));
|
||||
}
|
||||
@@ -2984,6 +3039,7 @@ namespace MtApi
|
||||
var client = Client;
|
||||
if (client == null)
|
||||
{
|
||||
Log.Warn("SendCommand: No connection");
|
||||
throw new MtConnectionException("No connection");
|
||||
}
|
||||
|
||||
@@ -2993,16 +3049,19 @@ namespace MtApi
|
||||
}
|
||||
catch (CommunicationException ex)
|
||||
{
|
||||
Log.Warn($"SendCommand: {ex.Message}");
|
||||
throw new MtConnectionException(ex.Message, ex);
|
||||
}
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
Log.Warn("SendCommand: Response from MetaTrader is null");
|
||||
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
|
||||
}
|
||||
|
||||
if (response.ErrorCode != 0)
|
||||
{
|
||||
Log.Warn($"SendCommand: ErrorCode = {response.ErrorCode}. {response}");
|
||||
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ToString());
|
||||
}
|
||||
|
||||
@@ -3026,12 +3085,14 @@ namespace MtApi
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
Log.Warn("SendRequest: Response from MetaTrader is null");
|
||||
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
|
||||
}
|
||||
|
||||
var response = JsonConvert.DeserializeObject<T>(res);
|
||||
if (response.ErrorCode != 0)
|
||||
{
|
||||
Log.Warn($"SendRequest: ErrorCode = {response.ErrorCode}. {response}");
|
||||
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ErrorMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.40.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.40.0")]
|
||||
[assembly: AssemblyVersion("1.0.42.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.42.0")]
|
||||
@@ -102,6 +102,8 @@ namespace MtApi5
|
||||
PositionClose = 64,
|
||||
PositionOpen = 65,
|
||||
PositionModify = 6066,
|
||||
PositionClosePartial_bySymbol = 6067,
|
||||
PositionClosePartial_byTicket = 6068,
|
||||
//PositionOpenWithResult = 1065,
|
||||
|
||||
//Backtesting
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<Compile Include="Events\Mt5EventTypes.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Mt5Quote.cs" />
|
||||
<Compile Include="Requests\BuyRequest.cs" />
|
||||
<Compile Include="Requests\ChartTimePriceToXyRequest.cs" />
|
||||
<Compile Include="Requests\ChartTimePriceToXyResult.cs" />
|
||||
<Compile Include="Requests\ChartXyToTimePriceRequest.cs" />
|
||||
@@ -88,6 +89,7 @@
|
||||
<Compile Include="Requests\MarketBookGetRequest.cs" />
|
||||
<Compile Include="Requests\OrderCheckRequest.cs" />
|
||||
<Compile Include="Requests\OrderCheckResult.cs" />
|
||||
<Compile Include="Requests\OrderSendAsyncRequest.cs" />
|
||||
<Compile Include="Requests\OrderSendRequest.cs" />
|
||||
<Compile Include="Requests\PositionCloseRequest.cs" />
|
||||
<Compile Include="Requests\PositionCloseResult.cs" />
|
||||
@@ -96,6 +98,7 @@
|
||||
<Compile Include="Requests\RequestType.cs" />
|
||||
<Compile Include="Requests\OrderSendResult.cs" />
|
||||
<Compile Include="Requests\Response.cs" />
|
||||
<Compile Include="Requests\SellRequest.cs" />
|
||||
<Compile Include="Requests\SymbolInfoStringRequest.cs" />
|
||||
<Compile Include="Requests\SymbolInfoStringResult.cs" />
|
||||
<Compile Include="Requests\SymbolInfoTickRequest.cs" />
|
||||
|
||||
@@ -134,6 +134,38 @@ namespace MtApi5
|
||||
return response != null && response.RetVal;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Function is used for conducting asynchronous trade operations without waiting for the trade server's response to a sent request.
|
||||
///</summary>
|
||||
///<param name="request">Reference to a object of MqlTradeRequest type describing the trade activity of the client.</param>
|
||||
///<param name="result">Reference to a object of MqlTradeResult type describing the result of trade operation in case of a successful completion (if true is returned).</param>
|
||||
/// <returns>
|
||||
/// Returns true if the request is sent to a trade server. In case the request is not sent, it returns false.
|
||||
/// In case the request is sent, in the result variable the response code contains TRADE_RETCODE_PLACED value (code 10008) – "order placed".
|
||||
/// Successful execution means only the fact of sending, but does not give any guarantee that the request has reached the trade server and has been accepted for processing.
|
||||
/// When processing the received request, a trade server sends a reply to a client terminal notifying of change in the current state of positions,
|
||||
/// orders and deals, which leads to the generation of the Trade event.
|
||||
/// </returns>
|
||||
public bool OrderSendAsync(MqlTradeRequest request, out MqlTradeResult result)
|
||||
{
|
||||
Log.Debug($"OrderSend: request = {request}");
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
Log.Warn("OrderSend: request is not defined!");
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var response = SendRequest<OrderSendResult>(new OrderSendAsyncRequest
|
||||
{
|
||||
TradeRequest = request
|
||||
});
|
||||
|
||||
result = response?.TradeResult;
|
||||
return response != null && response.RetVal;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///The function calculates the margin required for the specified order type, on the current account
|
||||
///, in the current market environment not taking into account current pending orders and open positions
|
||||
@@ -655,6 +687,92 @@ namespace MtApi5
|
||||
{
|
||||
return PositionOpen(symbol, orderType, volume, price, sl, tp, "", out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partially closes a position on a specified symbol in case of a "hedging" accounting.
|
||||
/// </summary>
|
||||
/// <param name="symbol">Name of a trading instrument, on which a position is closed partially.</param>
|
||||
/// <param name="volume"> Volume, by which a position should be decreased. If the value exceeds the volume of a partially closed position, it is closed in full. No position in the opposite direction is opened.</param>
|
||||
/// <param name="deviation">The maximum deviation from the current price (in points).</param>
|
||||
/// <returns>true if the basic check of structures is successful, otherwise false.</returns>
|
||||
public bool PositionClosePartial(string symbol, double volume, ulong deviation = ulong.MaxValue)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, volume, deviation };
|
||||
|
||||
return SendCommand<bool>(Mt5CommandType.PositionClosePartial_bySymbol, commandParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partially closes a position on a specified symbol in case of a "hedging" accounting.
|
||||
/// </summary>
|
||||
/// <param name="ticket">Closed position ticket.</param>
|
||||
/// <param name="volume"> Volume, by which a position should be decreased. If the value exceeds the volume of a partially closed position, it is closed in full. No position in the opposite direction is opened.</param>
|
||||
/// <param name="deviation">The maximum deviation from the current price (in points).</param>
|
||||
/// <returns>true if the basic check of structures is successful, otherwise false.</returns>
|
||||
public bool PositionClosePartial(ulong ticket, double volume, ulong deviation = ulong.MaxValue)
|
||||
{
|
||||
var commandParameters = new ArrayList { ticket, volume, deviation };
|
||||
|
||||
return SendCommand<bool>(Mt5CommandType.PositionClosePartial_byTicket, commandParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a long position with specified parameters with current market Ask price
|
||||
/// </summary>
|
||||
/// <param name="result">output result</param>
|
||||
/// <param name="volume">Requested position volume.</param>
|
||||
/// <param name="symbol">Position symbol. If it is not specified, the current symbol will be used.</param>
|
||||
/// <param name="price">Execution price.</param>
|
||||
/// <param name="sl">Stop Loss price.</param>
|
||||
/// <param name="tp">Take Profit price.</param>
|
||||
/// <param name="comment">Comment.</param>
|
||||
/// <returns>true - successful check of the structures, otherwise - false.</returns>
|
||||
public bool Buy(out MqlTradeResult result, double volume, string symbol = null, double price = 0.0, double sl = 0.0, double tp = 0.0, string comment = null)
|
||||
{
|
||||
Log.Debug($"Buy: volume = {volume}, symbol = {symbol}, sl = {sl}, tp = {tp}, comment = {comment}");
|
||||
|
||||
var response = SendRequest<OrderSendResult>(new BuyRequest
|
||||
{
|
||||
Volume = volume,
|
||||
Symbol = symbol,
|
||||
Price = price,
|
||||
Sl = sl,
|
||||
Tp = tp,
|
||||
Comment = comment
|
||||
});
|
||||
|
||||
result = response?.TradeResult;
|
||||
return response != null && response.RetVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a short position with specified parameters with current market Bid price
|
||||
/// </summary>
|
||||
/// <param name="result">output result</param>
|
||||
/// <param name="volume">Requested position volume.</param>
|
||||
/// <param name="symbol">Position symbol. If it is not specified, the current symbol will be used.</param>
|
||||
/// <param name="price">Execution price.</param>
|
||||
/// <param name="sl">Stop Loss price.</param>
|
||||
/// <param name="tp">Take Profit price.</param>
|
||||
/// <param name="comment">Comment.</param>
|
||||
/// <returns>true - successful check of the structures, otherwise - false.</returns>
|
||||
public bool Sell(out MqlTradeResult result, double volume, string symbol = null, double price = 0.0, double sl = 0.0, double tp = 0.0, string comment = null)
|
||||
{
|
||||
Log.Debug($"Sell: volume = {volume}, symbol = {symbol}, sl = {sl}, tp = {tp}, comment = {comment}");
|
||||
|
||||
var response = SendRequest<OrderSendResult>(new SellRequest
|
||||
{
|
||||
Volume = volume,
|
||||
Symbol = symbol,
|
||||
Price = price,
|
||||
Sl = sl,
|
||||
Tp = tp,
|
||||
Comment = comment
|
||||
});
|
||||
|
||||
result = response?.TradeResult;
|
||||
return response != null && response.RetVal;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Account Information functions
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.21")]
|
||||
[assembly: AssemblyFileVersion("1.0.21")]
|
||||
[assembly: AssemblyVersion("1.0.23")]
|
||||
[assembly: AssemblyFileVersion("1.0.23")]
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace MtApi5.Requests
|
||||
{
|
||||
internal class BuyRequest : RequestBase
|
||||
{
|
||||
public override RequestType RequestType => RequestType.Buy;
|
||||
|
||||
public double Volume { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
public double Price { get; set; }
|
||||
public double Sl { get; set; }
|
||||
public double Tp { get; set; }
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MtApi5.Requests
|
||||
{
|
||||
internal class OrderSendAsyncRequest : RequestBase
|
||||
{
|
||||
public override RequestType RequestType => RequestType.OrderSendAsync;
|
||||
|
||||
public MqlTradeRequest TradeRequest { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@ namespace MtApi5.Requests
|
||||
ChartTimePriceToXY = 9,
|
||||
ChartXYToTimePrice = 10,
|
||||
PositionClose = 11,
|
||||
SymbolInfoTick = 12
|
||||
SymbolInfoTick = 12,
|
||||
Buy = 13,
|
||||
Sell = 14,
|
||||
OrderSendAsync = 15
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace MtApi5.Requests
|
||||
{
|
||||
internal class SellRequest : RequestBase
|
||||
{
|
||||
public override RequestType RequestType => RequestType.Sell;
|
||||
|
||||
public double Volume { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
public double Price { get; set; }
|
||||
public double Sl { get; set; }
|
||||
public double Tp { get; set; }
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,8 @@ MQL files have been build to ex4 and stored into folders "mq4" for MetaTrader an
|
||||
Changing the source code of MQL expert requires recompilation with MetaEditor. Resulting in the need to copy files "hash.mqh" and "json.mqh" to the MetaEditor include folder.
|
||||
|
||||
# Home Website
|
||||
Please visit http://mtapi4.net
|
||||
|
||||
# Telegram Channel
|
||||
https://t.me/mtapi4
|
||||
|
||||
https://t.me/joinchat/GfnfUxvelQCLvvIvLO16-w
|
||||
@@ -439,6 +439,7 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<DockPanel Grid.Row="0" LastChildFill="True">
|
||||
@@ -454,6 +455,15 @@
|
||||
<Button Command="{Binding IndicatorReleaseCommand}" Margin="2"
|
||||
Content="IndicatorRelease" HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
<WrapPanel Grid.Row="2" Margin="2">
|
||||
<Button Command="{Binding iCustomCommand}" Content="iCustom" Margin="2"/>
|
||||
<Button Command="{Binding iBullsPowerCommand}" Content="iBullPower" Margin="2"/>
|
||||
<Button Command="{Binding iBearsPowerCommand}" Content="iBearPower" Margin="2"/>
|
||||
</WrapPanel>
|
||||
<WrapPanel Grid.Row="3">
|
||||
<Button Command="{Binding BarsCalculatedCommand}" Content="BarsCalculated" Margin="2"/>
|
||||
<Button Command="{Binding CopyBufferCommand}" Content="CopyBuffer" Margin="2"/>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -487,6 +497,7 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Button Grid.Row="0" Command="{Binding PositionOpenCommand}" Content="PositionOpen" Margin="2" HorizontalAlignment="Left"/>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="4">
|
||||
@@ -495,14 +506,13 @@
|
||||
<Button Command="{Binding PositionCloseCommand}" Content="PositionClose" Margin="2"/>
|
||||
</StackPanel>
|
||||
<Button Grid.Row="2" Command="{Binding PositionCloseAllCommand}" Content="PositionCloseAll" Margin="2" HorizontalAlignment="Left"/>
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="4">
|
||||
<Button Command="{Binding BuyCommand}" Content="Buy" Width="60" Margin="2" HorizontalAlignment="Left"/>
|
||||
<Button Command="{Binding SellCommand}" Content="Sell" Width="60" Margin="2" HorizontalAlignment="Left"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Indicators">
|
||||
<WrapPanel VerticalAlignment="Top" Margin="5">
|
||||
<Button Command="{Binding iCustomCommand}" Content="iCustom" Margin="2"/>
|
||||
</WrapPanel>
|
||||
</TabItem>
|
||||
<TabItem Header="Chart Functions">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
|
||||
@@ -44,6 +44,11 @@ namespace MtApi5TestClient
|
||||
public DelegateCommand CopyCloseCommand { get; private set; }
|
||||
public DelegateCommand IndicatorCreateCommand { get; private set; }
|
||||
public DelegateCommand IndicatorReleaseCommand { get; private set; }
|
||||
public DelegateCommand iCustomCommand { get; private set; }
|
||||
public DelegateCommand iBullsPowerCommand { get; private set; }
|
||||
public DelegateCommand iBearsPowerCommand { get; private set; }
|
||||
public DelegateCommand BarsCalculatedCommand { get; private set; }
|
||||
public DelegateCommand CopyBufferCommand { get; private set; }
|
||||
|
||||
public DelegateCommand CopyTickVolumeCommand { get; private set; }
|
||||
public DelegateCommand CopyRealVolumeCommand { get; private set; }
|
||||
@@ -68,6 +73,8 @@ namespace MtApi5TestClient
|
||||
public DelegateCommand PositionOpenCommand { get; private set; }
|
||||
public DelegateCommand PositionCloseCommand { get; private set; }
|
||||
public DelegateCommand PositionCloseAllCommand { get; private set; }
|
||||
public DelegateCommand BuyCommand { get; private set; }
|
||||
public DelegateCommand SellCommand { get; private set; }
|
||||
|
||||
public DelegateCommand GetLastErrorCommand { get; private set; }
|
||||
public DelegateCommand ResetLastErrorCommand { get; private set; }
|
||||
@@ -75,8 +82,6 @@ namespace MtApi5TestClient
|
||||
public DelegateCommand AlertCommand { get; private set; }
|
||||
public DelegateCommand TesterStopCommand { get; private set; }
|
||||
|
||||
public DelegateCommand iCustomCommand { get; private set; }
|
||||
|
||||
public DelegateCommand TimeCurrentCommand { get; private set; }
|
||||
|
||||
public DelegateCommand ChartOpenCommand { get; private set; }
|
||||
@@ -354,6 +359,11 @@ namespace MtApi5TestClient
|
||||
CopyCloseCommand = new DelegateCommand(ExecuteCopyClose);
|
||||
IndicatorCreateCommand = new DelegateCommand(ExecuteIndicatorCreate);
|
||||
IndicatorReleaseCommand = new DelegateCommand(ExecuteIndicatorRelease);
|
||||
iCustomCommand = new DelegateCommand(ExecuteICustom);
|
||||
iBullsPowerCommand = new DelegateCommand(ExecuteIBullsPowerCommand);
|
||||
iBearsPowerCommand = new DelegateCommand(ExecuteIBearsPowerCommand);
|
||||
BarsCalculatedCommand = new DelegateCommand(ExecuteBarsCalculatedCommand);
|
||||
CopyBufferCommand = new DelegateCommand(ExecuteCopyBufferCommand);
|
||||
|
||||
CopyTickVolumeCommand = new DelegateCommand(ExecuteCopyTickVolume);
|
||||
CopyRealVolumeCommand = new DelegateCommand(ExecuteCopyRealVolume);
|
||||
@@ -378,6 +388,8 @@ namespace MtApi5TestClient
|
||||
PositionOpenCommand = new DelegateCommand(ExecutePositionOpen);
|
||||
PositionCloseCommand = new DelegateCommand(ExecutePositionClose);
|
||||
PositionCloseAllCommand = new DelegateCommand(ExecutePositionCloseAll);
|
||||
BuyCommand = new DelegateCommand(ExecuteBuy);
|
||||
SellCommand = new DelegateCommand(ExecuteSell);
|
||||
|
||||
PrintCommand = new DelegateCommand(ExecutePrint);
|
||||
AlertCommand = new DelegateCommand(ExecuteAlert);
|
||||
@@ -385,8 +397,6 @@ namespace MtApi5TestClient
|
||||
ResetLastErrorCommand = new DelegateCommand(ExecuteResetLastError);
|
||||
TesterStopCommand = new DelegateCommand(ExecuteTesterStop);
|
||||
|
||||
iCustomCommand = new DelegateCommand(ExecuteICustom);
|
||||
|
||||
ChartOpenCommand = new DelegateCommand(ExecuteChartOpen);
|
||||
ChartTimePriceToXYCommand = new DelegateCommand(ExecuteChartTimePriceToXY);
|
||||
ChartXYToTimePriceCommand = new DelegateCommand(ExecuteChartXYToTimePrice);
|
||||
@@ -806,6 +816,68 @@ namespace MtApi5TestClient
|
||||
AddLog($"IndicatorRelease [{indicatorHandle}]: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteICustom(object o)
|
||||
{
|
||||
const string name = @"Examples\Custom Moving Average";
|
||||
int[] parameters = { 0, 21, (int)ENUM_APPLIED_PRICE.PRICE_CLOSE };
|
||||
|
||||
var retVal = await Execute(() => _mtApiClient.iCustom(TimeSeriesValues.SymbolValue, TimeSeriesValues.TimeFrame, name, parameters));
|
||||
TimeSeriesValues.IndicatorHandle = retVal;
|
||||
AddLog($"Custom Moving Average: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteIBullsPowerCommand(object o)
|
||||
{
|
||||
const int maPeriod = 13;
|
||||
var retVal = await Execute(() => _mtApiClient.iBullsPower(TimeSeriesValues.SymbolValue, TimeSeriesValues.TimeFrame, maPeriod));
|
||||
TimeSeriesValues.IndicatorHandle = retVal;
|
||||
|
||||
AddLog($"iBullPower: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteIBearsPowerCommand(object o)
|
||||
{
|
||||
const int maPeriod = 13;
|
||||
var retVal = await Execute(() => _mtApiClient.iBearsPower(TimeSeriesValues.SymbolValue, TimeSeriesValues.TimeFrame, maPeriod));
|
||||
TimeSeriesValues.IndicatorHandle = retVal;
|
||||
|
||||
AddLog($"iBearsPower: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteBarsCalculatedCommand(object o)
|
||||
{
|
||||
var retVal = await Execute(() => _mtApiClient.BarsCalculated(TimeSeriesValues.IndicatorHandle));
|
||||
|
||||
AddLog($"BarsCalculated: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteCopyBufferCommand(object o)
|
||||
{
|
||||
TimeSeriesResults.Clear();
|
||||
|
||||
var result = await Execute(() =>
|
||||
{
|
||||
var count = _mtApiClient.CopyBuffer(TimeSeriesValues.IndicatorHandle, 0, TimeSeriesValues.StartPos, TimeSeriesValues.Count, out var values);
|
||||
return count > 0 ? values : null;
|
||||
});
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
AddLog("CopyRates: result is null");
|
||||
return;
|
||||
}
|
||||
|
||||
RunOnUiThread(() =>
|
||||
{
|
||||
foreach (var value in result)
|
||||
{
|
||||
TimeSeriesResults.Add($"{value:F6}");
|
||||
}
|
||||
});
|
||||
|
||||
AddLog("CopyRates: success");
|
||||
}
|
||||
|
||||
private async void ExecuteCopyRates(object o)
|
||||
{
|
||||
if (string.IsNullOrEmpty(TimeSeriesValues?.SymbolValue)) return;
|
||||
@@ -1143,6 +1215,26 @@ namespace MtApi5TestClient
|
||||
AddLog($"PositionCloseAll: count = {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteBuy(object obj)
|
||||
{
|
||||
const string symbol = "EURUSD";
|
||||
const double volume = 0.1;
|
||||
MqlTradeResult tradeResult = null;
|
||||
|
||||
var retVal = await Execute(() => _mtApiClient.Buy(out tradeResult, volume, symbol));
|
||||
AddLog($"Buy: symbol EURUSD retVal = {retVal}, result = {tradeResult}");
|
||||
}
|
||||
|
||||
private async void ExecuteSell(object obj)
|
||||
{
|
||||
const string symbol = "EURUSD";
|
||||
const double volume = 0.1;
|
||||
MqlTradeResult tradeResult = null;
|
||||
|
||||
var retVal = await Execute(() => _mtApiClient.Sell(out tradeResult, volume, symbol));
|
||||
AddLog($"Sell: symbol EURUSD retVal = {retVal}, result = {tradeResult}");
|
||||
}
|
||||
|
||||
private async void ExecutePrint(object obj)
|
||||
{
|
||||
var message = MessageText;
|
||||
@@ -1177,17 +1269,6 @@ namespace MtApi5TestClient
|
||||
AddLog("TesterStop: executed.");
|
||||
}
|
||||
|
||||
private async void ExecuteICustom(object o)
|
||||
{
|
||||
const string symbol = "EURUSD";
|
||||
const ENUM_TIMEFRAMES timeframe = ENUM_TIMEFRAMES.PERIOD_H1;
|
||||
const string name = @"Examples\Custom Moving Average";
|
||||
int[] parameters = { 0, 21, (int)ENUM_APPLIED_PRICE.PRICE_CLOSE };
|
||||
|
||||
var retVal = await Execute(() => _mtApiClient.iCustom(symbol, timeframe, name, parameters));
|
||||
AddLog($"Custom Moving Average: result - {retVal}");
|
||||
}
|
||||
|
||||
private async void ExecuteTimeCurrent(object o)
|
||||
{
|
||||
var retVal = await Execute(() => _mtApiClient.TimeCurrent());
|
||||
@@ -1676,7 +1757,7 @@ namespace MtApi5TestClient
|
||||
|
||||
private void _mtApiClient_OnLastTimeBar(object sender, Mt5TimeBarArgs e)
|
||||
{
|
||||
AddLog($"OnBookEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
|
||||
AddLog($"OnLastTimeBarEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
|
||||
}
|
||||
|
||||
private void _mtApiClient_OnLockTicks(object sender, Mt5LockTicksEventArgs e)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Binary file not shown.
+258
-34
@@ -1,7 +1,7 @@
|
||||
#property copyright "Vyacheslav Demidyuk"
|
||||
#property link ""
|
||||
|
||||
#property version "1.6"
|
||||
#property version "1.9"
|
||||
#property description "MtApi (MT5) connection expert"
|
||||
|
||||
#include <json.mqh>
|
||||
@@ -50,6 +50,12 @@ enum LockTickType
|
||||
|
||||
input int Port = 8228;
|
||||
input LockTickType BacktestingLockTicks = NO_LOCK;
|
||||
input group "Disable Events "
|
||||
input bool Enable_OnBookEvent = true;
|
||||
input bool Enable_OnTickEvent = true;
|
||||
input bool Enable_OnTradeTransactionEvent = true;
|
||||
input bool Enable_OnLastBarEvent = true;
|
||||
|
||||
|
||||
int ExpertHandle;
|
||||
|
||||
@@ -89,27 +95,31 @@ void OnTick()
|
||||
long lastbar_time = SeriesInfoInteger(symbol, Period(), SERIES_LASTBAR_DATE);
|
||||
if (_last_bar_open_time != lastbar_time)
|
||||
{
|
||||
if (_last_bar_open_time != 0)
|
||||
if (_last_bar_open_time != 0 )
|
||||
{
|
||||
MqlRates rates_array[];
|
||||
CopyRates(symbol, Period(), 1, 1, rates_array);
|
||||
if(Enable_OnLastBarEvent)
|
||||
{
|
||||
MqlRates rates_array[];
|
||||
CopyRates(symbol, Period(), 1, 1, rates_array);
|
||||
|
||||
MtTimeBarEvent* time_bar = new MtTimeBarEvent(symbol, rates_array[0]);
|
||||
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
|
||||
delete time_bar;
|
||||
|
||||
lastbar_time_changed = true;
|
||||
MtTimeBarEvent* time_bar = new MtTimeBarEvent(symbol, rates_array[0]);
|
||||
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
|
||||
delete time_bar;
|
||||
}
|
||||
lastbar_time_changed = true;
|
||||
}
|
||||
|
||||
_last_bar_open_time = lastbar_time;
|
||||
}
|
||||
|
||||
MqlTick last_tick;
|
||||
SymbolInfoTick(Symbol(),last_tick);
|
||||
if (Enable_OnTickEvent)
|
||||
{
|
||||
MqlTick last_tick;
|
||||
SymbolInfoTick(Symbol(),last_tick);
|
||||
|
||||
MtOnTickEvent * tick_event = new MtOnTickEvent(symbol, last_tick);
|
||||
SendMtEvent(ON_TICK_EVENT, tick_event);
|
||||
delete tick_event;
|
||||
MtOnTickEvent * tick_event = new MtOnTickEvent(symbol, last_tick);
|
||||
SendMtEvent(ON_TICK_EVENT, tick_event);
|
||||
delete tick_event;
|
||||
}
|
||||
|
||||
if (IsTesting())
|
||||
{
|
||||
@@ -132,29 +142,37 @@ void OnTradeTransaction(
|
||||
const MqlTradeRequest& request, // request structure
|
||||
const MqlTradeResult& result // result structure
|
||||
)
|
||||
{
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s:", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
MtOnTradeTransactionEvent* trans_event = new MtOnTradeTransactionEvent(trans, request, result);
|
||||
SendMtEvent(ON_TRADE_TRANSACTION_EVENT, trans_event);
|
||||
delete trans_event;
|
||||
}
|
||||
|
||||
{
|
||||
if(!Enable_OnTradeTransactionEvent) return;
|
||||
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s:", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
|
||||
MtOnTradeTransactionEvent* trans_event = new MtOnTradeTransactionEvent(trans, request, result);
|
||||
SendMtEvent(ON_TRADE_TRANSACTION_EVENT, trans_event);
|
||||
delete trans_event;
|
||||
|
||||
}
|
||||
void OnBookEvent(const string& symbol)
|
||||
{
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: %s", __FUNCTION__, symbol);
|
||||
#endif
|
||||
{
|
||||
|
||||
if(!Enable_OnBookEvent) return;
|
||||
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: %s", __FUNCTION__, symbol);
|
||||
#endif
|
||||
|
||||
MtOnBookEvent * book_event = new MtOnBookEvent(symbol);
|
||||
SendMtEvent(ON_BOOK_EVENT, book_event);
|
||||
delete book_event;
|
||||
}
|
||||
MtOnBookEvent * book_event = new MtOnBookEvent(symbol);
|
||||
SendMtEvent(ON_BOOK_EVENT, book_event);
|
||||
delete book_event;
|
||||
|
||||
}
|
||||
|
||||
int preinit()
|
||||
{
|
||||
StringInit(_error,1000,0);
|
||||
StringInit(_response_error,1000,0);
|
||||
|
||||
return (0);
|
||||
@@ -555,6 +573,12 @@ int executeCommand()
|
||||
case 6066: //PositionModify
|
||||
Execute_PositionModify();
|
||||
break;
|
||||
case 6067: //PositionClosePartial_bySymbol
|
||||
Execute_PositionClosePartial_bySymbol();
|
||||
break;
|
||||
case 6068: //Execute_PositionClosePartial_byTicket
|
||||
Execute_PositionClosePartial_byTicket();
|
||||
break;
|
||||
case 66: //BacktestingReady
|
||||
Execute_BacktestingReady();
|
||||
break;
|
||||
@@ -3296,6 +3320,80 @@ void Execute_PositionModify()
|
||||
}
|
||||
}
|
||||
|
||||
void Execute_PositionClosePartial_bySymbol()
|
||||
{
|
||||
string symbol;
|
||||
double volume;
|
||||
ulong deviation;
|
||||
|
||||
if (!getStringValue(ExpertHandle, 0, symbol, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (1)", "symbol", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
if (!getDoubleValue(ExpertHandle, 1, volume, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (1)", "volume", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
if (!getULongValue(ExpertHandle, 2, deviation, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (1)", "deviation", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
|
||||
CTrade trade;
|
||||
bool ok = trade.PositionClosePartial(symbol, volume, deviation);
|
||||
#ifdef __DEBUG_LOG__
|
||||
Print("command PositionClosePartial (1): result = ", ok);
|
||||
#endif
|
||||
|
||||
if (!sendBooleanResponse(ExpertHandle, ok, _response_error))
|
||||
{
|
||||
PrintResponseError("PositionClosePartial (1)", _response_error);
|
||||
}
|
||||
}
|
||||
|
||||
void Execute_PositionClosePartial_byTicket()
|
||||
{
|
||||
ulong ticket;
|
||||
double volume;
|
||||
ulong deviation;
|
||||
|
||||
if (!getULongValue(ExpertHandle, 0, ticket, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (2)", "ticket", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
if (!getDoubleValue(ExpertHandle, 1, volume, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (2)", "volume", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
if (!getULongValue(ExpertHandle, 2, deviation, _error))
|
||||
{
|
||||
PrintParamError("PositionClosePartial (2)", "deviation", _error);
|
||||
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
|
||||
return;
|
||||
}
|
||||
|
||||
CTrade trade;
|
||||
bool ok = trade.PositionClosePartial(ticket, volume, deviation);
|
||||
#ifdef __DEBUG_LOG__
|
||||
Print("command PositionClosePartial (2): result = ", ok);
|
||||
#endif
|
||||
|
||||
if (!sendBooleanResponse(ExpertHandle, ok, _response_error))
|
||||
{
|
||||
PrintResponseError("PositionClosePartial (2)", _response_error);
|
||||
}
|
||||
}
|
||||
|
||||
void Execute_PositionOpen(bool isTradeResultRequired)
|
||||
{
|
||||
string symbol;
|
||||
@@ -4457,7 +4555,7 @@ void Execute_iBullsPower()
|
||||
}
|
||||
|
||||
if (!sendIntResponse(ExpertHandle,
|
||||
iBearsPower(symbol, (ENUM_TIMEFRAMES)period, ma_period),
|
||||
iBullsPower(symbol, (ENUM_TIMEFRAMES)period, ma_period),
|
||||
_error))
|
||||
{
|
||||
PrintResponseError("iBullsPower", _response_error);
|
||||
@@ -6858,6 +6956,15 @@ string OnRequest(string json)
|
||||
case 12: //SymbolInfoTick
|
||||
response = ExecuteRequest_SymbolInfoTick(jo);
|
||||
break;
|
||||
case 13: //Buy
|
||||
response = ExecuteRequest_Buy(jo);
|
||||
break;
|
||||
case 14: //Sell
|
||||
response = ExecuteRequest_Sell(jo);
|
||||
break;
|
||||
case 15: //OrderSendAsync
|
||||
response = ExecuteRequest_OrderSendAsync(jo);
|
||||
break;
|
||||
default:
|
||||
PrintFormat("%s [WARNING]: Unknown request type %d", __FUNCTION__, requestType);
|
||||
response = CreateErrorResponse(-1, "Unknown request type");
|
||||
@@ -7067,6 +7174,30 @@ string ExecuteRequest_OrderSend(JSONObject *jo)
|
||||
return CreateSuccessResponse("Value", result_value_jo);
|
||||
}
|
||||
|
||||
string ExecuteRequest_OrderSendAsync(JSONObject *jo)
|
||||
{
|
||||
CHECK_JSON_VALUE(jo, "TradeRequest", CreateErrorResponse(-1, "Undefinded mandatory parameter TradeRequest"));
|
||||
JSONObject* trade_request_jo = jo.getObject("TradeRequest");
|
||||
|
||||
MqlTradeRequest trade_request = {0};
|
||||
bool converted = JsonToMqlTradeRequest(trade_request_jo, trade_request);
|
||||
if (converted == false)
|
||||
return CreateErrorResponse(-1, "Failed to parse parameter TradeRequest");
|
||||
|
||||
MqlTradeResult trade_result = {0};
|
||||
bool ok = OrderSendAsync(trade_request, trade_result);
|
||||
|
||||
JSONObject* result_value_jo = new JSONObject();
|
||||
result_value_jo.put("RetVal", new JSONBool(ok));
|
||||
result_value_jo.put("TradeResult", MqlTradeResultToJson(trade_result));
|
||||
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: return value = %s", __FUNCTION__, ok ? "true" : "false");
|
||||
#endif
|
||||
|
||||
return CreateSuccessResponse("Value", result_value_jo);
|
||||
}
|
||||
|
||||
string ExecuteRequest_PositionOpen(JSONObject *jo)
|
||||
{
|
||||
//Symbol
|
||||
@@ -7389,6 +7520,98 @@ string ExecuteRequest_SymbolInfoTick(JSONObject *jo)
|
||||
return CreateSuccessResponse("Value", MqlTickToJson(tick));
|
||||
}
|
||||
|
||||
string ExecuteRequest_Buy(JSONObject *jo)
|
||||
{
|
||||
//Symbol
|
||||
string symbol=Symbol();
|
||||
if (jo.getValue("Symbol") != NULL)
|
||||
symbol = jo.getString("Symbol");
|
||||
|
||||
//Volume
|
||||
CHECK_JSON_VALUE(jo, "Volume", CreateErrorResponse(-1, "Undefinded mandatory parameter Volume"));
|
||||
double volume = jo.getDouble("Volume");
|
||||
|
||||
//Price
|
||||
CHECK_JSON_VALUE(jo, "Price", CreateErrorResponse(-1, "Undefinded mandatory parameter Price"));
|
||||
double price = jo.getDouble("Price");
|
||||
|
||||
//Sl
|
||||
CHECK_JSON_VALUE(jo, "Sl", CreateErrorResponse(-1, "Undefinded mandatory parameter Sl"));
|
||||
double sl = jo.getDouble("Sl");
|
||||
|
||||
//Tp
|
||||
CHECK_JSON_VALUE(jo, "Tp", CreateErrorResponse(-1, "Undefinded mandatory parameter Tp"));
|
||||
double tp = jo.getDouble("Tp");
|
||||
|
||||
//Comment
|
||||
string comment="";
|
||||
if (jo.getValue("Comment") != NULL)
|
||||
comment = jo.getString("Comment");
|
||||
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: symbol = %s, volume = %f, price = %f, sl = %f, tp = %f, comment = %s",
|
||||
__FUNCTION__, symbol, volume, price, sl, tp, comment);
|
||||
#endif
|
||||
|
||||
CTrade trade;
|
||||
bool ok = trade.Buy(volume, symbol, price, sl, tp, comment);
|
||||
|
||||
MqlTradeResult trade_result={0};
|
||||
trade.Result(trade_result);
|
||||
|
||||
JSONObject* result_value_jo = new JSONObject();
|
||||
result_value_jo.put("RetVal", new JSONBool(ok));
|
||||
result_value_jo.put("TradeResult", MqlTradeResultToJson(trade_result));
|
||||
|
||||
return CreateSuccessResponse("Value", result_value_jo);
|
||||
}
|
||||
|
||||
string ExecuteRequest_Sell(JSONObject *jo)
|
||||
{
|
||||
//Symbol
|
||||
string symbol=Symbol();
|
||||
if (jo.getValue("Symbol") != NULL)
|
||||
symbol = jo.getString("Symbol");
|
||||
|
||||
//Volume
|
||||
CHECK_JSON_VALUE(jo, "Volume", CreateErrorResponse(-1, "Undefinded mandatory parameter Volume"));
|
||||
double volume = jo.getDouble("Volume");
|
||||
|
||||
//Price
|
||||
CHECK_JSON_VALUE(jo, "Price", CreateErrorResponse(-1, "Undefinded mandatory parameter Price"));
|
||||
double price = jo.getDouble("Price");
|
||||
|
||||
//Sl
|
||||
CHECK_JSON_VALUE(jo, "Sl", CreateErrorResponse(-1, "Undefinded mandatory parameter Sl"));
|
||||
double sl = jo.getDouble("Sl");
|
||||
|
||||
//Tp
|
||||
CHECK_JSON_VALUE(jo, "Tp", CreateErrorResponse(-1, "Undefinded mandatory parameter Tp"));
|
||||
double tp = jo.getDouble("Tp");
|
||||
|
||||
//Comment
|
||||
string comment="";
|
||||
if (jo.getValue("Comment") != NULL)
|
||||
comment = jo.getString("Comment");
|
||||
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: symbol = %s, volume = %f, price = %f, sl = %f, tp = %f, comment = %s",
|
||||
__FUNCTION__, symbol, volume, price, sl, tp, comment);
|
||||
#endif
|
||||
|
||||
CTrade trade;
|
||||
bool ok = trade.Sell(volume, symbol, price, sl, tp, comment);
|
||||
|
||||
MqlTradeResult trade_result={0};
|
||||
trade.Result(trade_result);
|
||||
|
||||
JSONObject* result_value_jo = new JSONObject();
|
||||
result_value_jo.put("RetVal", new JSONBool(ok));
|
||||
result_value_jo.put("TradeResult", MqlTradeResultToJson(trade_result));
|
||||
|
||||
return CreateSuccessResponse("Value", result_value_jo);
|
||||
}
|
||||
|
||||
//------------ Events -------------------------------------------------------
|
||||
|
||||
enum MtEventTypes
|
||||
@@ -7521,6 +7744,7 @@ void SendMtEvent(MtEventTypes eventType, MtEvent* mtEvent)
|
||||
if (sendEvent(ExpertHandle, (int)eventType, json.toString(), _error))
|
||||
{
|
||||
#ifdef __DEBUG_LOG__
|
||||
PrintFormat("%s: event = %s", __FUNCTION__, EnumToString(eventType));
|
||||
PrintFormat("%s: payload = %s", __FUNCTION__, json.toString());
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user