diff --git a/MTApiService/MTApiService.csproj b/MTApiService/MTApiService.csproj
index 44777da8..ed103b9b 100755
--- a/MTApiService/MTApiService.csproj
+++ b/MTApiService/MTApiService.csproj
@@ -60,6 +60,7 @@
+
diff --git a/MTApiService/MtClient.cs b/MTApiService/MtClient.cs
index b7cb090a..57bee4b4 100755
--- a/MTApiService/MtClient.cs
+++ b/MTApiService/MtClient.cs
@@ -224,20 +224,14 @@ namespace MTApiService
{
Debug.WriteLine("[INFO] MtClient::OnQuoteAdded");
- if (QuoteAdded != null)
- {
- QuoteAdded(quote);
- }
+ QuoteAdded?.Invoke(quote);
}
public void OnQuoteRemoved(MtQuote quote)
{
Debug.WriteLine("[INFO] MtClient::OnQuoteRemoved");
- if (QuoteRemoved != null)
- {
- QuoteRemoved(quote);
- }
+ QuoteRemoved?.Invoke(quote);
}
public void OnServerStopped()
@@ -246,10 +240,13 @@ namespace MTApiService
Close();
- if (ServerDisconnected != null)
- {
- ServerDisconnected(this, EventArgs.Empty);
- }
+ ServerDisconnected?.Invoke(this, EventArgs.Empty);
+ }
+
+
+ public void OnMtEvent(MtEvent mtEvent)
+ {
+ MtEventReceived?.Invoke(this, new MtEventArgs(mtEvent));
}
#endregion
@@ -301,6 +298,7 @@ namespace MTApiService
public event MtQuoteHandler QuoteUpdated;
public event EventHandler ServerDisconnected;
public event EventHandler ServerFailed;
+ public event EventHandler MtEventReceived;
#endregion
#region Fields
diff --git a/MTApiService/MtEvent.cs b/MTApiService/MtEvent.cs
new file mode 100644
index 00000000..80b38b38
--- /dev/null
+++ b/MTApiService/MtEvent.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace MTApiService
+{
+ [DataContract]
+ public class MtEvent
+ {
+ [DataMember]
+ public int EventType { get; private set; }
+
+ [DataMember]
+ public string Payload { get; private set; }
+
+ public MtEvent(int eventType, string payload)
+ {
+ EventType = eventType;
+ Payload = payload;
+ }
+
+ public override string ToString()
+ {
+ return "MtEvent = " + EventType + ", Payload = " + Payload;
+ }
+ }
+
+ public class MtEventArgs: EventArgs
+ {
+ public MtEventArgs(MtEvent e)
+ {
+ Event = e;
+ }
+
+ public MtEvent Event { get; private set; }
+ }
+}
diff --git a/MTApiService/MtExpert.cs b/MTApiService/MtExpert.cs
index 7ea328d8..2d98eefc 100755
--- a/MTApiService/MtExpert.cs
+++ b/MTApiService/MtExpert.cs
@@ -66,6 +66,7 @@ namespace MTApiService
}
}
}
+
#endregion
#region Public Methods
@@ -114,6 +115,11 @@ namespace MTApiService
return null;
}
+
+ public void SendEvent(MtEvent mtEvent)
+ {
+ FireOnMtEvent(mtEvent);
+ }
#endregion
#region IMtCommandExecutor
@@ -134,29 +140,22 @@ namespace MTApiService
private void FireOnQuoteChanged(MtQuote quote)
{
- var handler = QuoteChanged;
- if (handler != null)
- {
- handler(this, quote);
- }
+ QuoteChanged?.Invoke(this, quote);
}
private void FireOnDeinited()
{
- var handler = Deinited;
- if (handler != null)
- {
- handler(this, EventArgs.Empty);
- }
+ Deinited?.Invoke(this, EventArgs.Empty);
}
private void FireOnCommandExecuted()
{
- var handler = CommandExecuted;
- if (handler != null)
- {
- handler(this, EventArgs.Empty);
- }
+ CommandExecuted?.Invoke(this, EventArgs.Empty);
+ }
+
+ private void FireOnMtEvent(MtEvent mtEvent)
+ {
+ OnMtEvent?.Invoke(this, new MtEventArgs(mtEvent));
}
#endregion
@@ -164,6 +163,7 @@ namespace MTApiService
public event EventHandler Deinited;
public event MtQuoteHandler QuoteChanged;
public event EventHandler CommandExecuted;
+ public event EventHandler OnMtEvent;
#endregion
#region Private Fields
diff --git a/MTApiService/MtServer.cs b/MTApiService/MtServer.cs
index 6bef6ea9..15283c99 100755
--- a/MTApiService/MtServer.cs
+++ b/MTApiService/MtServer.cs
@@ -107,6 +107,7 @@ namespace MTApiService
{
expert.Deinited += expert_Deinited;
expert.QuoteChanged += expert_QuoteChanged;
+ expert.OnMtEvent += Expert_OnMtEvent;
lock (_experts)
{
@@ -308,13 +309,14 @@ namespace MTApiService
_service.QuoteUpdate(quote);
}
+ private void Expert_OnMtEvent(object sender, MtEventArgs e)
+ {
+ _service.OnMtEvent(e.Event);
+ }
+
private void FireOnStopped()
{
- var handler = Stopped;
- if (handler != null)
- {
- handler(this, EventArgs.Empty);
- }
+ Stopped?.Invoke(this, EventArgs.Empty);
}
#endregion
diff --git a/MTApiService/MtServerInstance.cs b/MTApiService/MtServerInstance.cs
index 2eb06b38..b30f50fd 100755
--- a/MTApiService/MtServerInstance.cs
+++ b/MTApiService/MtServerInstance.cs
@@ -101,6 +101,24 @@ namespace MTApiService
Debug.WriteLine("MtApiServerInstance::SendQuote: finish.");
}
+ public void SendEvent(int expertHandle, int eventType, string payload)
+ {
+ Debug.WriteLine("MtApiServerInstance::SendEvent called. eventType = {0}, payload = {1}", eventType, payload);
+
+ MtExpert expert = null;
+ lock (mExpertsDictionary)
+ {
+ expert = mExpertsDictionary[expertHandle];
+ }
+
+ if (expert != null)
+ {
+ expert.SendEvent(new MtEvent(eventType, payload));
+ }
+
+ Debug.WriteLine("MtApiServerInstance::SendEvent: finished");
+ }
+
public void SendResponse(int expertHandle, MtResponse response)
{
Debug.WriteLine("MtApiServerInstance::SendResponse: id = {0}, response = {1}", expertHandle, response);
diff --git a/MTApiService/MtService.cs b/MTApiService/MtService.cs
index 56dfa4d4..5b5b9ee5 100755
--- a/MTApiService/MtService.cs
+++ b/MTApiService/MtService.cs
@@ -35,6 +35,9 @@ namespace MTApiService
[OperationContract(IsOneWay = true)]
void OnQuoteRemoved(MtQuote quote);
+
+ [OperationContract(IsOneWay = true)]
+ void OnMtEvent(MtEvent ntEvent);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
@@ -123,171 +126,74 @@ namespace MTApiService
#region Public Methods
public void OnStopServer()
{
- try
- {
- mClientsLocker.AcquireReaderLock(2000);
-
- try
- {
- foreach (var callback in mClientCallbacks)
- {
- try
- {
- callback.OnServerStopped();
- }
- catch (Exception)
- {
- }
- }
- }
- finally
- {
- mClientsLocker.ReleaseReaderLock();
- }
- }
- catch (ApplicationException)
- {
- }
+ ExecuteCallbackAction(a => a.OnServerStopped());
}
public void QuoteUpdate(MtQuote quote)
{
- try
- {
- mClientsLocker.AcquireReaderLock(200);
-
- List crashedClientsCallback = null;
-
- try
- {
- foreach (var callback in mClientCallbacks)
- {
- try
- {
- callback.OnQuoteUpdate(quote);
- }
- catch (Exception)
- {
- if (crashedClientsCallback == null)
- crashedClientsCallback = new List();
-
- crashedClientsCallback.Add(callback);
- }
- }
- }
- finally
- {
- mClientsLocker.ReleaseReaderLock();
- }
-
- removeCrashedClientCallbacks(crashedClientsCallback);
- }
- catch (ApplicationException)
- {
- }
+ ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
}
public void OnQuoteAdded(MtQuote quote)
{
- try
- {
- mClientsLocker.AcquireReaderLock(2000);
-
- List crashedClientsCallback = null;
-
- try
- {
- foreach (var callback in mClientCallbacks)
- {
- try
- {
- callback.OnQuoteAdded(quote);
- }
- catch (Exception)
- {
- if (crashedClientsCallback == null)
- crashedClientsCallback = new List();
-
- crashedClientsCallback.Add(callback);
- }
- }
- }
- finally
- {
- mClientsLocker.ReleaseReaderLock();
- }
-
- removeCrashedClientCallbacks(crashedClientsCallback);
- }
- catch (ApplicationException)
- {
- }
+ ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
}
public void OnQuoteRemoved(MtQuote quote)
{
- try
- {
- mClientsLocker.AcquireReaderLock(2000);
+ ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
+ }
- List crashedClientsCallback = null;
-
- try
- {
- foreach (var callback in mClientCallbacks)
- {
- try
- {
- callback.OnQuoteRemoved(quote);
- }
- catch (Exception)
- {
- if (crashedClientsCallback == null)
- crashedClientsCallback = new List();
-
- crashedClientsCallback.Add(callback);
- }
- }
- }
- finally
- {
- mClientsLocker.ReleaseReaderLock();
- }
-
- removeCrashedClientCallbacks(crashedClientsCallback);
- }
- catch (ApplicationException)
- {
- }
+ public void OnMtEvent(MtEvent mtEvent)
+ {
+ ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
}
#endregion
#region Private Methods
- private void removeCrashedClientCallbacks(List crashedClientCallbacks)
+ private void ExecuteCallbackAction(Action action)
{
- if (crashedClientCallbacks != null)
+ try
{
+ mClientsLocker.AcquireReaderLock(2000);
+
+ List crashedClientCallbacks = null;
+
try
{
- mClientsLocker.AcquireWriterLock(200);
+ foreach (var callback in mClientCallbacks)
+ {
+ try
+ {
+ action(callback);
+ }
+ catch (Exception)
+ {
+ if (crashedClientCallbacks == null)
+ crashedClientCallbacks = new List();
- try
+ crashedClientCallbacks.Add(callback);
+ }
+ }
+
+ if (crashedClientCallbacks != null)
{
foreach (var crashedCallback in crashedClientCallbacks)
{
mClientCallbacks.Remove(crashedCallback);
}
}
- finally
- {
- mClientsLocker.ReleaseWriterLock();
- }
}
- catch (ApplicationException)
+ finally
{
+ mClientsLocker.ReleaseReaderLock();
}
}
+ catch (ApplicationException)
+ {
+ //TODO: add logging
+ }
}
#endregion
diff --git a/MTConnector/MTConnector.cpp b/MTConnector/MTConnector.cpp
index 83e799ef..0e0805b7 100755
--- a/MTConnector/MTConnector.cpp
+++ b/MTConnector/MTConnector.cpp
@@ -71,6 +71,22 @@ int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double a
return 1;
}
+
+int _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;
+}
+
int _stdcall sendIntResponse(int expertHandle, int response)
{
try
diff --git a/MTConnector/MTConnector.def b/MTConnector/MTConnector.def
index c3078fdd..4957da7b 100755
--- a/MTConnector/MTConnector.def
+++ b/MTConnector/MTConnector.def
@@ -3,6 +3,7 @@ LIBRARY MTConnector
EXPORTS initExpert
deinitExpert
updateQuote
+ sendEvent
sendIntResponse
sendBooleanResponse
sendDoubleResponse
diff --git a/MtApi/ExtensionMethods.cs b/MtApi/ExtensionMethods.cs
index 64f33ad1..fa33115c 100755
--- a/MtApi/ExtensionMethods.cs
+++ b/MtApi/ExtensionMethods.cs
@@ -1,14 +1,8 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MtApi
+namespace MtApi
{
static class ExtensionMethods
{
- public static MtQuote Parse(this MTApiService.MtQuote quote)
+ public static MtQuote Convert(this MTApiService.MtQuote quote)
{
return (quote != null) ? new MtQuote(quote.Instrument, quote.Bid, quote.Ask) : null;
}
diff --git a/MtApi/MtApi.csproj b/MtApi/MtApi.csproj
index 0cc71a28..0d0ef21b 100755
--- a/MtApi/MtApi.csproj
+++ b/MtApi/MtApi.csproj
@@ -66,10 +66,12 @@
+
+
@@ -95,6 +97,7 @@
+
diff --git a/MtApi/MtApiClient.cs b/MtApi/MtApiClient.cs
index 47be5034..04b06838 100755
--- a/MtApi/MtApiClient.cs
+++ b/MtApi/MtApiClient.cs
@@ -29,11 +29,12 @@ namespace MtApi
public MtApiClient()
{
- _client.QuoteAdded +=new MtClient.MtQuoteHandler(mClient_QuoteAdded);
- _client.QuoteRemoved += new MtClient.MtQuoteHandler(mClient_QuoteRemoved);
- _client.QuoteUpdated += new MtClient.MtQuoteHandler(mClient_QuoteUpdated);
- _client.ServerDisconnected += new EventHandler(mClient_ServerDisconnected);
- _client.ServerFailed += new EventHandler(mClient_ServerFailed);
+ _client.QuoteAdded += mClient_QuoteAdded;
+ _client.QuoteRemoved += mClient_QuoteRemoved;
+ _client.QuoteUpdated += mClient_QuoteUpdated;
+ _client.ServerDisconnected += mClient_ServerDisconnected;
+ _client.ServerFailed += mClient_ServerFailed;
+ _client.MtEventReceived += _client_MtEventReceived;
}
#endregion
@@ -81,7 +82,7 @@ namespace MtApi
public IEnumerable GetQuotes()
{
var quotes = _client.GetQuotes();
- return quotes != null ? (from q in quotes select q.Parse()) : null;
+ return quotes != null ? (from q in quotes select q.Convert()) : null;
}
#endregion
@@ -1597,14 +1598,35 @@ namespace MtApi
private void mClient_QuoteRemoved(MTApiService.MtQuote quote)
{
var handler = QuoteRemoved;
- handler?.BeginInvoke(this, new MtQuoteEventArgs(quote.Parse()), (a) => handler.EndInvoke(a), null);
+ handler?.BeginInvoke(this, new MtQuoteEventArgs(quote.Convert()), (a) => handler.EndInvoke(a), null);
}
private void mClient_QuoteAdded(MTApiService.MtQuote quote)
{
var handler = QuoteAdded;
- handler?.BeginInvoke(this, new MtQuoteEventArgs(quote.Parse()), (a) => handler.EndInvoke(a), null);
+ handler?.BeginInvoke(this, new MtQuoteEventArgs(quote.Convert()), (a) => handler.EndInvoke(a), null);
}
+
+ private void _client_MtEventReceived(object sender, MtEventArgs e)
+ {
+ MtEventTypes eventType = (MtEventTypes) e.Event.EventType;
+
+ switch(eventType)
+ {
+ case MtEventTypes.LastTimeBar:
+ {
+ FireOnLastTimeBar(JsonConvert.DeserializeObject(e.Event.Payload));
+ }
+ break;
+ }
+ }
+
+ private void FireOnLastTimeBar(MtTimeBar timeBar)
+ {
+ var handler = OnLastTimeBar;
+ handler?.BeginInvoke(this, new TimeBarArgs(timeBar), (a) => handler.EndInvoke(a), null);
+ }
+
#endregion
#region Events
@@ -1612,6 +1634,7 @@ namespace MtApi
public event EventHandler QuoteAdded;
public event EventHandler QuoteRemoved;
public event EventHandler ConnectionStateChanged;
+ public event EventHandler OnLastTimeBar;
#endregion
#region Private Fields
diff --git a/MtApi/MtEventTypes.cs b/MtApi/MtEventTypes.cs
new file mode 100644
index 00000000..28616df7
--- /dev/null
+++ b/MtApi/MtEventTypes.cs
@@ -0,0 +1,7 @@
+namespace MtApi
+{
+ public enum MtEventTypes
+ {
+ LastTimeBar = 1
+ }
+}
diff --git a/MtApi/MtTimeBar.cs b/MtApi/MtTimeBar.cs
new file mode 100644
index 00000000..dfb1208a
--- /dev/null
+++ b/MtApi/MtTimeBar.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace MtApi
+{
+ public class MtTimeBar
+ {
+ public string Symbol { get; set; }
+ public int MtOpenTime { get; set; }
+ public int MtCloseTime { get; set; }
+ public double Open { get; set; }
+ public double Close { get; set; }
+ public double High { get; set; }
+ public double Low { get; set; }
+
+ public DateTime OpenTime
+ {
+ get { return MtApiTimeConverter.ConvertFromMtTime(MtOpenTime); }
+ }
+
+ public DateTime CloseTime
+ {
+ get { return MtApiTimeConverter.ConvertFromMtTime(MtCloseTime); }
+ }
+
+ }
+}
diff --git a/MtApi/TimeBarArgs.cs b/MtApi/TimeBarArgs.cs
new file mode 100644
index 00000000..e8ae32ba
--- /dev/null
+++ b/MtApi/TimeBarArgs.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MtApi
+{
+ public class TimeBarArgs: EventArgs
+ {
+ public TimeBarArgs(MtTimeBar timeBar)
+ {
+ TimeBar = timeBar;
+ }
+
+ public MtTimeBar TimeBar { get; private set; }
+ }
+}
diff --git a/TestClients/TestApiClientUI/Form1.cs b/TestClients/TestApiClientUI/Form1.cs
index f62aa984..9c8f4d50 100644
--- a/TestClients/TestApiClientUI/Form1.cs
+++ b/TestClients/TestApiClientUI/Form1.cs
@@ -23,6 +23,7 @@ namespace TestApiClientUI
_apiClient.QuoteAdded += apiClient_QuoteAdded;
_apiClient.QuoteRemoved += apiClient_QuoteRemoved;
_apiClient.ConnectionStateChanged += apiClient_ConnectionStateChanged;
+ _apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
initOrderCommandsGroup();
@@ -95,6 +96,14 @@ namespace TestApiClientUI
RunOnUiThread(() => AddNewQuote(e.Quote));
}
+ private void _apiClient_OnLastTimeBar(object sender, TimeBarArgs e)
+ {
+ string msg = string.Format("TimeBar: Symbol = {0}, OpenTime = {1}, CloseTime = {2}, Open = {3}, Close = {4}, High = {5}, Low = {6}",
+ e.TimeBar.Symbol, e.TimeBar.OpenTime, e.TimeBar.CloseTime, e.TimeBar.Open, e.TimeBar.Close, e.TimeBar.High, e.TimeBar.Low);
+ Console.WriteLine(msg);
+ AddToLog(msg);
+ }
+
private volatile bool IsUiQuoteUpdateReady = true;
private void apiClient_QuoteUpdated(object sender, string symbol, double bid, double ask)
diff --git a/mq4/MtApi.ex4 b/mq4/MtApi.ex4
index d1be98bb..d1dd3be7 100755
Binary files a/mq4/MtApi.ex4 and b/mq4/MtApi.ex4 differ
diff --git a/mq4/MtApi.mq4 b/mq4/MtApi.mq4
index 6b8aeda7..2fae8c67 100755
Binary files a/mq4/MtApi.mq4 and b/mq4/MtApi.mq4 differ