diff --git a/MtApi5/MtApi5Client.cs b/MtApi5/MtApi5Client.cs index f7fd45e5..d1124b2a 100755 --- a/MtApi5/MtApi5Client.cs +++ b/MtApi5/MtApi5Client.cs @@ -5,6 +5,7 @@ using MtClient; using MtApi5.MtProtocol; using System.Linq; using System.Net.Http.Headers; +using Newtonsoft.Json.Linq; namespace MtApi5 { @@ -131,12 +132,9 @@ namespace MtApi5 return false; } - var response = SendRequest(new OrderSendRequest - { - TradeRequest = request - }); - - result = response?.TradeResult; + Dictionary commandParameters = new() { { "TradeRequest", request } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.OrderSend, commandParameters); + result = response?.Result; return response != null && response.RetVal; } @@ -163,12 +161,9 @@ namespace MtApi5 return false; } - var response = SendRequest(new OrderSendAsyncRequest - { - TradeRequest = request - }); - - result = response?.TradeResult; + Dictionary commandParameters = new() { { "TradeRequest", request } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.OrderSendAsync, commandParameters); + result = response?.Result; return response != null && response.RetVal; } @@ -244,12 +239,9 @@ namespace MtApi5 return false; } - var response = SendRequest(new OrderCheckRequest - { - TradeRequest = request - }); - - result = response?.TradeCheckResult; + Dictionary commandParameters = new() { { "TradeRequest", request } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.OrderCheck, commandParameters); + result = response?.Result; return response != null && response.RetVal; } @@ -610,13 +602,10 @@ namespace MtApi5 { Log?.Debug($"PositionClose: ticket = {ticket}, deviation = {deviation}"); - var response = SendRequest(new PositionCloseRequest - { - Ticket = ticket, - Deviation = deviation - }); + Dictionary cmdParams = new() { { "Ticket", ticket }, { "Deviation", deviation } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.PositionClose, cmdParams); - result = response?.TradeResult; + result = response?.Result; return response != null && response.RetVal; } @@ -643,9 +632,10 @@ namespace MtApi5 /// true - successful check of the basic structures, otherwise - false. public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, string comment = "") { - var commandParameters = new ArrayList { symbol, (int) orderType, volume, price, sl, tp, comment }; - - return SendCommand(Mt5CommandType.PositionOpen, commandParameters); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "OrderType", (int)orderType }, + { "Volume", volume }, { "Price", price }, { "Sl", sl }, { "Tp", tp }, { "Comment", comment } }; + var response = SendCommand(ExecutorHandle, Mt5CommandType.PositionOpen, cmdParams); + return response; } /// @@ -660,22 +650,17 @@ namespace MtApi5 /// comment /// output result /// true - successful check of the basic structures, otherwise - false. - public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, string comment, out MqlTradeResult? result) + public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, string? comment, out MqlTradeResult? result) { Log?.Debug($"PositionOpen: symbol = {symbol}, orderType = {orderType}, volume = {volume}, price = {price}, sl = {sl}, tp = {tp}, comment = {comment}"); - var response = SendRequest(new PositionOpenRequest - { - Symbol = symbol, - OrderType = orderType, - Volume = volume, - Price = price, - Sl = sl, - Tp = tp, - Comment = comment - }); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "OrderType", (int)orderType }, + { "Volume", volume }, { "Price", price }, { "Sl", sl }, { "Tp", tp } }; + if (comment != null) + cmdParams["Comment"] = comment; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.PositionOpen2, cmdParams); - result = response?.TradeResult; + result = response?.Result; return response != null && response.RetVal; } @@ -738,17 +723,15 @@ namespace MtApi5 { Log?.Debug($"Buy: volume = {volume}, symbol = {symbol}, sl = {sl}, tp = {tp}, comment = {comment}"); - var response = SendRequest(new BuyRequest - { - Volume = volume, - Symbol = symbol, - Price = price, - Sl = sl, - Tp = tp, - Comment = comment - }); + Dictionary cmdParams = new() { { "Volume", volume }, { "Price", price }, { "Sl", sl }, { "Tp", tp } }; + if (symbol != null) + cmdParams["Symbol"] = symbol; + if (comment != null) + cmdParams["Comment"] = comment; - result = response?.TradeResult; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.Buy, cmdParams); + + result = response?.Result; return response != null && response.RetVal; } @@ -767,17 +750,15 @@ namespace MtApi5 { Log?.Debug($"Sell: volume = {volume}, symbol = {symbol}, sl = {sl}, tp = {tp}, comment = {comment}"); - var response = SendRequest(new SellRequest - { - Volume = volume, - Symbol = symbol, - Price = price, - Sl = sl, - Tp = tp, - Comment = comment - }); + Dictionary cmdParams = new() { { "Volume", volume }, { "Price", price }, { "Sl", sl }, { "Tp", tp } }; + if (symbol != null) + cmdParams["Symbol"] = symbol; + if (comment != null) + cmdParams["Comment"] = comment; - result = response?.TradeResult; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.Sell, cmdParams); + + result = response?.Result; return response != null && response.RetVal; } #endregion @@ -1465,15 +1446,11 @@ namespace MtApi5 ///The date from which you want to request ticks. In milliseconds since 1970.01.01. If from=0, the last count ticks will be returned. ///The number of ticks that you want to receive. If the 'from' and 'count' parameters are not specified, all available recent ticks (but not more than 2000) will be written to result. /// - public List CopyTicks(string symbolName, CopyTicksFlag flags = CopyTicksFlag.All, ulong from = 0, uint count = 0) + public List? CopyTicks(string symbolName, CopyTicksFlag flags = CopyTicksFlag.All, ulong from = 0, uint count = 0) { - var response = SendRequest>(new CopyTicksRequest - { - SymbolName = symbolName, - Flags = (int)flags, - From = from, - Count = count - }); + Dictionary cmdParams = new() { { "Symbol", symbolName }, { "Flags", flags }, + { "From", from }, { "Count", count } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.CopyTicks, cmdParams); return response; } @@ -1484,15 +1461,14 @@ namespace MtApi5 ///The value of the timeframe can be one of values of the ENUM_TIMEFRAMES enumeration, 0 means the current timeframe. ///Indicator type, can be one of values of the ENUM_INDICATOR enumeration. ///An array of MqlParam type, whose elements contain the type and value of each input parameter of a technical indicator. - public int IndicatorCreate(string symbol, ENUM_TIMEFRAMES period, ENUM_INDICATOR indicatorType, List? parameters = null) + public int IndicatorCreate(string? symbol, ENUM_TIMEFRAMES period, ENUM_INDICATOR indicatorType, List? parameters = null) { - var response = SendRequest(new IndicatorCreateRequest - { - Symbol = symbol, - Period = period, - IndicatorType = indicatorType, - Parameters = parameters - }); + Dictionary cmdParams = new() { { "Period", (int)period }, { "IndicatorType", (int)indicatorType } }; + if (symbol != null) + cmdParams["Symbol"] = symbol; + if (parameters != null) + cmdParams["Parameters"] = parameters; + var response = SendCommand(ExecutorHandle, Mt5CommandType.IndicatorCreate, cmdParams); return response; } @@ -1581,11 +1557,11 @@ namespace MtApi5 /// ///Symbol name. ///Identifier of a symbol property. - public string SymbolInfoString(string symbolName, ENUM_SYMBOL_INFO_STRING propId) + public string? SymbolInfoString(string symbolName, ENUM_SYMBOL_INFO_STRING propId) { - var commandParameters = new ArrayList { symbolName, (int)propId }; - - return SendCommand(Mt5CommandType.SymbolInfoString, commandParameters); + Dictionary cmdParams = new() { { "Symbol", symbolName }, { "PropId", (int)propId } }; + var response = SendCommand(ExecutorHandle, Mt5CommandType.SymbolInfoString, cmdParams); + return response; } /// @@ -1596,13 +1572,9 @@ namespace MtApi5 ///Variable of the string type receiving the value of the requested property. public bool SymbolInfoString(string symbolName, ENUM_SYMBOL_INFO_STRING propId, out string? value) { - var response = SendRequest(new SymbolInfoStringRequest - { - SymbolName = symbolName, - PropId = propId - }); - - value = response?.StringVar; + Dictionary cmdParams = new() { { "Symbol", symbolName }, { "PropId", (int)propId } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.SymbolInfoString2, cmdParams); + value = response?.Result; return response?.RetVal ?? false; } @@ -1612,28 +1584,23 @@ namespace MtApi5 /// ///Symbol name. /// Link to the structure of the MqlTick type, to which the current prices and time of the last price update will be placed. - public bool SymbolInfoTick(string symbol, out MqlTick tick) + public bool SymbolInfoTick(string symbol, out MqlTick? tick) { - tick = SendRequest(new SymbolInfoTickRequest - { - SymbolName = symbol - }); - - return tick != null; + Dictionary cmdParams = new() { { "Symbol", symbol } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.SymbolInfoTick, cmdParams); + tick = response?.Result; + return response?.RetVal ?? false; } /// ///The function returns current prices of a specified symbol in a variable of the MqlTick type. /// ///Symbol name. - public MqlTick SymbolInfoTick(string symbol) + public MqlTick? SymbolInfoTick(string symbol) { - var tick = SendRequest(new SymbolInfoTickRequest - { - SymbolName = symbol - }); - - return tick; + if (SymbolInfoTick(symbol, out MqlTick? tick)) + return tick; + return null; } /// @@ -1699,11 +1666,8 @@ namespace MtApi5 ///Reference to an array of Depth of Market records. public bool MarketBookGet(string symbol, out MqlBookInfo[]? book) { - var response = SendRequest>(new MarketBookGetRequest - { - Symbol = symbol - }); - + Dictionary cmdParams = new() { { "Symbol", symbol } }; + var response = SendCommand>(ExecutorHandle, Mt5CommandType.MarketBookGet, cmdParams); book = response?.ToArray(); return response != null; } @@ -1801,17 +1765,17 @@ namespace MtApi5 /// public bool ChartTimePriceToXY(long chartId, int subWindow, DateTime? time, double price, out int x, out int y) { - var result = SendRequest(new ChartTimePriceToXyRequest - { - ChartId = chartId, - SubWindow = subWindow, - Time = time, - Price = price - }); + Dictionary cmdParams = new() { { "ChartId", chartId }, { "SubWindow", subWindow }, + { "Time", Mt5TimeConverter.ConvertToMtTime(time) }, { "Price", price } }; - x = result?.X ?? 0; - y = result?.Y ?? 0; - return result?.RetVal ?? false; + Dictionary XY = []; + var response = SendCommand>>(ExecutorHandle, Mt5CommandType.ChartTimePriceToXY, cmdParams); + if (response != null && response.Result != null + && response.Result.TryGetValue("X", out x) + && response.Result.TryGetValue("Y", out y)) + return response.RetVal; + x = 0; y = 0; + return false; } /// @@ -1828,17 +1792,22 @@ namespace MtApi5 /// public bool ChartXYToTimePrice(long chartId, int x, int y, out int subWindow, out DateTime? time, out double price) { - var result = SendRequest(new ChartXyToTimePriceRequest + Dictionary cmdParams = new() { { "ChartId", chartId }, { "X", x }, { "Y", y } }; + var response = SendCommand>>(ExecutorHandle, Mt5CommandType.ChartXYToTimePrice, cmdParams); + if (response != null && response.Result != null + && response.Result.TryGetValue("SubWindow", out object? mtSubWindow) + && response.Result.TryGetValue("Time", out object? mtTime) + && response.Result.TryGetValue("Price", out object? mtPrice)) { - ChartId = chartId, - X = x, - Y = y - }); - - subWindow = result?.SubWindow ?? 0; - time = result?.Time; - price = result?.Price ?? double.NaN; - return result?.RetVal ?? false; + subWindow = Convert.ToInt32(mtSubWindow); + time = Mt5TimeConverter.ConvertFromMtTime(Convert.ToInt32(mtTime)); + price = Convert.ToDouble(mtPrice); + return response.RetVal; + } + subWindow = 0; + time = null; + price = double.NaN; + return false; } /// @@ -2987,16 +2956,11 @@ namespace MtApi5 ///input-parameters of a custom indicator. If there is no parameters specified, then default values will be used. public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, double[] parameters) { - Log?.Debug("iCustom: called."); - var response = SendRequest(new ICustomRequest - { - Symbol = symbol, - Timeframe = (int)period, - Name = name, - Params = new ArrayList(parameters), - ParamsType = ICustomRequest.ParametersType.Double - }); - Log?.Debug($"iCustom: response = {response}."); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "Period", (int)period }, + { "Name", name }, { "Parameters", parameters } }; + cmdParams["ParamsType"] = ICustomRequest.ParametersType.Double; + + var response = SendCommand(ExecutorHandle, Mt5CommandType.iCustom, cmdParams); return response; } @@ -3009,16 +2973,11 @@ namespace MtApi5 ///input-parameters of a custom indicator. If there is no parameters specified, then default values will be used. public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, int[] parameters) { - Log?.Debug("iCustom: called."); - var response = SendRequest(new ICustomRequest - { - Symbol = symbol, - Timeframe = (int)period, - Name = name, - Params = new ArrayList(parameters), - ParamsType = ICustomRequest.ParametersType.Int - }); - Log?.Debug($"iCustom: response = {response}."); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "Period", (int)period }, + { "Name", name }, { "Parameters", parameters } }; + cmdParams["ParamsType"] = ICustomRequest.ParametersType.Int; + + var response = SendCommand(ExecutorHandle, Mt5CommandType.iCustom, cmdParams); return response; } @@ -3031,16 +2990,11 @@ namespace MtApi5 ///input-parameters of a custom indicator. If there is no parameters specified, then default values will be used. public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, string[] parameters) { - Log?.Debug("iCustom: called."); - var response = SendRequest(new ICustomRequest - { - Symbol = symbol, - Timeframe = (int)period, - Name = name, - Params = new ArrayList(parameters), - ParamsType = ICustomRequest.ParametersType.Int - }); - Log?.Debug($"iCustom: response = {response}."); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "Period", (int)period }, + { "Name", name }, { "Parameters", parameters } }; + cmdParams["ParamsType"] = ICustomRequest.ParametersType.String; + + var response = SendCommand(ExecutorHandle, Mt5CommandType.iCustom, cmdParams); return response; } @@ -3053,16 +3007,11 @@ namespace MtApi5 ///input-parameters of a custom indicator. If there is no parameters specified, then default values will be used. public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, bool[] parameters) { - Log?.Debug("iCustom: called."); - var response = SendRequest(new ICustomRequest - { - Symbol = symbol, - Timeframe = (int)period, - Name = name, - Params = new ArrayList(parameters), - ParamsType = ICustomRequest.ParametersType.Int - }); - Log?.Debug($"iCustom: response = {response}."); + Dictionary cmdParams = new() { { "Symbol", symbol }, { "Period", (int)period }, + { "Name", name }, { "Parameters", parameters } }; + cmdParams["ParamsType"] = ICustomRequest.ParametersType.Boolean; + + var response = SendCommand(ExecutorHandle, Mt5CommandType.iCustom, cmdParams); return response; } @@ -3682,35 +3631,35 @@ namespace MtApi5 return default(T); } - private T SendRequest(RequestBase request) - { - if (request == null) - return default(T); + //private T SendRequest(RequestBase request) + //{ + // if (request == null) + // return default(T); - var serializer = JsonConvert.SerializeObject(request, Formatting.None, - new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore - }); - var commandParameters = new ArrayList { serializer }; + // var serializer = JsonConvert.SerializeObject(request, Formatting.None, + // new JsonSerializerSettings + // { + // NullValueHandling = NullValueHandling.Ignore + // }); + // var commandParameters = new ArrayList { serializer }; - var res = SendCommand(Mt5CommandType.MtRequest, commandParameters); + // var res = SendCommand(Mt5CommandType.MtRequest, commandParameters); - if (res == null) - { - Log?.Warn("SendRequest: Response from MetaTrader is null"); - throw new ExecutionException(ErrorCode.ErrCustom, "Response from MetaTrader is null"); - } + // if (res == null) + // { + // Log?.Warn("SendRequest: Response from MetaTrader is null"); + // throw new ExecutionException(ErrorCode.ErrCustom, "Response from MetaTrader is null"); + // } - var response = JsonConvert.DeserializeObject>(res) ?? throw new Exception("Failed to deserialize response"); - if (response.ErrorCode != 0) - { - Log?.Warn($"SendRequest: ErrorCode = {response.ErrorCode}. {response}"); - throw new ExecutionException((ErrorCode)response.ErrorCode, response.ErrorMessage); - } + // var response = JsonConvert.DeserializeObject>(res) ?? throw new Exception("Failed to deserialize response"); + // if (response.ErrorCode != 0) + // { + // Log?.Warn($"SendRequest: ErrorCode = {response.ErrorCode}. {response}"); + // throw new ExecutionException((ErrorCode)response.ErrorCode, response.ErrorMessage); + // } - return response.Value; - } + // return response.Value; + //} private void OnConnected() { diff --git a/MtApi5/MtProtocol/Mt5CommandType.cs b/MtApi5/MtProtocol/Mt5CommandType.cs index 078bfb4a..385bf318 100755 --- a/MtApi5/MtProtocol/Mt5CommandType.cs +++ b/MtApi5/MtProtocol/Mt5CommandType.cs @@ -90,6 +90,7 @@ namespace MtApi5.MtProtocol SymbolInfoDouble = 54, SymbolInfoInteger = 55, SymbolInfoString = 56, + SymbolInfoString2 = 1056, SymbolInfoTick = 57, SymbolInfoSessionQuote = 58, SymbolInfoSessionTrade = 59, @@ -101,6 +102,7 @@ namespace MtApi5.MtProtocol //CTrade PositionClose = 64, PositionOpen = 65, + PositionOpen2 = 1065, PositionModify = 6066, PositionClosePartial_bySymbol = 6067, PositionClosePartial_byTicket = 6068, @@ -111,7 +113,7 @@ namespace MtApi5.MtProtocol IsTesting = 67, //Requests - MtRequest = 155, + //MtRequest = 155, PositionSelectByTicket = 69, @@ -147,7 +149,7 @@ namespace MtApi5.MtProtocol iBullsPower = 98, iCCI = 99, iChaikin = 100, - //iCustom = 101, + iCustom = 101, iDEMA = 102, iDeMarker = 103, iEnvelopes = 104, @@ -188,8 +190,8 @@ namespace MtApi5.MtProtocol ChartApplyTemplate = 236, ChartSaveTemplate = 237, ChartWindowFind = 238, - //ChartTimePriceToXY = 239, - //ChartXYToTimePrice = 240, + ChartTimePriceToXY = 239, + ChartXYToTimePrice = 240, ChartOpen = 241, ChartFirst = 242, ChartNext = 243, @@ -255,6 +257,15 @@ namespace MtApi5.MtProtocol UnlockTicks = 159, PositionCloseAll = 160, - TesterStop = 161 + TesterStop = 161, + + CopyTicks = 300, + OrderSend = 301, + OrderSendAsync = 302, + OrderCheck = 303, + MarketBookGet = 304, + IndicatorCreate = 305, + Buy = 306, + Sell = 307 } }