From 1a5882b75a784ce42d4154219e317413bc04100b Mon Sep 17 00:00:00 2001 From: vdemydiuk Date: Tue, 5 Jun 2018 19:19:35 +0300 Subject: [PATCH] Issue #122: Implemented UnlockTicks function in MtApi (MT5) --- MTApiService/Mt5Expert.cs | 53 +++++++-- MTApiService/MtAdapter.cs | 27 ++++- MTApiService/MtExpert.cs | 6 +- MtApi5/Events/Mt5EventTypes.cs | 3 +- MtApi5/Events/OnLastTimeBarEvent.cs | 9 ++ MtApi5/MqlRates.cs | 4 +- MtApi5/Mt5CommandType.cs | 4 +- MtApi5/Mt5TimeBarArgs.cs | 18 +++ MtApi5/MtApi5.csproj | 2 + MtApi5/MtApi5Client.cs | 20 ++++ TestClients/MtApi5TestClient/MainWindow.xaml | 5 +- TestClients/MtApi5TestClient/ViewModel.cs | 15 +++ mq5/MtApi5.ex5 | Bin 610066 -> 705132 bytes mq5/MtApi5.mq5 | 116 +++++++++++++++++-- 14 files changed, 252 insertions(+), 30 deletions(-) create mode 100644 MtApi5/Events/OnLastTimeBarEvent.cs create mode 100644 MtApi5/Mt5TimeBarArgs.cs diff --git a/MTApiService/Mt5Expert.cs b/MTApiService/Mt5Expert.cs index 24f58da3..9f96e4e8 100644 --- a/MTApiService/Mt5Expert.cs +++ b/MTApiService/Mt5Expert.cs @@ -4,35 +4,51 @@ namespace MTApiService { public class Mt5Expert : MtExpert { - private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert)); + private static readonly ILog Log = LogManager.GetLogger(typeof(Mt5Expert)); private const int StopExpertInterval = 2000; // 2 sec for testing mode - private readonly System.Timers.Timer _stopTimer = new System.Timers.Timer(); + private System.Timers.Timer _stopTimer; public Mt5Expert(int handle, string symbol, double bid, double ask, IMetaTraderHandler mtHandler, bool isTestMode) : base(handle, symbol, bid, ask, mtHandler) { IsTestMode = isTestMode; - _stopTimer.Interval = StopExpertInterval; - _stopTimer.Elapsed += _stopTimer_Elapsed; } public bool IsTestMode { get; } - public override void UpdateQuote(MtQuote quote) + public override int GetCommandType() { - Log.Debug("UpdateQuote: begin."); - - base.UpdateQuote(quote); + Log.Debug("GetCommandType: called."); if (IsTestMode) { - //reset timer - _stopTimer.Stop(); - _stopTimer.Start(); + ResetTestModeTimer(); } - Log.Debug("UpdateQuote: end."); + return base.GetCommandType(); + } + + public override void SendEvent(MtEvent mtEvent) + { + Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent); + + if (IsTestMode) + { + if (_stopTimer == null) + { + _stopTimer = new System.Timers.Timer + { + Interval = StopExpertInterval, + AutoReset = false + }; + _stopTimer.Elapsed += _stopTimer_Elapsed; + } + } + + base.SendEvent(mtEvent); + + Log.Debug("SendEvent: end."); } private void _stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) @@ -42,7 +58,20 @@ namespace MTApiService Log.Warn("Mt5Expert has received new tick during 2 sec in testing mode. The possible cause: user has stopped the tester manually in MetaTrader 5."); Deinit(); + _stopTimer.Elapsed -= _stopTimer_Elapsed; + _stopTimer = null; + Log.Debug("_stopTimer_Elapsed: end."); } + + private void ResetTestModeTimer() + { + if (_stopTimer == null) + return; + + //reset timer + _stopTimer.Stop(); + _stopTimer.Start(); + } } } \ No newline at end of file diff --git a/MTApiService/MtAdapter.cs b/MTApiService/MtAdapter.cs index 30f810be..e5c075a5 100644 --- a/MTApiService/MtAdapter.cs +++ b/MTApiService/MtAdapter.cs @@ -66,6 +66,7 @@ namespace MTApiService } server.AddExpert(expert); + expert.Deinited += ExpertOnDeinited; Log.Info("AddExpert: end"); } @@ -81,7 +82,6 @@ namespace MTApiService if (_experts.ContainsKey(expertHandle)) { expert = _experts[expertHandle]; - _experts.Remove(expertHandle); } } @@ -270,6 +270,31 @@ namespace MTApiService } } } + + + private void ExpertOnDeinited(object sender, EventArgs eventArgs) + { + Log.Debug("ExpertOnDeinited: begin."); + + var expert = sender as MtExpert; + if (expert == null) + { + Log.Warn("expert_Deinited: end. Expert is not defined."); + return; + } + + lock (_experts) + { + if (_experts.ContainsKey(expert.Handle)) + { + _experts.Remove(expert.Handle); + } + } + + Log.DebugFormat("ExpertOnDeinited: removed expert {0}", expert.Handle); + + Log.Debug("ExpertOnDeinited: end."); + } #endregion } } diff --git a/MTApiService/MtExpert.cs b/MTApiService/MtExpert.cs index 3524906a..186124e7 100755 --- a/MTApiService/MtExpert.cs +++ b/MTApiService/MtExpert.cs @@ -48,7 +48,7 @@ namespace MTApiService Log.Debug("SendResponse: end."); } - public int GetCommandType() + public virtual int GetCommandType() { Log.Debug("GetCommandType: called."); @@ -110,7 +110,7 @@ namespace MTApiService return command.NamedParams.ContainsKey(name); } - public void SendEvent(MtEvent mtEvent) + public virtual void SendEvent(MtEvent mtEvent) { Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent); @@ -119,7 +119,7 @@ namespace MTApiService Log.Debug("SendEvent: end."); } - public virtual void UpdateQuote(MtQuote quote) + public void UpdateQuote(MtQuote quote) { Log.DebugFormat("UpdateQuote: begin. quote = {0}", quote); diff --git a/MtApi5/Events/Mt5EventTypes.cs b/MtApi5/Events/Mt5EventTypes.cs index bc7a8266..99e1a1a4 100644 --- a/MtApi5/Events/Mt5EventTypes.cs +++ b/MtApi5/Events/Mt5EventTypes.cs @@ -4,6 +4,7 @@ { OnTradeTransaction = 1, OnBookEvent = 2, - OnTick = 3 + OnTick = 3, + OnLastTimeBar = 4 } } diff --git a/MtApi5/Events/OnLastTimeBarEvent.cs b/MtApi5/Events/OnLastTimeBarEvent.cs new file mode 100644 index 00000000..f6995043 --- /dev/null +++ b/MtApi5/Events/OnLastTimeBarEvent.cs @@ -0,0 +1,9 @@ +namespace MtApi5.Events +{ + public class OnLastTimeBarEvent + { + public MqlRates Rates { get; set; } + public string Instrument { get; set; } + public int ExpertHandle { get; set; } + } +} \ No newline at end of file diff --git a/MtApi5/MqlRates.cs b/MtApi5/MqlRates.cs index 740cedb7..8d8ee6e6 100755 --- a/MtApi5/MqlRates.cs +++ b/MtApi5/MqlRates.cs @@ -7,7 +7,6 @@ namespace MtApi5 { public MqlRates(DateTime time, double open, double high, double low, double close, long tick_volume, int spread, long real_volume) { - this.time = time; mt_time = Mt5TimeConverter.ConvertToMtTime(time); this.open = open; this.high = high; @@ -20,7 +19,6 @@ namespace MtApi5 internal MqlRates(long time, double open, double high, double low, double close, long tick_volume, int spread, long real_volume) { - this.time = Mt5TimeConverter.ConvertFromMtTime(time); mt_time = time; this.open = open; this.high = high; @@ -35,7 +33,7 @@ namespace MtApi5 { } - public DateTime time { get; set; } // Period start time + public DateTime time => Mt5TimeConverter.ConvertFromMtTime(mt_time); // Period start time public long mt_time { get; set; } // Period start time (original MT time) public double open { get; set; } // Open price public double high { get; set; } // The highest price of the period diff --git a/MtApi5/Mt5CommandType.cs b/MtApi5/Mt5CommandType.cs index 2fe7948d..bde25f2d 100755 --- a/MtApi5/Mt5CommandType.cs +++ b/MtApi5/Mt5CommandType.cs @@ -248,6 +248,8 @@ namespace MtApi5 GlobalVariableTemp = 154, GlobalVariableSetOnCondition = 156, GlobalVariablesDeleteAll = 157, - GlobalVariablesTotal = 158 + GlobalVariablesTotal = 158, + + UnlockTicks = 159 } } diff --git a/MtApi5/Mt5TimeBarArgs.cs b/MtApi5/Mt5TimeBarArgs.cs new file mode 100644 index 00000000..4f89eb54 --- /dev/null +++ b/MtApi5/Mt5TimeBarArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace MtApi5 +{ + public class Mt5TimeBarArgs: EventArgs + { + internal Mt5TimeBarArgs(int expertHandle, string symbol, MqlRates rates) + { + ExpertHandle = expertHandle; + Rates = rates; + Symbol = symbol; + } + + public int ExpertHandle { get; } + public string Symbol { get; } + public MqlRates Rates { get; } + } +} diff --git a/MtApi5/MtApi5.csproj b/MtApi5/MtApi5.csproj index a765925a..8bd98c21 100755 --- a/MtApi5/MtApi5.csproj +++ b/MtApi5/MtApi5.csproj @@ -49,8 +49,10 @@ + + diff --git a/MtApi5/MtApi5Client.cs b/MtApi5/MtApi5Client.cs index 84d9dd8b..60ae0658 100755 --- a/MtApi5/MtApi5Client.cs +++ b/MtApi5/MtApi5Client.cs @@ -53,6 +53,7 @@ namespace MtApi5 _mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent; _mtEventHandlers[Mt5EventTypes.OnTick] = ReceivedOnTickEvent; _mtEventHandlers[Mt5EventTypes.OnTradeTransaction] = ReceivedOnTradeTransaction; + _mtEventHandlers[Mt5EventTypes.OnLastTimeBar] = ReceivedOnLastTimeBar; } /// @@ -3057,6 +3058,18 @@ namespace MtApi5 } #endregion + #region Backtesting functions + + /// + ///The function unlock ticks in backtesting mode. + /// + public void UnlockTicks() + { + SendCommand(Mt5CommandType.UnlockTicks, null); + } + + #endregion + #endregion // Public Methods #region Properties @@ -3104,6 +3117,7 @@ namespace MtApi5 public event EventHandler ConnectionStateChanged; public event EventHandler OnTradeTransaction; public event EventHandler OnBookEvent; + public event EventHandler OnLastTimeBar; #endregion #region Private Methods @@ -3216,6 +3230,12 @@ namespace MtApi5 QuoteUpdate?.Invoke(this, new Mt5QuoteEventArgs(quote)); } + private void ReceivedOnLastTimeBar(int expertHandler, string payload) + { + var e = JsonConvert.DeserializeObject(payload); + OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandler, e.Instrument, e.Rates)); + } + private void Connect(string host, int port) { var client = new MtClient(host, port); diff --git a/TestClients/MtApi5TestClient/MainWindow.xaml b/TestClients/MtApi5TestClient/MainWindow.xaml index 62c9e970..b9383780 100755 --- a/TestClients/MtApi5TestClient/MainWindow.xaml +++ b/TestClients/MtApi5TestClient/MainWindow.xaml @@ -574,6 +574,7 @@ + @@ -581,7 +582,9 @@