Compare commits

...

22 Commits

Author SHA1 Message Date
DW 5b76bf0547 Merge master fixed conflict. 2017-01-05 21:36:55 +02:00
DW 1c269f7339 Issue #32: Added function ObjectName into test client 2017-01-05 02:14:13 +02:00
DW 21fb790d8c Issue #32: Fixed small bugs in EA MtApi.mq4 2017-01-05 01:02:55 +02:00
DW 7c9a0aa8cc Issue #32: Implement object functions in EA MtApi.mq4 2017-01-03 21:29:41 +02:00
DW 18ddf3df1c Issue #32: Added c# implementations of most object functions in MtApi client 2016-12-30 17:16:48 +02:00
DW a8832b79ba Issue #32: Added function ObjectCreate in MtApi (MT4) 2016-12-27 17:41:11 +02:00
vdemydiuk 39146d68b2 Starting work on Object Functions 2016-12-26 17:49:06 +02:00
DW 5b03f01e9b Clear unnecessary witespaces in MtApi.mq4 2016-12-21 14:26:37 +02:00
vdemydiuk 8f5a1c8222 Refactored MtApi.mq4 2016-12-21 12:01:15 +02:00
vdemydiuk f5f13a13cc Issue #32: Added function ChartRedraw 2016-12-12 17:29:52 +02:00
vdemydiuk 9ef970cf1e Refactoring TestApiUiClient (Account Information tab) 2016-11-30 10:57:33 +02:00
vdemydiuk b5878ccb62 Refactoring TestApiUiClient (Check Status tab) 2016-11-29 19:08:53 +02:00
DW 4a7bb6f2cb MtApi (MT5) ver. 1.0.11.1 HotFix 2016-11-29 10:20:55 +02:00
vdemydiuk 5abfeebc90 Issue #32: Added function ChartId 2016-11-28 16:03:40 +02:00
vdemydiuk e333164552 Issue #32: Added ExecutorHandle property to determine which expert will be used for execution command 2016-11-28 14:45:33 +02:00
vdemydiuk 9a6968f618 Refactoring MtApi 2016-11-26 19:27:09 +02:00
DW d63a53b8a9 MtApi (MT4) version 1.0.32.1 (HotFix) 2016-11-25 16:06:11 +02:00
DW 7e821fcade Issue #38: Removed MemoryAppender in LogConfigurator (MtApiService) 2016-11-25 15:50:56 +02:00
DW 88e2d22abe Issue #38: Removed MemoryAppender in LogConfigurator (MtApiService) 2016-11-23 13:09:47 +02:00
DW fcfd741e5b Issue #37: Used ConcurrencyMode.Multiple for server and client side to avoid deadlocks and freezes of MtApiService 2016-11-23 10:51:50 +02:00
DW c722511c03 Refactored MtApiService (ver. 1.0.24): Added ExpertHandle to MtQuote and MtEvent. Added event QuoteUpdate to MtApiClient. 2016-11-18 15:47:55 +02:00
DW 39599436ab Started version 1.0.33 of MtApi MT4 2016-11-18 12:13:00 +02:00
52 changed files with 2599 additions and 1410 deletions
+2 -3
View File
@@ -1,8 +1,7 @@
namespace MTApiService
{
public interface ICommandManager
internal interface ICommandManager
{
void EnqueueCommandTask(MtCommandTask task);
MtCommandTask DequeueCommandTask();
MtCommandTask SendCommand(MtCommand task);
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace MTApiService
{
internal interface ITaskExecutor
{
void Execute(MtCommandTask task);
int Handle { get; }
}
}
-4
View File
@@ -41,10 +41,6 @@ namespace MTApiService
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
var memory = new MemoryAppender();
memory.ActivateOptions();
hierarchy.Root.AddAppender(memory);
#if (DEBUG)
hierarchy.Root.Level = Level.Debug;
#else
+3 -2
View File
@@ -62,6 +62,7 @@
<ItemGroup>
<Compile Include="ICommandManager.cs" />
<Compile Include="IMetaTraderHandler.cs" />
<Compile Include="ITaskExecutor.cs" />
<Compile Include="LogConfigurator.cs" />
<Compile Include="MtCommandEventArgs.cs" />
<Compile Include="IDisposableChannel.cs" />
@@ -78,11 +79,11 @@
<Compile Include="MtConnectionProfile.cs" />
<Compile Include="MtExecutorManager.cs" />
<Compile Include="MtExpert.cs" />
<Compile Include="MtInstrument.cs" />
<Compile Include="MtQuote.cs" />
<Compile Include="MtResponse.cs" />
<Compile Include="MtServer.cs" />
<Compile Include="MtCommand.cs" />
<Compile Include="MtServerInstance.cs" />
<Compile Include="MtAdapter.cs" />
<Compile Include="MtService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
+53 -9
View File
@@ -4,13 +4,13 @@ using log4net;
namespace MTApiService
{
public class MtServerInstance
public class MtAdapter
{
#region Fields
private const string LogProfileName = "MtApiService";
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServerInstance));
private static readonly MtServerInstance Instance = new MtServerInstance();
private static readonly ILog Log = LogManager.GetLogger(typeof(MtAdapter));
private static readonly MtAdapter Instance = new MtAdapter();
private readonly Dictionary<int, MtServer> _servers = new Dictionary<int, MtServer>();
private readonly Dictionary<int, MtExpert> _experts = new Dictionary<int, MtExpert>();
@@ -18,16 +18,16 @@ namespace MTApiService
#region Init Instance
private MtServerInstance()
private MtAdapter()
{
LogConfigurator.Setup(LogProfileName);
}
static MtServerInstance()
static MtAdapter()
{
}
public static MtServerInstance GetInstance()
public static MtAdapter GetInstance()
{
return Instance;
}
@@ -60,7 +60,7 @@ namespace MTApiService
}
}
var expert = new MtExpert(expertHandle, new MtQuote(symbol, bid, ask), mtHandler);
var expert = new MtExpert(expertHandle, new MtQuote { Instrument = symbol, Bid = bid, Ask = ask, ExpertHandle = expertHandle }, mtHandler);
lock (_experts)
{
@@ -111,7 +111,7 @@ namespace MTApiService
if (expert != null)
{
expert.Quote = new MtQuote(symbol, bid, ask);
expert.Quote = new MtQuote { Instrument = symbol, Bid = bid, Ask = ask, ExpertHandle = expertHandle };
}
else
{
@@ -133,7 +133,7 @@ namespace MTApiService
if (expert != null)
{
expert.SendEvent(new MtEvent(eventType, payload));
expert.SendEvent(new MtEvent { EventType = eventType, Payload = payload, ExpertHandle = expertHandle });
}
else
{
@@ -208,6 +208,50 @@ namespace MTApiService
return retval;
}
public object GetNamedParameter(int expertHandle, string name)
{
Log.DebugFormat("GetNamedParameter: begin. expertHandle = {0}, name = {1}", expertHandle, name);
MtExpert expert;
lock (_experts)
{
expert = _experts[expertHandle];
}
if (expert == null)
{
Log.WarnFormat("GetNamedParameter: expert with id {0} has not been found.", expertHandle);
}
var retval = expert?.GetNamedParameter(name);
Log.DebugFormat("GetNamedParameter: end. retval = {0}", retval);
return retval;
}
public bool ContainsNamedParameter(int expertHandle, string name)
{
Log.DebugFormat("ContainsNamedParameter: begin. expertHandle = {0}, name = {1}", expertHandle, name);
MtExpert expert;
lock (_experts)
{
expert = _experts[expertHandle];
}
if (expert == null)
{
Log.WarnFormat("ContainsNamedParameter: expert with id {0} has not been found.", expertHandle);
}
bool retval = expert != null ? expert.ContainsNamedParameter(name) : false;
Log.DebugFormat("ContainsNamedParameter: end. retval = {0}", retval);
return retval;
}
#endregion
#region Private Methods
+1 -1
View File
@@ -11,13 +11,13 @@ namespace MTApiService
: base(callbackContext, binding, remoteAddress)
{
InnerDuplexChannel.Faulted += InnerDuplexChannel_Faulted;
InnerDuplexChannel.Open();
}
#region IMtApi Members
public bool Connect()
{
InnerDuplexChannel.Open();
return Channel.Connect();
}
+42 -90
View File
@@ -6,38 +6,33 @@ using log4net;
namespace MTApiService
{
[CallbackBehavior(UseSynchronizationContext = false)]
public class MtClient: IMtApiCallback, IDisposable
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public class MtClient : IMtApiCallback, IDisposable
{
private const string ServiceName = "MtApiService";
public delegate void MtQuoteHandler(MtQuote quote);
public delegate void MtEventHandler(MtEvent e);
#region Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtClient));
private MtApiProxy _proxy;
private bool _isConnected;
private readonly MtApiProxy _proxy;
#endregion
#region Public Methods
public void Open(string host, int port)
#region ctor
public MtClient(string host, int port)
{
Log.DebugFormat("Open: begin. host = {0}, port = {1}", host, port);
if (string.IsNullOrEmpty(host))
throw new ArgumentNullException(nameof(host), "host is null or empty");
if (port < 0 || port > 65536)
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
var urlService = $"net.tcp://{host}:{port}/{ServiceName}";
Host = host;
Port = port;
if (_proxy != null)
{
Log.Warn("Open: end. _proxy is not null.");
return;
}
var urlService = $"net.tcp://{host}:{port}/{ServiceName}";
var bind = new NetTcpBinding(SecurityMode.None)
{
@@ -55,28 +50,19 @@ namespace MTApiService
MaxNameTableCharCount = 2147483647
}
};
// Commented next statement since it is not required
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
_proxy.Faulted += ProxyFaulted;
Log.Debug("Open: end.");
}
public void Open(int port)
public MtClient(int port)
{
Log.DebugFormat("Open: begin. port = {0}", port);
if (port < 0 || port > 65536)
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
var urlService = $"net.pipe://localhost/{ServiceName}_{port}";
Port = port;
if (_proxy != null)
{
Log.Warn("Open: end. _proxy is not null.");
return;
}
var urlService = $"net.pipe://localhost/{ServiceName}_{port}";
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
{
@@ -94,61 +80,40 @@ namespace MTApiService
MaxNameTableCharCount = 2147483647
}
};
// Commented next statement since it is not required
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
_proxy.Faulted += ProxyFaulted;
Log.Debug("Open: end.");
}
public void Close()
{
Log.Debug("Close: begin.");
if (_proxy != null)
{
_proxy.Faulted -= ProxyFaulted;
_proxy.Dispose();
_proxy = null;
}
_isConnected = false;
Log.Debug("Close: end.");
}
#endregion
#region Public Methods
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public void Connect()
{
Log.Debug("Connect: begin.");
if (_proxy == null)
if (_proxy.State != CommunicationState.Created)
{
Log.Error("Connect: _proxy is not defined.");
throw new CommunicationException("Connection failed to service. Proxy is not defined (needs to call Open)");
}
if (_isConnected)
{
Log.Warn("Connected: end. Client is already connected.");
Log.ErrorFormat("Connected: end. Client has invalid state {0}", _proxy.State);
return;
}
bool coonected;
try
{
_isConnected = _proxy.Connect();
coonected = _proxy.Connect();
}
catch (Exception ex)
{
Log.ErrorFormat("Connect: Exception - {0}", ex.Message);
Close();
throw new CommunicationException($"Connection failed to service. {ex.Message}");
}
if (_isConnected == false)
if (coonected == false)
{
Log.Error("Connect: end. Connection failed.");
throw new CommunicationException("Connection failed");
@@ -163,72 +128,60 @@ namespace MTApiService
try
{
_isConnected = false;
_proxy?.Disconnect();
_proxy.Disconnect();
}
catch (Exception ex)
{
Log.ErrorFormat("Disconnect: Exception - {0}", ex.Message);
Close();
}
Log.Debug("Disconnect: end.");
}
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public MtResponse SendCommand(int commandType, ArrayList parameters)
public MtResponse SendCommand(int commandType, ArrayList parameters, Dictionary<string, object> namedParams, int expertHandle)
{
Log.DebugFormat("SendCommand: begin. commandType = {0}, parameters count = {1}", commandType, parameters?.Count);
MtResponse result;
if (_isConnected == false)
if (IsConnected == false)
{
Log.Error("SendCommand: Client is not connected.");
throw new CommunicationException("Client is not connected.");
}
if (_proxy == null)
{
Log.Error("SendCommand: Proxy is not defined.");
throw new CommunicationException("Proxy is not defined.");
}
MtResponse result;
try
{
result = _proxy.SendCommand(new MtCommand(commandType, parameters));
result = _proxy.SendCommand(new MtCommand {
CommandType = commandType,
Parameters = parameters,
NamedParams = namedParams,
ExpertHandle = expertHandle});
}
catch (Exception ex)
{
Log.ErrorFormat("SendCommand: Exception - {0}", ex.Message);
Close();
throw new CommunicationException("Service connection failed! " + ex.Message);
}
Log.DebugFormat("SendCommand: end. result = {0}", result);
return result;
}
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public IEnumerable<MtQuote> GetQuotes()
public List<MtQuote> GetQuotes()
{
Log.Debug("GetQuotes: begin.");
if (_isConnected == false)
if (IsConnected == false)
{
Log.Warn("GetQuotes: end. Client is not connected.");
return null;
}
if (_proxy == null)
{
Log.Warn("GetQuotes: end. _proxy is not defined.");
return null;
}
List<MtQuote> result;
try
@@ -239,8 +192,6 @@ namespace MTApiService
{
Log.ErrorFormat("GetQuotes: Exception - {0}", ex.Message);
Close();
throw new CommunicationException($"Service connection failed! {ex.Message}");
}
@@ -286,18 +237,17 @@ namespace MTApiService
{
Log.Debug("OnServerStopped: begin.");
Close();
ServerDisconnected?.Invoke(this, EventArgs.Empty);
Log.Debug("OnServerStopped: end.");
}
public void OnMtEvent(MtEvent mtEvent)
public void OnMtEvent(MtEvent e)
{
Log.DebugFormat("OnMtEvent: begin. event = {0}", mtEvent);
Log.DebugFormat("OnMtEvent: begin. event = {0}", e);
MtEventReceived?.Invoke(this, new MtEventArgs(mtEvent));
MtEventReceived?.Invoke(e);
Log.Debug("OnMtEvent: end.");
}
@@ -305,7 +255,10 @@ namespace MTApiService
#endregion
#region Properties
public bool IsConnected => _proxy.State == CommunicationState.Opened && _isConnected;
public string Host { get; private set; }
public int Port { get; private set; }
private bool IsConnected => _proxy.State == CommunicationState.Opened;
#endregion
@@ -315,7 +268,6 @@ namespace MTApiService
{
Log.Debug("ProxyFaulted: begin.");
Close();
ServerFailed?.Invoke(this, EventArgs.Empty);
Log.Debug("ProxyFaulted: end.");
@@ -329,7 +281,7 @@ namespace MTApiService
{
Log.Debug("Dispose: begin.");
Close();
_proxy.Dispose();
Log.Debug("Dispose: end.");
}
@@ -342,7 +294,7 @@ namespace MTApiService
public event MtQuoteHandler QuoteUpdated;
public event EventHandler ServerDisconnected;
public event EventHandler ServerFailed;
public event EventHandler<MtEventArgs> MtEventReceived;
public event MtEventHandler MtEventReceived;
#endregion
}
}
+9 -8
View File
@@ -1,26 +1,27 @@
using System.Runtime.Serialization;
using System.Collections;
using System.Collections.Generic;
namespace MTApiService
{
[DataContract]
public class MtCommand
{
public MtCommand(int commandType, ArrayList parameters)
{
CommandType = commandType;
Parameters = parameters;
}
[DataMember]
public int CommandType { get; set; }
[DataMember]
public int CommandType { get; private set; }
public ArrayList Parameters { get; set; }
[DataMember]
public ArrayList Parameters { get; private set; }
public Dictionary<string, object> NamedParams { get; set; }
[DataMember]
public int ExpertHandle { get; set; }
public override string ToString()
{
return $"CommandType = {CommandType}";
return $"CommandType = {CommandType}; ExpertHandle = {ExpertHandle}";
}
}
}
+5 -18
View File
@@ -7,30 +7,17 @@ namespace MTApiService
public class MtEvent
{
[DataMember]
public int EventType { get; private set; }
public int EventType { get; internal set; }
[DataMember]
public string Payload { get; private set; }
public string Payload { get; internal set; }
public MtEvent(int eventType, string payload)
{
EventType = eventType;
Payload = payload;
}
[DataMember]
public int ExpertHandle { get; internal set; }
public override string ToString()
{
return "MtEvent = " + EventType + ", Payload = " + Payload;
return $"EventType = {EventType}; Payload = {Payload}; ExpertHandle = {ExpertHandle}";
}
}
public class MtEventArgs: EventArgs
{
public MtEventArgs(MtEvent e)
{
Event = e;
}
public MtEvent Event { get; private set; }
}
}
+55 -111
View File
@@ -4,14 +4,13 @@ using log4net;
namespace MTApiService
{
internal class MtCommandExecutorManager : ICommandManager
internal class MtExecutorManager : ICommandManager
{
#region Private Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtCommandExecutorManager));
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExecutorManager));
private readonly List<ITaskExecutor> _executorList = new List<ITaskExecutor>();
private readonly Dictionary<int, ITaskExecutor> _executorMap = new Dictionary<int, ITaskExecutor>();
private readonly object _locker = new object();
#endregion
@@ -23,149 +22,94 @@ namespace MTApiService
lock (_locker)
{
_commandExecutors.Clear();
_commandTasks.Clear();
_executorList.Clear();
_executorMap.Clear();
}
Log.Debug("Stop: end.");
}
public void AddCommandExecutor(MtExpert commandExecutor)
public void AddExecutor(ITaskExecutor executor)
{
if (commandExecutor == null)
throw new ArgumentNullException(nameof(commandExecutor));
if (executor == null)
throw new ArgumentNullException(nameof(executor));
Log.DebugFormat("AddCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
Log.DebugFormat("AddExecutor: begin. executor = {0}", executor);
var notify = false;
lock (_locker)
{
if (_commandExecutors.Contains(commandExecutor))
if (_executorList.Contains(executor))
{
Log.Warn("AddCommandExecutor: end. Command executor already exist.");
Log.Warn("AddExecutor: end. Executor already exist.");
return;
}
_commandExecutors.Add(commandExecutor);
if (_commandTasks.Count > 0)
{
notify = true;
}
}
commandExecutor.CommandExecuted += CommandExecutor_CommandExecuted;
commandExecutor.CommandManager = this;
if (notify)
{
NotifyCommandReady();
_executorList.Add(executor);
_executorMap[executor.Handle] = executor;
}
Log.Debug("AddCommandExecutor: end.");
}
public void RemoveCommandExecutor(MtExpert commandExecutor)
public void RemoveExecutor(ITaskExecutor executor)
{
if (commandExecutor == null)
throw new ArgumentNullException(nameof(commandExecutor));
if (executor == null)
throw new ArgumentNullException(nameof(executor));
Log.DebugFormat("RemoveCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
Log.DebugFormat("RemoveExecutor: begin. executor = {0}", executor);
var notify = false;
lock (_locker)
{
if (_commandExecutors.Contains(commandExecutor) == false)
if (_executorList.Contains(executor) == false)
{
Log.Warn("RemoveCommandExecutor: end. Command executor is not exist in collection.");
Log.Warn("RemoveExecutor: end. Executor is not exist in collection.");
return;
}
_commandExecutors.Remove(commandExecutor);
if (_commandTasks.Count > 0)
_executorList.Remove(executor);
_executorMap.Remove(executor.Handle);
}
Log.Debug("RemoveExecutor: end.");
}
public MtCommandTask SendCommand(MtCommand command)
{
if (command == null)
throw new ArgumentNullException(nameof(command));
var task = new MtCommandTask(command);
Log.DebugFormat("SendTask: begin. command = {0}", command);
ITaskExecutor executor;
lock (_locker)
{
if (_executorMap.ContainsKey(command.ExpertHandle))
{
notify = true;
executor = _executorMap[command.ExpertHandle];
}
else
{
executor = _executorList.Count > 0 ? _executorList[0] : null;
}
}
commandExecutor.CommandExecuted -= CommandExecutor_CommandExecuted;
commandExecutor.CommandManager = null;
if (notify)
if (executor == null)
{
NotifyCommandReady();
Log.Error("SendTask: Executor is null!");
}
else
{
executor.Execute(task);
}
Log.Debug("RemoveCommandExecutor: end.");
Log.Debug("SendTask: end.");
return task;
}
public void EnqueueCommandTask(MtCommandTask task)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
Log.DebugFormat("EnqueueCommandTask: begin. task = {0}", task);
lock (_locker)
{
_commandTasks.Enqueue(task);
}
NotifyCommandReady();
Log.Debug("EnqueueCommandTask: end.");
}
public MtCommandTask DequeueCommandTask()
{
Log.Debug("DequeueCommandTask: called.");
lock (_locker)
{
return _commandTasks.Count > 0 ? _commandTasks.Dequeue() : null;
}
}
#endregion
#region Private Methods
private void NotifyCommandReady()
{
Log.Debug("NotifyCommandReady: begin.");
var commandExecutors = new List<MtExpert>();
lock (_locker)
{
commandExecutors.AddRange(_commandExecutors);
}
foreach (var executor in commandExecutors)
{
executor.NotifyCommandReady();
}
Log.DebugFormat("NotifyCommandReady: end. Notified executor count = {0}", commandExecutors.Count);
}
private void CommandExecutor_CommandExecuted(object sender, EventArgs e)
{
Log.Debug("CommandExecutor_CommandExecuted: begin.");
var notify = false;
lock (_locker)
{
if (_commandTasks.Count > 0)
{
notify = true;
}
}
if (notify)
{
NotifyCommandReady();
}
Log.Debug("CommandExecutor_CommandExecuted: end.");
}
#endregion
}
}
+91 -52
View File
@@ -1,18 +1,20 @@
using System;
using log4net;
using System.Collections.Generic;
namespace MTApiService
{
public class MtExpert
internal class MtExpert: ITaskExecutor
{
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
public delegate void MtEventHandler(MtExpert expert, MtEvent e);
#region Private Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert));
private readonly IMetaTraderHandler _mtHadler;
private MtCommandTask _commandTask;
private ICommandManager _commandManager;
private MtCommandTask _currentTask;
private readonly Queue<MtCommandTask> _taskQueue = new Queue<MtCommandTask>();
private readonly object _locker = new object();
#endregion
@@ -41,9 +43,8 @@ namespace MTApiService
{
Log.DebugFormat("SendResponse: begin. response = {0}", response);
_commandTask.SetResult(response);
_commandTask = null;
FireOnCommandExecuted();
_currentTask.SetResult(response);
_currentTask = null;
Log.Debug("SendResponse: end.");
}
@@ -52,20 +53,16 @@ namespace MTApiService
{
Log.Debug("GetCommandType: called.");
var commandManager = CommandManager;
if (commandManager != null)
{
_commandTask = commandManager.DequeueCommandTask();
}
_currentTask = DequeueTask();
return _commandTask?.Command?.CommandType ?? 0;
return _currentTask?.Command?.CommandType ?? 0;
}
public object GetCommandParameter(int index)
{
Log.DebugFormat("GetCommandType: called. index = {0}", index);
Log.DebugFormat("GetCommandParameter: called. index = {0}", index);
var command = _commandTask?.Command;
var command = _currentTask?.Command;
if (command?.Parameters != null && index >= 0 && index < command.Parameters.Count)
{
return command.Parameters[index];
@@ -74,6 +71,46 @@ namespace MTApiService
return null;
}
public object GetNamedParameter(string name)
{
Log.DebugFormat("GetNamedParameter: called. name = {0}", name);
var command = _currentTask?.Command;
if (command == null)
{
Log.Warn("GetNamedParameter: command is not defined in task.");
return null;
}
if (command.NamedParams == null)
{
Log.Warn("GetNamedParameter: NamedParams is not defined in command.");
return null;
}
return command.NamedParams[name];
}
public bool ContainsNamedParameter(string name)
{
Log.DebugFormat("ContainsNamedParameter: called. name = {0}", name);
var command = _currentTask?.Command;
if (command == null)
{
Log.Warn("ContainsNamedParameter: command is not defined in task.");
return false;
}
if (command.NamedParams == null)
{
Log.Warn("ContainsNamedParameter: NamedParams is not defined in command.");
return false;
}
return command.NamedParams.ContainsKey(name);
}
public void SendEvent(MtEvent mtEvent)
{
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
@@ -90,7 +127,22 @@ namespace MTApiService
#endregion
#region ITaskExecutor
public void Execute(MtCommandTask task)
{
lock (_taskQueue)
{
_taskQueue.Enqueue(task);
}
NotifyCommandReady();
}
#endregion
#region Properties
private MtQuote _quote;
public MtQuote Quote
{
@@ -133,41 +185,34 @@ namespace MTApiService
}
}
public ICommandManager CommandManager
{
private get
{
lock (_locker)
{
return _commandManager;
}
}
set
{
lock (_locker)
{
_commandManager = value;
}
}
}
#endregion
#region IMtCommandExecutor
public void NotifyCommandReady()
{
Log.Debug("NotifyCommandReady: begin.");
SendTickToMetaTrader();
Log.Debug("NotifyCommandReady: end.");
}
#endregion
#region Private Methods
private void SendTickToMetaTrader()
private MtCommandTask DequeueTask()
{
Log.Debug("DequeueTask: called.");
MtCommandTask task;
int count;
lock (_locker)
{
count = _taskQueue.Count;
task = _taskQueue.Count > 0 ? _taskQueue.Dequeue() : null;
}
Log.DebugFormat("DequeueTask: end. left task count = {0}.", count);
return task;
}
private void NotifyCommandReady()
{
Log.Debug("NotifyCommandReady: begin.");
_mtHadler.SendTickToMetaTrader(Handle);
Log.Debug("NotifyCommandReady: end.");
}
private void FireOnQuoteChanged(MtQuote quote)
@@ -180,22 +225,16 @@ namespace MTApiService
Deinited?.Invoke(this, EventArgs.Empty);
}
private void FireOnCommandExecuted()
{
CommandExecuted?.Invoke(this, EventArgs.Empty);
}
private void FireOnMtEvent(MtEvent mtEvent)
{
OnMtEvent?.Invoke(this, new MtEventArgs(mtEvent));
OnMtEvent?.Invoke(this, mtEvent);
}
#endregion
#region Events
public event EventHandler Deinited;
public event MtQuoteHandler QuoteChanged;
public event EventHandler CommandExecuted;
public event EventHandler<MtEventArgs> OnMtEvent;
public event MtEventHandler OnMtEvent;
#endregion
}
}
-29
View File
@@ -1,29 +0,0 @@
using System.Runtime.Serialization;
namespace MTApiService
{
[DataContract]
public class MtQuote
{
[DataMember]
public string Instrument { get; private set; }
[DataMember]
public double Bid { get; private set; }
[DataMember]
public double Ask { get; private set; }
public MtQuote(string instrument, double bid, double ask)
{
Instrument = instrument;
Bid = bid;
Ask = ask;
}
public override string ToString()
{
return "Instrument = " + Instrument + ", Bid = " + Bid + ", Ask = " + Ask;
}
}
}
+25
View File
@@ -0,0 +1,25 @@
using System.Runtime.Serialization;
namespace MTApiService
{
[DataContract]
public class MtQuote
{
[DataMember]
public string Instrument { get; internal set; }
[DataMember]
public double Bid { get; internal set; }
[DataMember]
public double Ask { get; internal set; }
[DataMember]
public int ExpertHandle { get; internal set; }
public override string ToString()
{
return $"Instrument = {Instrument}; Bid = {Bid}; Ask = {Ask}; ExpertHandle = {ExpertHandle}";
}
}
}
+24 -1
View File
@@ -12,7 +12,8 @@ namespace MTApiService
{
static IEnumerable<Type> GetKnownTypes()
{
return new Type[] { typeof(MtResponseInt), typeof(MtResponseDouble),
return new Type[] { typeof(MtResponseObject),
typeof(MtResponseInt), typeof(MtResponseDouble),
typeof(MtResponseString), typeof(MtResponseBool),
typeof(MtResponseLong), typeof(MtResponseULong),
typeof(MtResponseDoubleArray), typeof(MtResponseIntArray),
@@ -22,6 +23,28 @@ namespace MTApiService
}
public abstract object GetValue();
[DataMember]
public int ErrorCode { get; set; }
}
[DataContract]
public class MtResponseObject : MtResponse
{
public MtResponseObject(object value)
{
Value = value;
}
[DataMember]
public object Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value?.ToString() ?? string.Empty;
}
}
[DataContract]
+18 -9
View File
@@ -21,7 +21,7 @@ namespace MTApiService
private readonly MtService _service;
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
private readonly MtExecutorManager _executorManager = new MtExecutorManager();
private readonly List<MtExpert> _experts = new List<MtExpert>();
#endregion
@@ -149,7 +149,7 @@ namespace MTApiService
_experts.Add(expert);
}
_executorManager.AddCommandExecutor(expert);
_executorManager.AddExecutor(expert);
_service.OnQuoteAdded(expert.Quote);
@@ -170,11 +170,20 @@ namespace MTApiService
return null;
}
var task = new MtCommandTask(command);
_executorManager.EnqueueCommandTask(task);
var task = _executorManager.SendCommand(command);
//wait for execute command in MetaTrader
var response = task.WaitResult(WaitResponseTime);
MtResponse response = null;
try
{
response = task.WaitResult(WaitResponseTime);
}
catch (Exception ex)
{
Log.WarnFormat("SendCommand: Exception - {0}", ex.Message);
}
Log.DebugFormat("SendCommand: end. response = {0}", response);
return response;
}
@@ -371,7 +380,7 @@ namespace MTApiService
expertsCount = _experts.Count;
}
_executorManager.RemoveCommandExecutor(expert);
_executorManager.RemoveExecutor(expert);
expert.Deinited -= expert_Deinited;
expert.QuoteChanged -= expert_QuoteChanged;
@@ -398,11 +407,11 @@ namespace MTApiService
Log.Debug("expert_QuoteChanged: end.");
}
private void Expert_OnMtEvent(object sender, MtEventArgs e)
private void Expert_OnMtEvent(MtExpert expert, MtEvent e)
{
Log.DebugFormat("Expert_OnMtEvent: begin. event = {0}", e.Event);
Log.DebugFormat("Expert_OnMtEvent: begin. expert = {0}, event = {1}", expert, e);
_service.OnMtEvent(e.Event);
_service.OnMtEvent(e);
Log.Debug("Expert_OnMtEvent: end.");
}
+7 -7
View File
@@ -66,7 +66,7 @@ namespace MTApiService
if (callback == null)
{
Log.Warn("Connect: end. Callback is not definded.");
Log.Warn("Connect: end. Callback is not defined.");
return false;
}
@@ -158,7 +158,7 @@ namespace MTApiService
public void QuoteUpdate(MtQuote quote)
{
Log.Debug("QuoteUpdate: begin.");
Log.DebugFormat("QuoteUpdate: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
@@ -167,7 +167,7 @@ namespace MTApiService
public void OnQuoteAdded(MtQuote quote)
{
Log.Debug("OnQuoteAdded: begin.");
Log.DebugFormat("OnQuoteAdded: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
@@ -176,18 +176,18 @@ namespace MTApiService
public void OnQuoteRemoved(MtQuote quote)
{
Log.Debug("OnQuoteRemoved: begin.");
Log.DebugFormat("OnQuoteRemoved: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
Log.Debug("OnQuoteRemoved: end.");
}
public void OnMtEvent(MtEvent mtEvent)
public void OnMtEvent(MtEvent e)
{
Log.Debug("OnMtEvent: begin.");
Log.DebugFormat("OnMtEvent: begin.quote = {0}", e);
ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
ExecuteCallbackAction(a => a.OnMtEvent(e));
Log.Debug("OnMtEvent: end.");
}
+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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.23.0")]
[assembly: AssemblyFileVersion("1.0.23.0")]
[assembly: AssemblyVersion("1.0.25.0")]
[assembly: AssemblyFileVersion("1.0.25.0")]
+179 -199
View File
@@ -4,7 +4,8 @@
#include "MT4Handler.h"
#include "Windows.h"
#include < vcclr.h >
#include <vcclr.h>
#include <functional>
using namespace System;
using namespace MTApiService;
@@ -17,6 +18,8 @@ using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Diagnostics;
#define _DLLAPI extern "C" __declspec(dllexport)
void convertSystemString(wchar_t* dest, String^ src)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(src);
@@ -24,264 +27,241 @@ void convertSystemString(wchar_t* dest, String^ src)
dest[wcslen(wch)] = '\0';
}
int _stdcall initExpert(int expertHandle, int port, wchar_t* symbol, double bid, double ask, wchar_t* err)
template <typename T> T Execute(std::function<T()> func, wchar_t* err, T default_value)
{
T result = default_value;
try
{
result = func();
}
catch (Exception^ e)
{
convertSystemString(err, e->Message);
}
return result;
}
_DLLAPI bool _stdcall initExpert(int expertHandle, int port, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
return Execute<bool>([&expertHandle, &port, symbol, &bid, &ask]() {
MT4Handler^ mtHandler = gcnew MT4Handler();
MtAdapter::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHandler);
return true;
}, err, false);
MtServerInstance::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHandler);
}
catch (Exception^ e)
{
convertSystemString(err, e->Message);
Debug::WriteLine("[ERROR] MTConnector:initExpert(): " + e->Message);
return 0;
}
return 1;
}
int _stdcall deinitExpert(int expertHandle, wchar_t* err)
_DLLAPI bool _stdcall deinitExpert(int expertHandle, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->DeinitExpert(expertHandle);
}
catch (Exception^ e)
{
convertSystemString(err, e->Message);
Debug::WriteLine("[ERROR] MTConnector:deinitExpert(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle]() {
MtAdapter::GetInstance()->DeinitExpert(expertHandle);
return true;
}, err, false);
}
int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double ask, wchar_t* err)
_DLLAPI bool _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
}
catch (Exception^ e)
{
convertSystemString(err, e->Message);
Debug::WriteLine("[ERROR] MTConnector:updateQuote(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, symbol, &bid, &ask]() {
MtAdapter::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
return true;
}, err, false);
}
int _stdcall sendEvent(int expertHandle, int eventType, wchar_t* payload, wchar_t* err)
_DLLAPI bool _stdcall sendEvent(int expertHandle, int eventType, wchar_t* payload, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendEvent(expertHandle, eventType, gcnew String(payload));
}
catch (Exception^ e)
{
convertSystemString(err, e->Message);
Debug::WriteLine("[ERROR] MTConnector:updateTimeBar(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &eventType, payload]() {
MtAdapter::GetInstance()->SendEvent(expertHandle, eventType, gcnew String(payload));
return true;
}, err, false);
}
int _stdcall sendIntResponse(int expertHandle, int response)
_DLLAPI bool _stdcall sendIntResponse(int expertHandle, int response, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendIntResponse(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &response]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
return true;
}, err, false);
}
int _stdcall sendBooleanResponse(int expertHandle, int response)
_DLLAPI bool _stdcall sendBooleanResponse(int expertHandle, bool response, wchar_t* err)
{
try
{
bool value = (response != 0) ? true : false;
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(value));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendBooleanResponse(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &response]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(response));
return true;
}, err, false);
}
int _stdcall sendDoubleResponse(int expertHandle, double response)
_DLLAPI bool _stdcall sendDoubleResponse(int expertHandle, double response, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendDoubleResponse(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &response]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
return true;
}, err, false);
}
int _stdcall sendStringResponse(int expertHandle, wchar_t* response)
_DLLAPI bool _stdcall sendStringResponse(int expertHandle, wchar_t* response, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendStringResponse(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, response]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
return true;
}, err, false);
}
int _stdcall sendVoidResponse(int expertHandle)
_DLLAPI bool _stdcall sendErrorResponse(int expertHandle, int code, wchar_t* message, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendResponse(expertHandle, nullptr);
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendVoidResponse(): " + e->Message);
return 0;
}
return 1;
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);
}
int _stdcall sendDoubleArrayResponse(int expertHandle, double* values, int size)
_DLLAPI bool _stdcall sendVoidResponse(int expertHandle, wchar_t* err)
{
try
{
return Execute<bool>([&expertHandle]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseObject(nullptr));
return true;
}, err, false);
}
_DLLAPI bool _stdcall sendDoubleArrayResponse(int expertHandle, double* values, int size, wchar_t* err)
{
return Execute<bool>([&expertHandle, values, &size]() {
array<double>^ list = gcnew array<double>(size);
for(int i = 0; i < size; i++)
for (int i = 0; i < size; i++)
{
list[i] = values[i];
}
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendDoubleArrayResponse(): " + e->Message);
return 0;
}
return 1;
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
return true;
}, err, false);
}
int _stdcall sendIntArrayResponse(int expertHandle, int* values, int size)
_DLLAPI bool _stdcall sendIntArrayResponse(int expertHandle, int* values, int size, wchar_t* err)
{
try
{
return Execute<bool>([&expertHandle, values, &size]() {
array<int>^ list = gcnew array<int>(size);
for(int i = 0; i < size; i++)
for (int i = 0; i < size; i++)
{
list[i] = values[i];
}
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendIntArrayResponse(): " + e->Message);
return 0;
}
return 1;
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
return true;
}, err, false);
}
int _stdcall sendLongResponse(int expertHandle, __int64 response)
_DLLAPI bool _stdcall sendLongResponse(int expertHandle, __int64 response, wchar_t* err)
{
try
{
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:sendLongResponse(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &response]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
return true;
}, err, false);
}
int _stdcall getCommandType(int expertHandle, int* res)
_DLLAPI bool _stdcall getCommandType(int expertHandle, int* res, wchar_t* err)
{
try
{
*res = MtServerInstance::GetInstance()->GetCommandType(expertHandle);
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:getCommandType(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, res]() {
*res = MtAdapter::GetInstance()->GetCommandType(expertHandle);
return true;
}, err, false);
}
int _stdcall getIntValue(int expertHandle, int paramIndex, int* res)
_DLLAPI bool _stdcall getIntValue(int expertHandle, int paramIndex, int* res, wchar_t* err)
{
try
{
*res = (int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:getIntValue(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &paramIndex, res]() {
*res = (int)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return true;
}, err, false);
}
int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res)
// --- index parameters
_DLLAPI bool _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res, wchar_t* err)
{
try
{
*res = (double)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:getDoubleValue(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &paramIndex, res]() {
*res = (double)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return true;
}, err, false);
}
int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res)
_DLLAPI bool _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res, wchar_t* err)
{
try
{
convertSystemString(res, (String^)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MTConnector:getStringValue(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &paramIndex, res]() {
convertSystemString(res, (String^)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
return true;
}, err, false);
}
int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res)
_DLLAPI bool _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res, wchar_t* err)
{
try
{
bool val = (bool)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
*res = val == true ? 1 : 0;
}
catch (Exception^ e)
{
Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
return 0;
}
return 1;
return Execute<bool>([&expertHandle, &paramIndex, res]() {
*res = (bool)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return true;
}, err, false);
}
_DLLAPI bool _stdcall getLongValue(int expertHandle, int paramIndex, __int64* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, &paramIndex, res]() {
*res = (__int64)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return true;
}, err, false);
}
// --- named parameters
_DLLAPI bool _stdcall containsNamedValue(int expertHandle, wchar_t* paramName)
{
wchar_t err[1000];
return Execute<bool>([&expertHandle, paramName]() {
return MtAdapter::GetInstance()->ContainsNamedParameter(expertHandle, gcnew String(paramName));
}, err, false);
}
_DLLAPI bool _stdcall getNamedIntValue(int expertHandle, wchar_t* paramName, int* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, paramName, res]() {
System::Object^ obj = MtAdapter::GetInstance()->GetNamedParameter(expertHandle, gcnew String(paramName));
*res = (int)obj;
return true;
}, err, false);
}
_DLLAPI bool _stdcall getNamedDoubleValue(int expertHandle, wchar_t* paramName, double* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, paramName, res]() {
System::Object^ obj = MtAdapter::GetInstance()->GetNamedParameter(expertHandle, gcnew String(paramName));
*res = (double)obj;
return true;
}, err, false);
}
_DLLAPI bool _stdcall getNamedStringValue(int expertHandle, wchar_t* paramName, wchar_t* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, paramName, res]() {
System::Object^ obj = MtAdapter::GetInstance()->GetNamedParameter(expertHandle, gcnew String(paramName));
convertSystemString(res, (String^)obj);
return true;
}, err, false);
}
_DLLAPI bool _stdcall getNamedBooleanValue(int expertHandle, wchar_t* paramName, int* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, paramName, res]() {
System::Object^ obj = MtAdapter::GetInstance()->GetNamedParameter(expertHandle, gcnew String(paramName));
*res = (bool)obj;
return true;
}, err, false);
}
_DLLAPI bool _stdcall getNamedLongValue(int expertHandle, wchar_t* paramName, __int64* res, wchar_t* err)
{
return Execute<bool>([&expertHandle, paramName, res]() {
System::Object^ obj = MtAdapter::GetInstance()->GetNamedParameter(expertHandle, gcnew String(paramName));
if (obj != nullptr)
*res = (__int64)obj;
return true;
}, err, false);
}
-19
View File
@@ -1,19 +0,0 @@
LIBRARY MTConnector
EXPORTS initExpert
deinitExpert
updateQuote
sendEvent
sendIntResponse
sendBooleanResponse
sendDoubleResponse
sendStringResponse
sendVoidResponse
sendDoubleArrayResponse
sendIntArrayResponse
sendLongResponse
getCommandType
getIntValue
getDoubleValue
getStringValue
getBooleanValue
-5
View File
@@ -96,7 +96,6 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\MTConnector.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -109,7 +108,6 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\MTConnector.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -121,7 +119,6 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\MTConnector.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -133,7 +130,6 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\MTConnector.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -154,7 +150,6 @@
</ItemGroup>
<ItemGroup>
<None Include="app.ico" />
<None Include="MTConnector.def" />
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
-3
View File
@@ -44,9 +44,6 @@
<None Include="app.ico">
<Filter>Resource Files</Filter>
</None>
<None Include="MTConnector.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="app.rc">
+9
View File
@@ -0,0 +1,9 @@
namespace MtApi
{
enum EnumColorFormat
{
COLOR_FORMAT_XRGB_NOALPHA = 0, //The component of the alpha channel is ignored
COLOR_FORMAT_ARGB_RAW = 1, //Color components are not handled by the terminal (must be correctly set by the user)
COLOR_FORMAT_ARGB_NORMALIZE = 2 //Color components are handled by the terminal
}
}
+46
View File
@@ -0,0 +1,46 @@
namespace MtApi
{
public enum EnumObject
{
OBJ_VLINE = 0, //Vertical Line
OBJ_HLINE = 1, //Horizontal Line
OBJ_TREND = 2, //Trend Line
BJ_TRENDBYANGLE = 3, //Trend Line By Angle
OBJ_CYCLES = 20, //Cycle Lines
OBJ_CHANNEL = 5, //Equidistant Channel
OBJ_STDDEVCHANNEL = 6, //Standard Deviation Channel
OBJ_REGRESSION = 4, //Linear Regression Channel
OBJ_PITCHFORK = 19, //Andrews’ Pitchfork
OBJ_GANNLINE = 7, //Gann Line
OBJ_GANNFAN = 8, //Gann Fan
OBJ_GANNGRID = 9, //Gann Grid
OBJ_FIBO = 10, //Fibonacci Retracement
OBJ_FIBOTIMES = 11, //Fibonacci Time Zones
OBJ_FIBOFAN = 12, //Fibonacci Fan
OBJ_FIBOARC = 13, //Fibonacci Arcs
OBJ_FIBOCHANNEL = 15, //Fibonacci Channel
OBJ_EXPANSION = 14, //Fibonacci Expansion
OBJ_RECTANGLE = 16, //Rectangle
OBJ_TRIANGLE = 17, //Triangle
OBJ_ELLIPSE = 18, //Ellipse
OBJ_ARROW_THUMB_UP = 29, //Thumbs Up
OBJ_ARROW_THUMB_DOWN = 30, //Thumbs Down
OBJ_ARROW_UP = 31, //Arrow Up
OBJ_ARROW_DOWN = 32, //Arrow Down
OBJ_ARROW_STOP = 33, //Stop Sign
OBJ_ARROW_CHECK = 34, //Check Sign
OBJ_ARROW_LEFT_PRICE = 35, //Left Price Label
OBJ_ARROW_RIGHT_PRICE = 36, //Right Price Label
OBJ_ARROW_BUY = 37, //Buy Sign
OBJ_ARROW_SELL = 38, //Sell Sign
OBJ_ARROW = 22, //Arrow
OBJ_TEXT = 21, //Text
OBJ_LABEL = 23, //Label
OBJ_BUTTON = 25, //Button
OBJ_BITMAP = 26, //Bitmap
OBJ_BITMAP_LABEL = 24, //Bitmap Label
OBJ_EDIT = 27, //Edit
OBJ_EVENT = 42, //The "Event" object corresponding to an event in the economic calendar
OBJ_RECTANGLE_LABEL = 28 //The "Rectangle label" object for creating and designing the custom graphical interface.
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace MtApi
{
public enum EnumObjectPropertyDouble
{
OBJPROP_PRICE = 20, // Price coordinate
OBJPROP_LEVELVALUE = 204, // Level value
OBJPROP_SCALE = 12, // Scale (properties of Gann objects, Fibonacci Arcs and Ellipse)
OBJPROP_ANGLE = 13, // Angle. For the objects with no angle specified, created from a program, the value is equal to EMPTY_VALUE
OBJPROP_DEVIATION = 16, // Deviation for the Standard Deviation Channel
}
}
+40
View File
@@ -0,0 +1,40 @@
namespace MtApi
{
public enum EnumObjectPropertyInteger
{
OBJPROP_COLOR = 6,
OBJPROP_STYLE = 7,
OBJPROP_WIDTH = 8,
OBJPROP_BACK = 9,
OBJPROP_ZORDER = 207,
OBJPROP_HIDDEN = 208,
OBJPROP_SELECTED = 17,
OBJPROP_READONLY = 1028,
OBJPROP_TYPE = 18,
OBJPROP_TIME = 19,
OBJPROP_SELECTABLE = 1000,
OBJPROP_CREATETIME = 998,
OBJPROP_LEVELS = 200,
OBJPROP_LEVELCOLOR = 201,
OBJPROP_LEVELSTYLE = 202,
OBJPROP_LEVELWIDTH = 203,
OBJPROP_ALIGN = 1036,
OBJPROP_FONTSIZE = 100,
OBJPROP_RAY_RIGHT = 1004,
OBJPROP_ELLIPSE = 11,
OBJPROP_ARROWCODE = 14,
OBJPROP_TIMEFRAMES = 15,
OBJPROP_ANCHOR = 1011,
OBJPROP_XDISTANCE = 102,
OBJPROP_YDISTANCE = 103,
OBJPROP_STATE = 1018,
OBJPROP_XSIZE = 1019,
OBJPROP_YSIZE = 1020,
OBJPROP_XOFFSET = 1033,
OBJPROP_YOFFSET = 1034,
OBJPROP_BGCOLOR = 1025,
OBJPROP_CORNER = 101,
OBJPROP_BORDER_TYPE = 1029,
OBJPROP_BORDER_COLOR = 1035
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace MtApi
{
public enum EnumObjectPropertyString
{
OBJPROP_NAME = 1037,
OBJPROP_TEXT = 999,
OBJPROP_TOOLTIP = 206,
OBJPROP_LEVELTEXT = 205,
OBJPROP_FONT = 1001,
OBJPROP_BMPFILE = 1017,
OBJPROP_SYMBOL = 1021
}
}
-42
View File
@@ -1,42 +0,0 @@
using System;
using System.Threading.Tasks;
namespace MtApi
{
static class ExtensionMethods
{
#region Event Methods
public static Task FireEventAsync(this MtApiQuoteHandler evenHandler, object sender, string symbol, double bid, double ask)
{
return Task.Factory.StartNew(() =>
{
evenHandler?.Invoke(sender, symbol, bid, ask);
});
}
public static Task FireEventAsync(this EventHandler eventHandler, object sender)
{
return Task.Factory.StartNew(() =>
{
eventHandler?.Invoke(sender, EventArgs.Empty);
});
}
public static Task FireEventAsync<T>(this EventHandler<T> eventHandler, object sender, T e)
where T : EventArgs
{
return Task.Factory.StartNew(() =>
{
eventHandler?.Invoke(sender, e);
});
}
#endregion
public static MtQuote Convert(this MTApiService.MtQuote quote)
{
return (quote != null) ? new MtQuote(quote.Instrument, quote.Bid, quote.Ask) : null;
}
}
}
+30
View File
@@ -0,0 +1,30 @@
using System;
namespace MtApi
{
[Flags]
public enum FlagFontStyle
{
//Flags for specifying font style
FONT_ITALIC = -2147483648,
FONT_UNDERLINE = 1073741824,
FONT_STRIKEOUT = 536870912,
//Flags for specifying font width
FW_DONTCARE = 0,
FW_THIN = 1,
FW_EXTRALIGHT = 2,
FW_ULTRALIGHT = 3,
FW_LIGHT = 4,
FW_NORMAL = 5,
FW_REGULAR = 6,
FW_MEDIUM = 7,
FW_SEMIBOLD = 8,
FW_DEMIBOLD = 9,
FW_BOLD = 10,
FW_EXTRABOLD = 11,
FW_ULTRABOLD = 12,
FW_HEAVY = 13,
FW_BLACK = 14
}
}
+6 -1
View File
@@ -59,12 +59,17 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ChartPeriod.cs" />
<Compile Include="EnumColorFormat.cs" />
<Compile Include="EnumObject.cs" />
<Compile Include="EnumObjectPropertyDouble.cs" />
<Compile Include="EnumObjectPropertyInteger.cs" />
<Compile Include="EnumObjectPropertyString.cs" />
<Compile Include="EnumSeriesInfoInteger.cs" />
<Compile Include="EnumSymbolInfoDouble.cs" />
<Compile Include="EnumSymbolInfoInteger.cs" />
<Compile Include="EnumTerminalInfoDouble.cs" />
<Compile Include="EnumTerminalInfoInteger.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="FlagFontStyle.cs" />
<Compile Include="Monitors\AvailabilityOrdersEventArgs.cs" />
<Compile Include="MqlRates.cs" />
<Compile Include="MqlTick.cs" />
+633 -108
View File
@@ -8,6 +8,7 @@ using System.ServiceModel;
using MtApi.Requests;
using MtApi.Responses;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace MtApi
{
@@ -15,8 +16,6 @@ namespace MtApi
public sealed class MtApiClient
{
private volatile bool _isBacktestingMode;
#region MetaTrader Constants
//Special constant
@@ -27,9 +26,11 @@ namespace MtApi
#endregion
#region Private Fields
private readonly MtClient _client = new MtClient();
private MtClient _client;
private readonly object _locker = new object();
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
private volatile bool _isBacktestingMode;
private int _executorHandle;
#endregion
#region ctor
@@ -37,13 +38,6 @@ namespace MtApi
public MtApiClient()
{
LogConfigurator.Setup(LogProfileName);
_client.QuoteAdded += _client_QuoteAdded;
_client.QuoteRemoved += _client_QuoteRemoved;
_client.QuoteUpdated += _client_QuoteUpdated;
_client.ServerDisconnected += _client_ServerDisconnected;
_client.ServerFailed += _client_ServerFailed;
_client.MtEventReceived += _client_MtEventReceived;
}
#endregion
@@ -55,8 +49,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(string host, int port)
{
Action<string, int> connectAction = Connect;
connectAction.BeginInvoke(host, port, null, null);
Task.Factory.StartNew(() => Connect(host, port));
}
///<summary>
@@ -65,8 +58,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(int port)
{
Action<int> connectAction = Connect;
connectAction.BeginInvoke(port, null, null);
Task.Factory.StartNew(() => Connect(port));
}
///<summary>
@@ -74,21 +66,17 @@ namespace MtApi
///</summary>
public void BeginDisconnect()
{
Action disconnectAction = Disconnect;
disconnectAction.BeginInvoke(null, null);
Task.Factory.StartNew(() => Disconnect(false));
}
///<summary>
///Load quotes connected into MetaTrader API.
///</summary>
public IEnumerable<MtQuote> GetQuotes()
public List<MtQuote> GetQuotes()
{
IEnumerable<MTApiService.MtQuote> quotes;
lock (_client)
{
quotes = _client.GetQuotes();
}
return quotes?.Select(q => q.Convert());
var client = Client;
var quotes = client != null ? client.GetQuotes() : null;
return quotes?.Select(q => new MtQuote(q)).ToList();
}
#endregion
@@ -107,6 +95,27 @@ namespace MtApi
}
}
}
///<summary>
///Handle of expert used to execute commands
///</summary>
public int ExecutorHandle
{
get
{
lock (_locker)
{
return _executorHandle;
}
}
set
{
lock (_locker)
{
_executorHandle = value;
}
}
}
#endregion
@@ -852,10 +861,10 @@ namespace MtApi
return SendCommand<int>(MtCommandType.MessageBox, commandParameters);
}
public void PlaySound(string filename)
public bool PlaySound(string filename)
{
var commandParameters = new ArrayList { filename };
SendCommand<object>(MtCommandType.PlaySound, commandParameters);
return SendCommand<bool>(MtCommandType.PlaySound, commandParameters);
}
public void Print(string msg)
@@ -876,10 +885,10 @@ namespace MtApi
return SendCommand<bool>(MtCommandType.SendFTPA, commandParameters);
}
public void SendMail(string subject, string someText)
public bool SendMail(string subject, string someText)
{
var commandParameters = new ArrayList { subject, someText };
SendCommand<object>(MtCommandType.SendMail, commandParameters);
return SendCommand<bool>(MtCommandType.SendMail, commandParameters);
}
public void Sleep(int milliseconds)
@@ -1704,45 +1713,555 @@ namespace MtApi
}
#endregion
#region Private Methods
private void Connect(string host, int port)
#region Chart Operations
///<summary>
///Returns the ID of the current chart.
///</summary>
///<returns>
/// Value of long type.
///</returns>
public long ChartId()
{
UpdateConnectionState(MtConnectionState.Connecting, $"Connecting to {host}:{port}");
try
return SendCommand<long>(MtCommandType.ChartId, null);
}
///<summary>
///This function calls a forced redrawing of a specified chart.
///</summary>
public void ChartRedraw(long chartId = 0)
{
var commandParameters = new ArrayList { chartId };
SendCommand<object>(MtCommandType.ChartRedraw, commandParameters);
}
#endregion
#region Object Functions
///<summary>
///The function creates an object with the specified name, type, and the initial coordinates in the specified chart subwindow of the specified chart.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object. The name must be unique within a chart, including its subwindows.</param>
///<param name="objectType">Object type.</param>
///<param name="subWindow">Number of the chart subwindow. 0 means the main chart window.</param>
///<param name="time1">The time coordinate of the first anchor point.</param>
///<param name="price1">The price coordinate of the first anchor point.</param>
///<param name="time2">The time coordinate of the second anchor point.</param>
///<param name="price2">The price coordinate of the second anchor point.</param>
///<param name="time3">The time coordinate of the third anchor point.</param>
///<param name="price3">The price coordinate of the third anchor point.</param>
///<returns>
///Returns true or false depending on whether the object is created or not.
///</returns>
public bool ObjectCreate(long chartId, string objectName, EnumObject objectType, int subWindow,
DateTime? time1, double price1, DateTime? time2 = null, double? price2 = null, DateTime? time3 = null, double? price3 = null)
{
var namedParams = new Dictionary<string, object>
{
lock (_client)
{nameof(chartId), chartId},
{nameof(objectName), objectName},
{nameof(objectType), (int) objectType},
{nameof(subWindow), subWindow},
{nameof(time1), MtApiTimeConverter.ConvertToMtTime(time1)},
{nameof(price1), price1}
};
if (time2 != null)
namedParams.Add(nameof(time2), MtApiTimeConverter.ConvertToMtTime(time2.Value));
if (price2 != null)
namedParams.Add(nameof(price2), price2.Value);
if (time3 != null)
namedParams.Add(nameof(time3), MtApiTimeConverter.ConvertToMtTime(time3.Value));
if (price3 != null)
namedParams.Add(nameof(price3), price3.Value);
return SendCommand<bool>(MtCommandType.ObjectCreate, null, namedParams);
}
///<summary>
///The function returns the name of the corresponding object by its index in the objects list.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectIndex">Object index. This value must be greater or equal to 0 and less than ObjectsTotal().</param>
///<param name="subWindow">Number of the chart window. Must be greater or equal to -1 (-1 mean all subwindows, 0 means the main chart window) and less than WindowsTotal().</param>
///<param name="objectType">Type of the object. The value can be one of the values of the EnumObject enumeration. EMPTY (-1) means all types.</param>
///<returns>
///Name of the object is returned in case of success.
///</returns>
public string ObjectName(long chartId, int objectIndex, int subWindow = EMPTY, int objectType = EMPTY)
{
var commandParameters = new ArrayList { chartId, objectIndex, subWindow, objectType };
return SendCommand<string>(MtCommandType.ObjectName, commandParameters);
}
///<summary>
///The function removes the object with the specified name at the specified chart.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of object to be deleted.</param>
///<returns>
///Returns true if the removal was successful, otherwise returns false.
///</returns>
public bool ObjectDelete(long chartId, string objectName)
{
var commandParameters = new ArrayList { chartId, objectName };
return SendCommand<bool>(MtCommandType.ObjectDelete, commandParameters);
}
///<summary>
///The function removes the object with the specified name at the specified chart.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="subWindow">Number of the chart window. Must be greater or equal to -1 (-1 mean all subwindows, 0 means the main chart window) and less than WindowsTotal().</param>
///<param name="objectType">Type of the object. The value can be one of the values of the EnumObject enumeration. EMPTY (-1) means all types.</param>
///<returns>
///Returns true if the removal was successful, otherwise returns false.
///</returns>
public int ObjectsDeleteAll(long chartId, int subWindow = EMPTY, int objectType = EMPTY)
{
var commandParameters = new ArrayList { chartId, subWindow, objectType };
return SendCommand<int>(MtCommandType.ObjectsDeleteAll, commandParameters);
}
///<summary>
///The function searches for an object having the specified name.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">The name of the object to find.</param>
///<returns>
///If successful the function returns the number of the subwindow (0 means the main window of the chart), in which the object is found.
///</returns>
public int ObjectFind(long chartId, string objectName)
{
var commandParameters = new ArrayList { chartId, objectName };
return SendCommand<int>(MtCommandType.ObjectFind, commandParameters);
}
///<summary>
///The function returns the time value for the specified price value of the specified object.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="value">Price value.</param>
///<param name="lineId">Line identifier.</param>
///<returns>
///The time value for the specified price value of the specified object.
///</returns>
public DateTime ObjectGetTimeByValue(long chartId, string objectName, double value, int lineId = 0)
{
var commandParameters = new ArrayList { chartId, objectName, value, lineId };
var res = SendCommand<int>(MtCommandType.ObjectGetTimeByValue, commandParameters);
return MtApiTimeConverter.ConvertFromMtTime(res);
}
///<summary>
///The function returns the price value for the specified time value of the specified object.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="time">Time value.</param>
///<param name="lineId">Line identifier.</param>
///<returns>
///The price value for the specified time value of the specified object.
///</returns>
public double ObjectGetValueByTime(long chartId, string objectName, DateTime? time, int lineId = 0)
{
var commandParameters = new ArrayList { chartId, objectName, time, lineId };
return SendCommand<double>(MtCommandType.ObjectGetValueByTime, commandParameters);
}
///<summary>
///The function changes coordinates of the specified anchor point of the object at the specified chart
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="pointIndex">Index of the anchor point.</param>
///<param name="time">Time coordinate of the selected anchor point.</param>
///<param name="price">Price coordinate of the selected anchor point.</param>
///<returns>
///If successful, returns true, in case of failure returns false.
///</returns>
public bool ObjectMove(long chartId, string objectName, int pointIndex, DateTime? time, double price)
{
var commandParameters = new ArrayList { chartId, objectName, pointIndex, MtApiTimeConverter.ConvertToMtTime(time), price };
return SendCommand<bool>(MtCommandType.ObjectMove, commandParameters);
}
///<summary>
///The function changes coordinates of the specified anchor point of the object at the specified chart.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="subWindow">Number of the chart subwindow. 0 means the main chart window, -1 means all the subwindows of the chart, including the main window.</param>
///<param name="type">Type of the object. The value can be one of the values of the EnumObject enumeration. EMPTY(-1) means all types.</param>
///<returns>
///The number of objects.
///</returns>
public int ObjectsTotal(long chartId, int subWindow = EMPTY, int type = EMPTY)
{
var commandParameters = new ArrayList { chartId, subWindow, type };
return SendCommand<int>(MtCommandType.ObjectsTotal, commandParameters);
}
///<summary>
///The function returns the value of the corresponding object property.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyDouble enumeration.</param>
///<param name="propModifier">Modifier of the specified property. For the first variant, the default modifier value is equal to 0. Most properties do not require a modifier.</param>
///<returns>
///Value of the double type.
///</returns>
public double ObjectGetDouble(long chartId, string objectName, EnumObjectPropertyDouble propId, int propModifier = 0)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propModifier };
return SendCommand<double>(MtCommandType.ObjectGetDouble, commandParameters);
}
///<summary>
///The function returns the value of the corresponding object property. The object property must be of the datetime, int, color, bool or char type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyDouble enumeration.</param>
///<param name="propModifier">Modifier of the specified property. For the first variant, the default modifier value is equal to 0. Most properties do not require a modifier.</param>
///<returns>
///The long value.
///</returns>
public long ObjectGetInteger(long chartId, string objectName, EnumObjectPropertyInteger propId, int propModifier = 0)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propModifier };
return SendCommand<long>(MtCommandType.ObjectGetInteger, commandParameters);
}
///<summary>
///The function returns the value of the corresponding object property. The object property must be of the string type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyString enumeration.</param>
///<param name="propModifier">Modifier of the specified property. For the first variant, the default modifier value is equal to 0. Most properties do not require a modifier. It denotes the number of the level in Fibonacci tools and in the graphical object Andrew's pitchfork. The numeration of levels starts from zero.</param>
///<returns>
///String value.
///</returns>
public string ObjectGetString(long chartId, string objectName, EnumObjectPropertyString propId, int propModifier = 0)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propModifier };
return SendCommand<string>(MtCommandType.ObjectGetString, commandParameters);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the double type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyDouble enumeration.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully.
///</returns>
public bool ObjectSetDouble(long chartId, string objectName, EnumObjectPropertyDouble propId, double propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
return SendCommand<bool>(MtCommandType.ObjectSetDouble, commandParameters);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the double type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyDouble enumeration.</param>
///<param name="propModifier">Modifier of the specified property. It denotes the number of the level in Fibonacci tools and in the graphical object Andrew's pitchfork. The numeration of levels starts from zero.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully.
///</returns>
public bool ObjectSetDouble(long chartId, string objectName, EnumObjectPropertyDouble propId, int propModifier, double propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
var namedParams = new Dictionary<string, object> {{nameof(propModifier), propModifier}};
return SendCommand<bool>(MtCommandType.ObjectSetDouble, commandParameters, namedParams);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the int type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyInteger enumeration.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully. Otherwise it returns false.
///</returns>
public bool ObjectSetInteger(long chartId, string objectName, EnumObjectPropertyInteger propId, long propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
return SendCommand<bool>(MtCommandType.ObjectSetInteger, commandParameters);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the int type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyInteger enumeration.</param>
///<param name="propModifier">Modifier of the specified property. It denotes the number of the level in Fibonacci tools and in the graphical object Andrew's pitchfork. The numeration of levels starts from zero.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully. Otherwise it returns false.
///</returns>
public bool ObjectSetInteger(long chartId, string objectName, EnumObjectPropertyInteger propId, int propModifier, long propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
var namedParams = new Dictionary<string, object> {{nameof(propModifier), propModifier}};
return SendCommand<bool>(MtCommandType.ObjectSetInteger, commandParameters, namedParams);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the string type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyString enumeration.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully. Otherwise it returns false.
///</returns>
public bool ObjectSetString(long chartId, string objectName, EnumObjectPropertyString propId, string propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
return SendCommand<bool>(MtCommandType.ObjectSetString, commandParameters);
}
///<summary>
///The function sets the value of the corresponding object property. The object property must be of the string type.
///</summary>
///<param name="chartId">Chart identifier. 0 means the current chart.</param>
///<param name="objectName">Name of the object.</param>
///<param name="propId">ID of the object property. The value can be one of the values of the EnumObjectPropertyString enumeration.</param>
///<param name="propModifier">Modifier of the specified property. It denotes the number of the level in Fibonacci tools and in the graphical object Andrew's pitchfork. The numeration of levels starts from zero.</param>
///<param name="propValue">The value of the property.</param>
///<returns>
///The function returns true only if the command to change properties of a graphical object has been sent to a chart successfully. Otherwise it returns false.
///</returns>
public bool ObjectSetString(long chartId, string objectName, EnumObjectPropertyString propId, int propModifier, string propValue)
{
var commandParameters = new ArrayList { chartId, objectName, (int)propId, propValue };
var namedParams = new Dictionary<string, object> {{nameof(propModifier), propModifier}};
return SendCommand<bool>(MtCommandType.ObjectSetString, commandParameters, namedParams);
}
///<summary>
///The function sets the font for displaying the text using drawing methods and returns the result of that operation. Arial font with the size -120 (12 pt) is used by default.
///</summary>
///<param name="name">Font name in the system or the name of the resource containing the font or the path to font file on the disk.</param>
///<param name="size">The font size that can be set using positive and negative values. In case of positive values, the size of a displayed text does not depend on the operating system's font size settings. In case of negative values, the value is set in tenths of a point and the text size depends on the operating system settings ("standard scale" or "large scale"). See the Note below for more information about the differences between the modes.</param>
///<param name="flags">Combination of flags describing font style.</param>
///<param name="orientation">Text's horizontal inclination to X axis, the unit of measurement is 0.1 degrees. It means that orientation=450 stands for inclination equal to 45 degrees.</param>
///<returns>
///Returns true if the current font is successfully installed, otherwise false.
///</returns>
public bool TextSetFont(string name, int size, FlagFontStyle flags = 0, int orientation = 0)
{
var commandParameters = new ArrayList { name, size, (uint)flags, orientation };
return SendCommand<bool>(MtCommandType.TextSetFont, commandParameters);
}
///<summary>
///Returns the object description.
///</summary>
///<param name="objectName">Object name.</param>
///<returns>
///Object description. For objects of OBJ_TEXT and OBJ_LABEL types, the text drawn by these objects will be returned.
///</returns>
public string ObjectDescription(string objectName)
{
var commandParameters = new ArrayList { objectName };
return SendCommand<string>(MtCommandType.ObjectDescription, commandParameters);
}
///<summary>
///Returns the level description of a Fibonacci object.
///</summary>
///<param name="objectName">Fibonacci object name.</param>
///<param name="index">Index of the Fibonacci level (0-31).</param>
///<returns>
///The level description of a Fibonacci object.
///</returns>
public string ObjectGetFiboDescription(string objectName, int index)
{
var commandParameters = new ArrayList { objectName, index };
return SendCommand<string>(MtCommandType.ObjectGetFiboDescription, commandParameters);
}
///<summary>
///The function calculates and returns bar index (shift related to the current bar) for the given price.
///</summary>
///<param name="objectName">Object name.</param>
///<param name="value">Price value.</param>
///<returns>
///The function calculates and returns bar index (shift related to the current bar) for the given price. The bar index is calculated by the first and second coordinates using a linear equation. Applied to trendlines and similar objects.
///</returns>
public int ObjectGetShiftByValue(string objectName, double value)
{
var commandParameters = new ArrayList { objectName, value };
return SendCommand<int>(MtCommandType.ObjectGetShiftByValue, commandParameters);
}
///<summary>
///The function calculates and returns the price value for the specified bar (shift related to the current bar).
///</summary>
///<param name="objectName">Object name.</param>
///<param name="shift">Bar index.</param>
///<returns>
///The function calculates and returns the price value for the specified bar (shift related to the current bar). The price value is calculated by the first and second coordinates using a linear equation. Applied to trendlines and similar objects.
///</returns>
public double ObjectGetValueByShift(string objectName, int shift)
{
var commandParameters = new ArrayList { objectName, shift };
return SendCommand<double>(MtCommandType.ObjectGetValueByShift, commandParameters);
}
///<summary>
///Changes the value of the specified object property.
///</summary>
///<param name="objectName">Object name.</param>
///<param name="index">Object property index. It can be any of object properties enumeration values.</param>
///<param name="value">New value of the given property.</param>
///<returns>
///If the function succeeds, the returned value will be true, otherwise it returns false.
///</returns>
public bool ObjectSet(string objectName, int index, double value)
{
var commandParameters = new ArrayList { objectName, index, value };
return SendCommand<bool>(MtCommandType.ObjectSet, commandParameters);
}
///<summary>
///The function sets a new description to a level of a Fibonacci object.
///</summary>
///<param name="objectName">Object name.</param>
///<param name="index">Index of the Fibonacci level (0-31).</param>
///<param name="text">New description of the level.</param>
///<returns>
///The function returns true if successful, otherwise false.
///</returns>
public bool ObjectSetFiboDescription(string objectName, int index, string text)
{
var commandParameters = new ArrayList { objectName, index, text };
return SendCommand<bool>(MtCommandType.ObjectSetFiboDescription, commandParameters);
}
///<summary>
///The function changes the object description.
///</summary>
///<param name="objectName">Object name.</param>
///<param name="text">A text describing the object.</param>
///<param name="fontSize">Font size in points.</param>
///<param name="fontName">Font name.</param>
///<param name="textColor">Font color.</param>
///<returns>
///Changes the object description. If the function succeeds, the returned value will be true, otherwise false.
///</returns>
public bool ObjectSetText(string objectName, string text, int fontSize = 0, string fontName = null, Color? textColor = null)
{
var commandParameters = new ArrayList { objectName, text, fontSize, fontName, MtApiColorConverter.ConvertToMtColor(textColor) };
return SendCommand<bool>(MtCommandType.ObjectSetText, commandParameters);
}
///<summary>
///The function returns the object type value.
///</summary>
///<param name="objectName">Object name.</param>
///<returns>
///The function returns the object type value.
///</returns>
public EnumObject ObjectType(string objectName)
{
var commandParameters = new ArrayList { objectName };
return (EnumObject)SendCommand<int>(MtCommandType.ObjectType, commandParameters);
}
#endregion
#region Private Methods
private MtClient Client
{
get
{
lock(_locker)
{
_client.Open(host, port);
_client.Connect();
return _client;
}
}
catch (Exception e)
}
private void Connect(MtClient client)
{
lock (_locker)
{
UpdateConnectionState(MtConnectionState.Failed, $"Failed connection to {host}:{port}. {e.Message}");
return;
if (_connectionState == MtConnectionState.Connected
|| _connectionState == MtConnectionState.Connecting)
{
return;
}
_connectionState = MtConnectionState.Connecting;
}
UpdateConnectionState(MtConnectionState.Connected, $"Connected to {host}:{port}");
OnConnected();
string message = string.IsNullOrEmpty(client.Host) ? $"Connecting to localhost:{client.Port}" : $"Connecting to {client.Host}:{client.Port}";
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connecting, message));
var state = MtConnectionState.Failed;
lock (_locker)
{
try
{
client.Connect();
state = MtConnectionState.Connected;
}
catch (Exception e)
{
client.Dispose();
message = string.IsNullOrEmpty(client.Host) ? $"Failed connection to localhost:{client.Port}. {e.Message}" : $"Failed connection to {client.Host}:{client.Port}. {e.Message}";
}
if (state == MtConnectionState.Connected)
{
_client = client;
_client.QuoteAdded += _client_QuoteAdded;
_client.QuoteRemoved += _client_QuoteRemoved;
_client.QuoteUpdated += _client_QuoteUpdated;
_client.ServerDisconnected += _client_ServerDisconnected;
_client.ServerFailed += _client_ServerFailed;
_client.MtEventReceived += _client_MtEventReceived;
message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}";
}
_connectionState = state;
}
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message));
if (state == MtConnectionState.Connected)
{
OnConnected();
}
}
private void Connect(string host, int port)
{
var client = new MtClient(host, port);
Connect(client);
}
private void Connect(int port)
{
UpdateConnectionState(MtConnectionState.Connecting, $"Connecting to 'localhost':{port}");
try
{
lock (_client)
{
_client.Open(port);
_client.Connect();
}
}
catch (Exception e)
{
UpdateConnectionState(MtConnectionState.Failed, $"Failed connection to 'localhost':{port}. {e.Message}");
return;
}
UpdateConnectionState(MtConnectionState.Connected, $"Connected to 'localhost':{port}");
OnConnected();
var client = new MtClient(port);
Connect(client);
}
private void OnConnected()
@@ -1754,50 +2273,72 @@ namespace MtApi
}
}
private void Disconnect()
private void Disconnect(bool failed)
{
lock (_client)
{
_client.Disconnect();
_client.Close();
}
var state = failed ? MtConnectionState.Failed : MtConnectionState.Disconnected;
var message = failed ? "Connection Failed" : "Disconnected";
UpdateConnectionState(MtConnectionState.Disconnected, "Disconnected");
}
private void UpdateConnectionState(MtConnectionState state, string message)
{
var changed = false;
lock (_locker)
{
if (_connectionState != state)
if (_connectionState == MtConnectionState.Disconnected
|| _connectionState == MtConnectionState.Failed)
return;
if (_client != null)
{
_connectionState = state;
changed = true;
_client.QuoteAdded -= _client_QuoteAdded;
_client.QuoteRemoved -= _client_QuoteRemoved;
_client.QuoteUpdated -= _client_QuoteUpdated;
_client.ServerDisconnected -= _client_ServerDisconnected;
_client.ServerFailed -= _client_ServerFailed;
_client.MtEventReceived -= _client_MtEventReceived;
if (!failed)
{
_client.Disconnect();
}
_client.Dispose();
_client = null;
}
_connectionState = state;
}
if (changed)
{
ConnectionStateChanged.FireEventAsync(this, new MtConnectionEventArgs(state, message));
}
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message));
}
private T SendCommand<T>(MtCommandType commandType, ArrayList commandParameters)
private T SendCommand<T>(MtCommandType commandType, ArrayList commandParameters, Dictionary<string, object> namedParams = null)
{
MtResponse response;
var client = Client;
if (client == null)
{
throw new MtConnectionException("No connection");
}
try
{
lock (_client)
{
response = _client.SendCommand((int)commandType, commandParameters);
}
response = client.SendCommand((int)commandType, commandParameters, namedParams, ExecutorHandle);
}
catch (CommunicationException ex)
{
throw new MtConnectionException(ex.Message, ex);
}
if (response == null)
{
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
}
if (response.ErrorCode != 0)
{
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ToString());
}
var responseValue = response.GetValue();
return responseValue != null ? (T)responseValue : default(T);
}
@@ -1814,25 +2355,14 @@ namespace MtApi
});
var commandParameters = new ArrayList { serializer };
MtResponseString res;
try
{
lock (_client)
{
res = (MtResponseString)_client.SendCommand((int)MtCommandType.MtRequest, commandParameters);
}
}
catch (CommunicationException ex)
{
throw new MtConnectionException(ex.Message, ex);
}
var res = SendCommand<string>(MtCommandType.MtRequest, commandParameters);
if (res == null)
{
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
}
var response = JsonConvert.DeserializeObject<T>(res.Value);
var response = JsonConvert.DeserializeObject<T>(res);
if (response.ErrorCode != 0)
{
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ErrorMessage);
@@ -1845,46 +2375,40 @@ namespace MtApi
{
if (quote != null)
{
if (_isBacktestingMode)
{
QuoteUpdated?.Invoke(this, quote.Instrument, quote.Bid, quote.Ask);
}
else
{
QuoteUpdated.FireEventAsync(this, quote.Instrument, quote.Bid, quote.Ask);
}
QuoteUpdate?.Invoke(this, new MtQuoteEventArgs(new MtQuote(quote)));
QuoteUpdated?.Invoke(this, quote.Instrument, quote.Bid, quote.Ask);
}
}
private void _client_ServerDisconnected(object sender, EventArgs e)
{
UpdateConnectionState(MtConnectionState.Disconnected, "MtApi is disconnected");
Disconnect(false);
}
private void _client_ServerFailed(object sender, EventArgs e)
{
UpdateConnectionState(MtConnectionState.Failed, "Failed connection with MtApi");
Disconnect(true);
}
private void _client_QuoteRemoved(MTApiService.MtQuote quote)
{
QuoteRemoved.FireEventAsync(this, new MtQuoteEventArgs(quote.Convert()));
QuoteRemoved?.Invoke(this, new MtQuoteEventArgs(new MtQuote(quote)));
}
private void _client_QuoteAdded(MTApiService.MtQuote quote)
{
QuoteAdded.FireEventAsync(this, new MtQuoteEventArgs(quote.Convert()));
QuoteAdded?.Invoke(this, new MtQuoteEventArgs(new MtQuote(quote)));
}
private void _client_MtEventReceived(object sender, MtEventArgs e)
private void _client_MtEventReceived(MtEvent e)
{
var eventType = (MtEventTypes) e.Event.EventType;
var eventType = (MtEventTypes) e.EventType;
switch(eventType)
{
case MtEventTypes.LastTimeBar:
{
FireOnLastTimeBar(JsonConvert.DeserializeObject<MtTimeBar>(e.Event.Payload));
FireOnLastTimeBar(JsonConvert.DeserializeObject<MtTimeBar>(e.Payload));
}
break;
default:
@@ -1894,7 +2418,7 @@ namespace MtApi
private void FireOnLastTimeBar(MtTimeBar timeBar)
{
OnLastTimeBar.FireEventAsync(this, new TimeBarArgs(timeBar));
OnLastTimeBar?.Invoke(this, new TimeBarArgs(timeBar));
}
private void BacktestingReady()
@@ -1907,6 +2431,7 @@ namespace MtApi
#region Events
public event MtApiQuoteHandler QuoteUpdated;
public event EventHandler<MtQuoteEventArgs> QuoteUpdate;
public event EventHandler<MtQuoteEventArgs> QuoteAdded;
public event EventHandler<MtQuoteEventArgs> QuoteRemoved;
public event EventHandler<MtConnectionEventArgs> ConnectionStateChanged;
+2 -2
View File
@@ -13,9 +13,9 @@ namespace MtApi
return Color.FromArgb((byte)(color), (byte)(color >> 8), (byte)(color >> 16));
}
public static int ConvertToMtColor(Color color)
public static int ConvertToMtColor(Color? color)
{
return color == Color.Empty ? 0xffffff : (Color.FromArgb(color.B, color.G, color.R).ToArgb() & 0xffffff);
return color == null || color == Color.Empty ? 0xffffff : (Color.FromArgb(color.Value.B, color.Value.G, color.Value.R).ToArgb() & 0xffffff);
}
}
}
+3 -3
View File
@@ -13,13 +13,13 @@ namespace MtApi
return new DateTime(tmpTime.Ticks + (time * 0x989680L));
}
public static int ConvertToMtTime(DateTime time)
public static int ConvertToMtTime(DateTime? time)
{
int result = 0;
if (time != DateTime.MinValue)
if (time != null && time != DateTime.MinValue)
{
DateTime tmpTime = new DateTime(1970, 1, 1);
result = (int)((time.Ticks - tmpTime.Ticks) / 0x989680L);
result = (int)((time.Value.Ticks - tmpTime.Ticks) / 0x989680L);
}
return result;
}
+35 -9
View File
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MtApi
namespace MtApi
{
enum MtCommandType
{
@@ -140,8 +135,8 @@ namespace MtApi
iBullsPower = 106,
iCCI = 107,
iCCIOnArray = 108,
iCustom = 109,
iCustom_d = 10109,
//iCustom = 109,
//iCustom_d = 10109,
iDeMarker = 110,
iEnvelopes = 111,
iEnvelopesOnArray = 112,
@@ -201,6 +196,37 @@ namespace MtApi
SymbolsTotal = 200,
SymbolName = 201,
SymbolSelect = 202,
SymbolInfoInteger = 203
SymbolInfoInteger = 203,
ChartId = 206,
ChartRedraw = 207,
//Object Functions
ObjectCreate = 208,
ObjectName = 209,
ObjectDelete = 210,
ObjectsDeleteAll = 211,
ObjectFind = 212,
ObjectGetTimeByValue = 213,
ObjectGetValueByTime = 214,
ObjectMove = 215,
ObjectsTotal = 216,
ObjectGetDouble = 217,
ObjectGetInteger = 218,
ObjectGetString = 219,
ObjectSetDouble = 220,
ObjectSetInteger = 221,
ObjectSetString = 222,
TextSetFont = 223,
TextOut = 224,
TextGetSize = 225,
ObjectDescription = 226,
ObjectGet = 227,
ObjectGetFiboDescription = 228,
ObjectGetShiftByValue = 229,
ObjectGetValueByShift = 230,
ObjectSet = 231,
ObjectSetFiboDescription = 232,
ObjectSetText = 233,
ObjectType = 234
}
}
+1 -4
View File
@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MtApi
{
public class MtConnectionEventArgs: EventArgs
{
public MtConnectionState Status { get; private set; }
public String ConnectionMessage { get; private set; }
public string ConnectionMessage { get; private set; }
public MtConnectionEventArgs(MtConnectionState status, string message)
{
+9
View File
@@ -5,6 +5,7 @@
public string Instrument { get; private set; }
public double Bid { get; private set; }
public double Ask { get; private set; }
public int ExpertHandle { get; private set; }
public MtQuote(string instrument, double bid, double ask)
{
@@ -12,5 +13,13 @@
Bid = bid;
Ask = ask;
}
internal MtQuote(MTApiService.MtQuote quote)
{
Instrument = quote.Instrument;
Bid = quote.Bid;
Ask = quote.Ask;
ExpertHandle = quote.ExpertHandle;
}
}
}
-3
View File
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MtApi
{
Executable → Regular
+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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.32.0")]
[assembly: AssemblyFileVersion("1.0.32.0")]
[assembly: AssemblyVersion("1.0.33.0")]
[assembly: AssemblyFileVersion("1.0.33.0")]
-4
View File
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MtApi
{
-21
View File
@@ -1,21 +0,0 @@
using System;
namespace MtApi5
{
internal static class ExtensionMethods
{
#region Event Methods
public static void FireEvent(this EventHandler eventHandler, object sender)
{
eventHandler?.Invoke(sender, EventArgs.Empty);
}
public static void FireEvent<T>(this EventHandler<T> eventHandler, object sender, T e)
where T : EventArgs
{
eventHandler?.Invoke(sender, e);
}
#endregion
}
}
+1 -4
View File
@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MtApi5
{
public class Mt5ConnectionEventArgs: EventArgs
{
public Mt5ConnectionState Status { get; private set; }
public String ConnectionMessage { get; private set; }
public string ConnectionMessage { get; private set; }
public Mt5ConnectionEventArgs(Mt5ConnectionState status, string message)
{
-1
View File
@@ -56,7 +56,6 @@
<Compile Include="Mt5Enums.cs" />
<Compile Include="Mt5ConnectionEventArgs.cs" />
<Compile Include="Mt5ConnectionState.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="MqlTradeRequest.cs" />
<Compile Include="MqlTradeResult.cs" />
<Compile Include="Mt5QuoteEventArgs.cs" />
+163 -111
View File
@@ -7,6 +7,7 @@ using System.ServiceModel;
using MtApi5.Requests;
using MtApi5.Responses;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace MtApi5
{
@@ -31,22 +32,17 @@ namespace MtApi5
#region Private Fields
private readonly MtClient _client = new MtClient();
private MtClient _client;
private readonly object _locker = new object();
private volatile bool _isBacktestingMode = false;
private Mt5ConnectionState _connectionState = Mt5ConnectionState.Disconnected;
private int _executorHandle;
#endregion
#region Public Methods
public MtApi5Client()
{
LogConfigurator.Setup(LogProfileName);
ConnectionState = Mt5ConnectionState.Disconnected;
_client.QuoteAdded += mClient_QuoteAdded;
_client.QuoteRemoved += mClient_QuoteRemoved;
_client.QuoteUpdated += mClient_QuoteUpdated;
_client.ServerDisconnected += mClient_ServerDisconnected;
_client.ServerFailed += mClient_ServerFailed;
}
///<summary>
@@ -56,15 +52,7 @@ namespace MtApi5
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(string host, int port)
{
//if (string.IsNullOrEmpty(host) == false && (host.Equals("localhost") || host.Equals("127.0.0.1")))
//{
// this.BeginConnect(port);
//}
//else
//{
Action<string, int> connectAction = Connect;
connectAction.BeginInvoke(host, port, null, null);
//}
Task.Factory.StartNew(() => Connect(host, port));
}
///<summary>
@@ -73,8 +61,7 @@ namespace MtApi5
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(int port)
{
Action<int> connectAction = Connect;
connectAction.BeginInvoke(port, null, null);
Task.Factory.StartNew(() => Connect(port));
}
///<summary>
@@ -82,8 +69,7 @@ namespace MtApi5
///</summary>
public void BeginDisconnect()
{
Action disconnectAction = Disconnect;
disconnectAction.BeginInvoke(null, null);
Task.Factory.StartNew(() => Disconnect(false));
}
///<summary>
@@ -91,11 +77,8 @@ namespace MtApi5
///</summary>
public IEnumerable<Mt5Quote> GetQuotes()
{
IEnumerable<MtQuote> quotes;
lock (_client)
{
quotes = _client.GetQuotes();
}
var client = Client;
var quotes = client != null ? client.GetQuotes() : null;
return quotes?.Select(q => q.Parse());
}
@@ -1432,7 +1415,37 @@ namespace MtApi5
///<summary>
///Connection status of MetaTrader API.
///</summary>
public Mt5ConnectionState ConnectionState { get; private set; }
public Mt5ConnectionState ConnectionState
{
get
{
lock (_locker)
{
return _connectionState;
}
}
}
///<summary>
///Handle of expert used to execute commands
///</summary>
public int ExecutorHandle
{
get
{
lock (_locker)
{
return _executorHandle;
}
}
set
{
lock (_locker)
{
_executorHandle = value;
}
}
}
#endregion
#region Events
@@ -1443,94 +1456,148 @@ namespace MtApi5
#endregion
#region Private Methods
private void Connect(string host, int port)
private MtClient Client
{
ConnectionState = Mt5ConnectionState.Connecting;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, "Connecting to " + host + ":" + port));
try
get
{
lock (_client)
lock (_locker)
{
_client.Open(host, port);
_client.Connect();
return _client;
}
}
catch (Exception e)
}
private void Connect(MtClient client)
{
lock (_locker)
{
ConnectionState = Mt5ConnectionState.Failed;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Failed, "Failed connection to " + host + ":" + port + ". " + e.Message));
return;
if (_connectionState == Mt5ConnectionState.Connected
|| _connectionState == Mt5ConnectionState.Connecting)
{
return;
}
_connectionState = Mt5ConnectionState.Connecting;
}
ConnectionState = Mt5ConnectionState.Connected;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connected, "Connected to " + host + ":" + port));
string message = string.IsNullOrEmpty(client.Host) ? $"Connecting to localhost:{client.Port}" : $"Connecting to {client.Host}:{client.Port}";
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, message));
OnConnected();
var state = Mt5ConnectionState.Failed;
lock (_locker)
{
try
{
client.Connect();
state = Mt5ConnectionState.Connected;
}
catch (Exception e)
{
client.Dispose();
message = string.IsNullOrEmpty(client.Host) ? $"Failed connection to localhost:{client.Port}. {e.Message}" : $"Failed connection to {client.Host}:{client.Port}. {e.Message}";
}
if (state == Mt5ConnectionState.Connected)
{
_client = client;
_client.QuoteAdded += _client_QuoteAdded;
_client.QuoteRemoved += _client_QuoteRemoved;
_client.QuoteUpdated += _client_QuoteUpdated;
_client.ServerDisconnected += _client_ServerDisconnected;
_client.ServerFailed += _client_ServerFailed;
message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}";
}
_connectionState = state;
}
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(state, message));
if (state == Mt5ConnectionState.Connected)
{
OnConnected();
}
}
private void Connect(string host, int port)
{
var client = new MtClient(host, port);
Connect(client);
}
private void Connect(int port)
{
ConnectionState = Mt5ConnectionState.Connecting;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, "Connecting to 'localhost':" + port));
try
{
lock (_client)
{
_client.Open(port);
_client.Connect();
}
}
catch (Exception e)
{
ConnectionState = Mt5ConnectionState.Failed;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Failed, "Failed connection to 'localhost':" + port + ". " + e.Message));
return;
}
ConnectionState = Mt5ConnectionState.Connected;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connected, "Connected to 'localhost':" + port));
OnConnected();
var client = new MtClient(port);
Connect(client);
}
private void Disconnect()
private void Disconnect(bool failed)
{
lock (_client)
var state = failed ? Mt5ConnectionState.Failed : Mt5ConnectionState.Disconnected;
var message = failed ? "Connection Failed" : "Disconnected";
lock (_locker)
{
_client.Disconnect();
_client.Close();
if (_connectionState == Mt5ConnectionState.Disconnected
|| _connectionState == Mt5ConnectionState.Failed)
return;
if (_client != null)
{
_client.QuoteAdded -= _client_QuoteAdded;
_client.QuoteRemoved -= _client_QuoteRemoved;
_client.QuoteUpdated -= _client_QuoteUpdated;
_client.ServerDisconnected -= _client_ServerDisconnected;
_client.ServerFailed -= _client_ServerFailed;
if (!failed)
{
_client.Disconnect();
}
_client.Dispose();
_client = null;
}
_connectionState = state;
}
ConnectionState = Mt5ConnectionState.Disconnected;
ConnectionStateChanged.FireEvent(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Disconnected, "Disconnected"));
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(state, message));
}
private T SendCommand<T>(Mt5CommandType commandType, ArrayList commandParameters)
private T SendCommand<T>(Mt5CommandType commandType, ArrayList commandParameters, Dictionary<string, object> namedParams = null)
{
MtResponse response;
var client = Client;
if (client == null)
{
throw new Exception("No connection");
}
try
{
lock (_client)
{
response = _client.SendCommand((int) commandType, commandParameters);
}
response = client.SendCommand((int)commandType, commandParameters, namedParams, ExecutorHandle);
}
catch (CommunicationException ex)
{
throw new Exception(ex.Message, ex);
}
var responseValue = response?.GetValue();
return responseValue != null ? (T) responseValue : default(T);
if (response == null)
{
throw new ExecutionException(ErrorCode.ErrCustom, "Response from MetaTrader is null");
}
if (response.ErrorCode != 0)
{
throw new ExecutionException((ErrorCode)response.ErrorCode, response.ToString());
}
var responseValue = response.GetValue();
return responseValue != null ? (T)responseValue : default(T);
}
private T SendRequest<T>(RequestBase request) where T : ResponseBase, new()
@@ -1545,25 +1612,14 @@ namespace MtApi5
});
var commandParameters = new ArrayList { serializer };
MtResponseString res;
try
{
lock (_client)
{
res = (MtResponseString)_client.SendCommand((int)Mt5CommandType.MtRequest, commandParameters);
}
}
catch (CommunicationException ex)
{
throw new Exception(ex.Message, ex);
}
var res = SendCommand<string>(Mt5CommandType.MtRequest, commandParameters);
if (res == null)
{
throw new ExecutionException(ErrorCode.ErrCustom, "Response from MetaTrader is null");
}
var response = JsonConvert.DeserializeObject<T>(res.Value);
var response = JsonConvert.DeserializeObject<T>(res);
if (response.ErrorCode != 0)
{
throw new ExecutionException((ErrorCode)response.ErrorCode, response.ErrorMessage);
@@ -1573,7 +1629,7 @@ namespace MtApi5
}
private void mClient_QuoteUpdated(MtQuote quote)
private void _client_QuoteUpdated(MtQuote quote)
{
if (quote != null)
{
@@ -1581,28 +1637,24 @@ namespace MtApi5
}
}
private void mClient_ServerDisconnected(object sender, EventArgs e)
private void _client_ServerDisconnected(object sender, EventArgs e)
{
ConnectionState = Mt5ConnectionState.Disconnected;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Disconnected, "MtApi is disconnected"));
Disconnect(false);
}
private void mClient_ServerFailed(object sender, EventArgs e)
private void _client_ServerFailed(object sender, EventArgs e)
{
ConnectionState = Mt5ConnectionState.Failed;
ConnectionStateChanged.FireEvent(this
, new Mt5ConnectionEventArgs(Mt5ConnectionState.Failed, "Failed connection with MtApi"));
Disconnect(true);
}
private void mClient_QuoteRemoved(MtQuote quote)
private void _client_QuoteRemoved(MtQuote quote)
{
QuoteRemoved.FireEvent(this, new Mt5QuoteEventArgs(quote.Parse()));
QuoteRemoved?.Invoke(this, new Mt5QuoteEventArgs(quote.Parse()));
}
private void mClient_QuoteAdded(MtQuote quote)
private void _client_QuoteAdded(MtQuote quote)
{
QuoteAdded.FireEvent(this, new Mt5QuoteEventArgs(quote.Parse()));
QuoteAdded?.Invoke(this, new Mt5QuoteEventArgs(quote.Parse()));
}
private void OnConnected()
+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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.11.0")]
[assembly: AssemblyFileVersion("1.0.11.0")]
[assembly: AssemblyVersion("1.0.11.1")]
[assembly: AssemblyFileVersion("1.0.11.1")]
File diff suppressed because it is too large Load Diff
+367 -251
View File
@@ -33,8 +33,11 @@ namespace TestApiClientUI
comboBox8.DataSource = Enum.GetNames(typeof(MarketInfoModeType));
comboBox9.DataSource = Enum.GetNames(typeof(EnumTerminalInfoInteger));
comboBox10.DataSource = Enum.GetNames(typeof(EnumTerminalInfoDouble));
comboBox11.DataSource = Enum.GetNames(typeof(EnumObject));
comboBoxAccountInfoCmd.DataSource = Enum.GetNames(typeof(TradeOperation));
_apiClient.QuoteUpdated += apiClient_QuoteUpdated;
_apiClient.QuoteUpdate += _apiClient_QuoteUpdate;
_apiClient.QuoteAdded += apiClient_QuoteAdded;
_apiClient.QuoteRemoved += apiClient_QuoteRemoved;
_apiClient.ConnectionStateChanged += apiClient_ConnectionStateChanged;
@@ -47,6 +50,8 @@ namespace TestApiClientUI
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
comboBox5.SelectedIndex = 0;
comboBox11.SelectedIndex = 0;
comboBoxAccountInfoCmd.SelectedIndex = 0;
_timerTradeMonitor = new TimerTradeMonitor(_apiClient) { Interval = 10000 }; // 10 sec
_timerTradeMonitor.AvailabilityOrdersChanged += _tradeMonitor_AvailabilityOrdersChanged;
@@ -112,12 +117,18 @@ namespace TestApiClientUI
private void apiClient_QuoteRemoved(object sender, MtQuoteEventArgs e)
{
RunOnUiThread(() => RemoveQuote(e.Quote) );
if (e.Quote != null)
{
RunOnUiThread(() => RemoveQuote(e.Quote));
}
}
private void apiClient_QuoteAdded(object sender, MtQuoteEventArgs e)
{
RunOnUiThread(() => AddNewQuote(e.Quote));
if (e.Quote != null)
{
RunOnUiThread(() => AddNewQuote(e.Quote));
}
}
private void _apiClient_OnLastTimeBar(object sender, TimeBarArgs e)
@@ -130,73 +141,53 @@ namespace TestApiClientUI
private void apiClient_QuoteUpdated(object sender, string symbol, double bid, double ask)
{
Console.WriteLine(@"Quote: Symbol = {0}, Bid = {1}, Ask = {2}", symbol, bid, ask);
Console.WriteLine(@"Quote: Symbol = {0}, Bid = {1}, Ask = {2}", symbol, bid, ask);
}
private void _apiClient_QuoteUpdate(object sender, MtQuoteEventArgs e)
{
//if UI of quite is busy we are skipping this update
if (_isUiQuoteUpdateReady)
{
RunOnUiThread(() => ChangeQuote(symbol, bid, ask));
RunOnUiThread(() => ChangeQuote(e.Quote));
}
}
private void AddNewQuote(MtQuote quote)
{
if (quote == null)
return;
var key = quote.ExpertHandle.ToString();
if (string.IsNullOrEmpty(quote.Instrument) == false
&& listViewQuotes.Items.ContainsKey(quote.Instrument) == false)
if (listViewQuotes.Items.ContainsKey(key) == false)
{
var item = new ListViewItem(quote.Instrument) { Name = quote.Instrument };
var item = new ListViewItem(quote.Instrument) { Name = key };
item.SubItems.Add(quote.Bid.ToString(CultureInfo.CurrentCulture));
item.SubItems.Add(quote.Ask.ToString(CultureInfo.CurrentCulture));
item.SubItems.Add("1");
item.SubItems.Add(key);
listViewQuotes.Items.Add(item);
}
else
{
var item = listViewQuotes.Items[quote.Instrument];
int feedCount;
int.TryParse(item.SubItems[3].Text, out feedCount);
feedCount++;
item.SubItems[3].Text = feedCount.ToString();
}
}
private void RemoveQuote(MtQuote quote)
{
if (quote == null)
return;
var key = quote.ExpertHandle.ToString();
if (string.IsNullOrEmpty(quote.Instrument) == false
&& listViewQuotes.Items.ContainsKey(quote.Instrument))
if (listViewQuotes.Items.ContainsKey(key))
{
var item = listViewQuotes.Items[quote.Instrument];
int feedCount;
int.TryParse(item.SubItems[3].Text, out feedCount);
feedCount--;
if (feedCount <= 0)
{
listViewQuotes.Items.RemoveByKey(quote.Instrument);
}
else
{
item.SubItems[3].Text = feedCount.ToString();
}
listViewQuotes.Items.RemoveByKey(key);
}
}
private void ChangeQuote(string symbol, double bid, double ask)
private void ChangeQuote(MtQuote quote)
{
_isUiQuoteUpdateReady = false;
if (string.IsNullOrEmpty(symbol) == false)
var key = quote.ExpertHandle.ToString();
if (listViewQuotes.Items.ContainsKey(key))
{
if (listViewQuotes.Items.ContainsKey(symbol))
{
var item = listViewQuotes.Items[symbol];
item.SubItems[1].Text = bid.ToString(CultureInfo.CurrentCulture);
item.SubItems[2].Text = ask.ToString(CultureInfo.CurrentCulture);
}
var item = listViewQuotes.Items[key];
item.SubItems[1].Text = quote.Bid.ToString(CultureInfo.CurrentCulture);
item.SubItems[2].Text = quote.Ask.ToString(CultureInfo.CurrentCulture);
}
_isUiQuoteUpdateReady = true;
@@ -256,6 +247,12 @@ namespace TestApiClientUI
textBoxOrderSymbol.Text = listViewQuotes.SelectedItems[0].Text;
txtMarketInfoSymbol.Text = listViewQuotes.SelectedItems[0].Text;
textBoxSelectedSymbol.Text = listViewQuotes.SelectedItems[0].Text;
textBoxAccountInfoSymbol.Text = listViewQuotes.SelectedItems[0].Text;
if (checkBox2.Checked)
{
_apiClient.ExecutorHandle = int.Parse(listViewQuotes.SelectedItems[0].SubItems[3].Text);
}
}
}
@@ -526,206 +523,6 @@ namespace TestApiClientUI
});
}
private void button3_Click(object sender, EventArgs e)
{
switch (comboBoxStatusCommand.SelectedIndex)
{
case 0:
{
var result = _apiClient.GetLastError();
PrintLog($"GetLastError result: {result}");
}
break;
case 1:
{
var result = _apiClient.IsConnected();
PrintLog($"IsConnected result: {result}");
}
break;
case 2:
{
var result = _apiClient.IsDemo();
PrintLog($"IsDemo result: {result}");
}
break;
case 3:
{
var result = _apiClient.IsDllsAllowed();
PrintLog($"IsDllsAllowed result: {result}");
}
break;
case 4:
{
var result = _apiClient.IsExpertEnabled();
PrintLog($"IsExpertEnabled result: {result}");
}
break;
case 5:
{
var result = _apiClient.IsLibrariesAllowed();
PrintLog($"IsLibrariesAllowed result: {result}");
}
break;
case 6:
{
var result = _apiClient.IsOptimization();
PrintLog($"IsOptimization result: {result}");
}
break;
case 7:
{
var result = _apiClient.IsStopped();
PrintLog($"IsStopped result: {result}");
}
break;
case 8:
{
var result = _apiClient.IsTesting();
PrintLog($"IsTesting result: {result}");
}
break;
case 9:
{
var result = _apiClient.IsTradeAllowed();
PrintLog($"IsTradeAllowed result: {result}");
}
break;
case 10:
{
var result = _apiClient.IsTradeContextBusy();
PrintLog($"IsTradeContextBusy result: {result}");
}
break;
case 11:
{
var result = _apiClient.IsVisualMode();
PrintLog($"IsVisualMode result: {result}");
}
break;
case 12:
{
var result = _apiClient.UninitializeReason();
PrintLog($"UninitializeReason result: {result}");
}
break;
case 13:
{
int errorCode;
int.TryParse(textBoxErrorCode.Text, out errorCode);
var result = _apiClient.ErrorDescription(errorCode);
PrintLog($"ErrorDescription result: {result}");
}
break;
default:
return;
}
}
private void button4_Click(object sender, EventArgs e)
{
switch (listBoxAccountInfo.SelectedIndex)
{
case 0:
{
var result = _apiClient.AccountBalance();
PrintLog($"AccountBalance result: {result}");
}
break;
case 1:
{
var result = _apiClient.AccountCredit();
PrintLog($"AccountCredit result: {result}");
}
break;
case 2:
{
var result = _apiClient.AccountCompany();
PrintLog($"AccountCompany result: {result}");
}
break;
case 3:
{
var result = _apiClient.AccountCurrency();
PrintLog($"AccountCurrency result: {result}");
}
break;
case 4:
{
var result = _apiClient.AccountEquity();
PrintLog($"AccountEquity result: {result}");
}
break;
case 5:
{
var result = _apiClient.AccountFreeMargin();
PrintLog($"AccountFreeMargin result: {result}");
}
break;
case 6:
{
var result = _apiClient.AccountFreeMarginCheck(textBoxAccountInfoSymbol.Text, (TradeOperation)comboBoxAccountInfoCmd.SelectedIndex, int.Parse(textBoxAccountInfoVolume.Text));
PrintLog($"AccountFreeMarginCheck result: {result}");
}
break;
case 7:
{
var result = _apiClient.AccountFreeMarginMode();
PrintLog($"AccountFreeMarginMode result: {result}");
}
break;
case 8:
{
var result = _apiClient.AccountLeverage();
PrintLog($"AccountLeverage result: {result}");
}
break;
case 9:
{
var result = _apiClient.AccountMargin();
PrintLog($"AccountMargin result: {result}");
}
break;
case 10:
{
var result = _apiClient.AccountName();
PrintLog($"AccountName result: {result}");
}
break;
case 11:
{
var result = _apiClient.AccountNumber();
PrintLog($"AccountNumber result: {result}");
}
break;
case 12:
{
var result = _apiClient.AccountProfit();
PrintLog($"AccountProfit result: {result}");
}
break;
case 13:
{
var result = _apiClient.AccountServer();
PrintLog($"AccountServer result: {result}");
}
break;
case 14:
{
var result = _apiClient.AccountStopoutLevel();
PrintLog($"AccountStopoutLevel result: {result}");
}
break;
case 15:
{
var result = _apiClient.AccountStopoutMode();
PrintLog($"AccountStopoutMode result: {result}");
}
break;
default:
return;
}
}
//MarketInfo
private async void button5_Click(object sender, EventArgs e)
{
@@ -753,13 +550,13 @@ namespace TestApiClientUI
Console.WriteLine($"Finished time: {DateTime.Now}");
using (var file = new System.IO.StreamWriter($@"{System.IO.Path.GetTempPath()}\MtApi\test.txt"))
{
foreach (var value in openPriceList)
{
file.WriteLine(value);
}
}
//using (var file = new System.IO.StreamWriter($@"{System.IO.Path.GetTempPath()}\MtApi\test.txt"))
//{
// foreach (var value in openPriceList)
// {
// file.WriteLine(value);
// }
//}
}
private void button7_Click(object sender, EventArgs e)
@@ -832,9 +629,9 @@ namespace TestApiClientUI
listBoxEventLog.Items.Clear();
}
private async Task<TResult> Execute<TResult>(Func<TResult> func)
private Task<TResult> Execute<TResult>(Func<TResult> func)
{
return await Task.Factory.StartNew(() =>
return Task.Factory.StartNew(() =>
{
var result = default(TResult);
try
@@ -854,6 +651,25 @@ namespace TestApiClientUI
});
}
private Task Execute(Action action)
{
return Task.Factory.StartNew(() =>
{
try
{
action();
}
catch (MtConnectionException ex)
{
PrintLog("MtExecutionException: " + ex.Message);
}
catch (MtExecutionException ex)
{
PrintLog("MtExecutionException: " + ex.Message + "; ErrorCode = " + ex.ErrorCode);
}
});
}
//OrderSend
private async void button1_Click(object sender, EventArgs e)
{
@@ -1286,5 +1102,305 @@ namespace TestApiClientUI
var result = await Execute(() => _apiClient.TerminalInfoDouble(propId));
PrintLog($"TerminalInfoDouble: result = {result}");
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
var checkbox = sender as CheckBox;
if (checkbox == null)
return;
int expertHandle = 0;
if (checkbox.Checked)
{
if (listViewQuotes.SelectedItems.Count > 0)
{
expertHandle = int.Parse(listViewQuotes.SelectedItems[0].SubItems[3].Text);
}
}
_apiClient.ExecutorHandle = expertHandle;
}
//GetLastError
private async void button40_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.GetLastError);
PrintLog($"GetLastError: result = {result}");
RunOnUiThread(() => { textBoxErrorCode.Text = result.ToString(); });
}
//ErrorDescription
private async void button39_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxErrorCode.Text))
{
MessageBox.Show(@"Error code is not defined!");
textBoxErrorCode.Focus();
return;
}
int errorCode;
if (int.TryParse(textBoxErrorCode.Text, out errorCode) == false)
{
MessageBox.Show(@"Failed to parse error code!");
textBoxErrorCode.Focus();
return;
}
var result = await Execute(() => _apiClient.ErrorDescription(errorCode));
PrintLog($"ErrorDescription: code = {errorCode}, description = {result}");
}
//IsConnected
private async void button41_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsConnected);
PrintLog($"IsConnected: result = {result}");
}
//IsDemo
private async void button42_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsDemo);
PrintLog($"IsDemo: result = {result}");
}
//IsDllsAllowed
private async void button43_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsDllsAllowed);
PrintLog($"IsDllsAllowed: result = {result}");
}
//IsExpertEnabled
private async void button44_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsExpertEnabled);
PrintLog($"IsExpertEnabled: result = {result}");
}
//IsLibrariesAllowed
private async void button45_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsLibrariesAllowed);
PrintLog($"IsLibrariesAllowed: result = {result}");
}
//IsOptimization
private async void button46_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsOptimization);
PrintLog($"IsOptimization: result = {result}");
}
//IsStopped
private async void button47_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsStopped);
PrintLog($"IsStopped: result = {result}");
}
//IsTesting
private async void button48_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsTesting);
PrintLog($"IsTesting: result = {result}");
}
//IsTradeAllowed
private async void button49_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsTradeAllowed);
PrintLog($"IsTradeAllowed: result = {result}");
}
//IsTradeContextBusy
private async void button50_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsTradeContextBusy);
PrintLog($"IsTradeContextBusy: result = {result}");
}
//IsVisualMode
private async void button51_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.IsVisualMode);
PrintLog($"IsVisualMode: result = {result}");
}
//UninitializeReason
private async void button52_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.UninitializeReason);
PrintLog($"UninitializeReason: result = {result}");
}
//AccountBalance
private async void button3_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountBalance);
PrintLog($"AccountBalance result: {result}");
}
//AccountCredit
private async void button53_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountCredit);
PrintLog($"AccountCredit result: {result}");
}
//AccountCompany
private async void button54_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountCompany);
PrintLog($"AccountCompany result: {result}");
}
//AccountCurrency
private async void button55_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountCurrency);
PrintLog($"AccountCurrency result: {result}");
}
//AccountEquity
private async void button56_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountEquity);
PrintLog($"AccountEquity result: {result}");
}
//AccountFreeMargin
private async void button57_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountFreeMargin);
PrintLog($"AccountFreeMargin result: {result}");
}
//AccountFreeMarginCheck
private async void button58_Click(object sender, EventArgs e)
{
var symbol = textBoxAccountInfoSymbol.Text;
if (string.IsNullOrEmpty(symbol))
{
MessageBox.Show(@"Symbol is not defined!");
textBoxAccountInfoSymbol.Focus();
return;
}
double volume;
if (double.TryParse(textBoxAccountInfoVolume.Text, out volume) == false)
{
MessageBox.Show(@"Failed to parse volume value!");
textBoxAccountInfoVolume.Focus();
return;
}
TradeOperation cmd;
Enum.TryParse(comboBoxAccountInfoCmd.Text, out cmd);
var result = await Execute(() => _apiClient.AccountFreeMarginCheck(symbol, cmd, volume));
PrintLog($"AccountFreeMarginCheck result: {result}");
}
//AccountFreeMarginMode
private async void button59_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountFreeMarginMode);
PrintLog($"AccountFreeMarginMode result: {result}");
}
//AccountLeverage
private async void button60_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountLeverage);
PrintLog($"AccountLeverage result: {result}");
}
//AccountMargin
private async void button61_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountMargin);
PrintLog($"AccountMargin result: {result}");
}
//AccountName
private async void button62_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountName);
PrintLog($"AccountName result: {result}");
}
//AccountNumber
private async void button63_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountNumber);
PrintLog($"AccountNumber result: {result}");
}
//AccountProfit
private async void button64_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountProfit);
PrintLog($"AccountProfit result: {result}");
}
//AccountServer
private async void button65_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountServer);
PrintLog($"AccountServer result: {result}");
}
//AccountStopoutLevel
private async void button66_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountStopoutLevel);
PrintLog($"AccountStopoutLevel result: {result}");
}
//AccountStopoutMode
private async void button67_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.AccountStopoutMode);
PrintLog($"AccountStopoutMode result: {result}");
}
//CharID
private async void button37_Click(object sender, EventArgs e)
{
var result = await Execute(_apiClient.ChartId);
PrintLog($"CharID: result = {result}");
RunOnUiThread(() => textBoxChartId.Text = result.ToString());
}
//ChartRedraw
private async void button38_Click(object sender, EventArgs e)
{
await Execute(() => _apiClient.ChartRedraw());
PrintLog($"ChartRedraw: called.");
}
//ObjectCreate
private async void button4_Click(object sender, EventArgs e)
{
const long chartId = 0;
const string objectName = "label_object";
EnumObject objectType;
Enum.TryParse(comboBox11.Text, out objectType);
var result = await Execute(() => _apiClient.ObjectCreate(chartId, objectName, objectType, 0, null, 0));
PrintLog($"ObjectCreate result: {result}");
}
//ObjectName
private async void button68_Click(object sender, EventArgs e)
{
const long chartId = 0;
const int objectIndex = 0;
var result = await Execute(() => _apiClient.ObjectName(chartId, objectIndex));
PrintLog($"ObjectName result: {result}");
}
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>
</configuration>
@@ -1,7 +1,7 @@
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by a tool.
' Runtime Version:4.0.30319.17929
' Runtime Version:4.0.30319.42000
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
@@ -1,7 +1,7 @@
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by a tool.
' Runtime Version:4.0.30319.17929
' Runtime Version:4.0.30319.42000
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
@@ -11,6 +11,7 @@
Option Strict On
Option Explicit On
Imports System
Namespace My.Resources
@@ -21,20 +22,20 @@ Namespace My.Resources
'''<summary>
''' A strongly-typed resource class, for looking up localized strings, etc.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Friend Module Resources
Private resourceMan As Global.System.Resources.ResourceManager
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Returns the cached ResourceManager instance used by this class.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
@@ -44,17 +45,17 @@ Namespace My.Resources
Return resourceMan
End Get
End Property
'''<summary>
''' Overrides the current thread's CurrentUICulture property for all
''' resource lookups using this strongly typed resource class.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set(ByVal value As Global.System.Globalization.CultureInfo)
Set
resourceCulture = value
End Set
End Property
@@ -1,7 +1,7 @@
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by a tool.
' Runtime Version:4.0.30319.17929
' Runtime Version:4.0.30319.42000
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
@@ -13,42 +13,42 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
#Region "My.Settings Auto-Save Functionality"
#If _MyType = "WindowsForms" Then
Private Shared addedHandler As Boolean
Private Shared addedHandler As Boolean
Private Shared addedHandlerLockObject As New Object
Private Shared addedHandlerLockObject As New Object
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
If My.Application.SaveMySettingsOnExit Then
My.Settings.Save()
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
If My.Application.SaveMySettingsOnExit Then
My.Settings.Save()
End If
End Sub
#End If
#End Region
Public Shared ReadOnly Property [Default]() As MySettings
Get
#If _MyType = "WindowsForms" Then
If Not addedHandler Then
SyncLock addedHandlerLockObject
If Not addedHandler Then
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
addedHandler = True
End If
End SyncLock
End If
If Not addedHandler Then
SyncLock addedHandlerLockObject
If Not addedHandler Then
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
addedHandler = True
End If
End SyncLock
End If
#End If
Return defaultInstance
End Get
@@ -13,8 +13,9 @@
<AssemblyName>TestMtApi</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>WindowsForms</MyType>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -40,6 +41,7 @@
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>TestMtApi.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
@@ -50,6 +52,7 @@
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>TestMtApi.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
@@ -67,7 +70,6 @@
<ApplicationManifest>My Project\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="MtApi, Version=1.0.7.0, Culture=neutral, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
@@ -126,6 +128,7 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="My Project\app.manifest" />
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
@@ -159,6 +162,12 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\MtApi\MtApi.csproj">
<Project>{7a76c388-a8fb-4949-8170-24d4742e934e}</Project>
<Name>MtApi</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.