diff --git a/MtApi/MtTypes.cs b/MtApi/MtTypes.cs index ff48f41b..81b18a47 100755 --- a/MtApi/MtTypes.cs +++ b/MtApi/MtTypes.cs @@ -1,4 +1,6 @@ -namespace MtApi +// ReSharper disable InconsistentNaming + +namespace MtApi { public enum ENUM_TERMINAL_INFO_STRING { diff --git a/MtApi5/MqlTradeRequest.cs b/MtApi5/MqlTradeRequest.cs index 7ce45cb5..c940979f 100755 --- a/MtApi5/MqlTradeRequest.cs +++ b/MtApi5/MqlTradeRequest.cs @@ -1,4 +1,5 @@ -using System; +// ReSharper disable InconsistentNaming +using System; namespace MtApi5 { @@ -22,6 +23,8 @@ namespace MtApi5 public ulong Position { get; set; } // Position ticket public ulong PositionBy { get; set; } // The ticket of an opposite position + public int MtExpiration => Mt5TimeConverter.ConvertToMtTime(Expiration); + public override string ToString() { return $"{Symbol}|{Volume}|{Price}|{Volume}|{Action}"; diff --git a/MtApi5/MqlTradeResult.cs b/MtApi5/MqlTradeResult.cs index d9e8e8e6..0d10af81 100755 --- a/MtApi5/MqlTradeResult.cs +++ b/MtApi5/MqlTradeResult.cs @@ -1,4 +1,6 @@ -namespace MtApi5 +// ReSharper disable InconsistentNaming + +namespace MtApi5 { public class MqlTradeResult { @@ -15,15 +17,28 @@ Request_id = request_id; } - public uint Retcode { get; private set; } // Operation return code - public ulong Deal { get; private set; } // Deal ticket, if it is performed - public ulong Order { get; private set; } // Order ticket, if it is placed - public double Volume { get; private set; } // Deal volume, confirmed by broker - public double Price { get; private set; } // Deal price, confirmed by broker - public double Bid { get; private set; } // Current Bid price - public double Ask { get; private set; } // Current Ask price - public string Comment { get; private set; } // Broker comment to operation (by default it is filled by the operation description) - public uint Request_id { get; private set; } // Request ID set by the terminal during the dispatch + internal MqlTradeResult(MqlTradeResult o) + { + Retcode = o.Retcode; + Deal = o.Deal; + Order = o.Order; + Volume = o.Volume; + Price = o.Price; + Bid = o.Bid; + Ask = o.Ask; + Comment = o.Comment; + Request_id = o.Request_id; + } + + public uint Retcode { get; } // Operation return code + public ulong Deal { get; } // Deal ticket, if it is performed + public ulong Order { get; } // Order ticket, if it is placed + public double Volume { get; } // Deal volume, confirmed by broker + public double Price { get; } // Deal price, confirmed by broker + public double Bid { get; } // Current Bid price + public double Ask { get; } // Current Ask price + public string Comment { get; } // Broker comment to operation (by default it is filled by the operation description) + public uint Request_id { get; } // Request ID set by the terminal during the dispatch public override string ToString() { diff --git a/MtApi5/Mt5Enums.cs b/MtApi5/Mt5Enums.cs index 2c5fd935..1cd3cb7b 100755 --- a/MtApi5/Mt5Enums.cs +++ b/MtApi5/Mt5Enums.cs @@ -1,4 +1,6 @@ -namespace MtApi5 +// ReSharper disable InconsistentNaming + +namespace MtApi5 { // Chart Constants: diff --git a/MtApi5/MtApi5.csproj b/MtApi5/MtApi5.csproj index dfd855fd..30bc22a9 100755 --- a/MtApi5/MtApi5.csproj +++ b/MtApi5/MtApi5.csproj @@ -73,6 +73,7 @@ + diff --git a/MtApi5/MtApi5Client.cs b/MtApi5/MtApi5Client.cs index 015c8876..8a746d0d 100755 --- a/MtApi5/MtApi5Client.cs +++ b/MtApi5/MtApi5Client.cs @@ -1,9 +1,9 @@ -using System; +// ReSharper disable InconsistentNaming +using System; using System.Collections.Generic; using System.Linq; using MTApiService; using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.ServiceModel; using MtApi5.Requests; using MtApi5.Responses; @@ -12,7 +12,6 @@ using System.Threading.Tasks; namespace MtApi5 { - [SuppressMessage("ReSharper", "InconsistentNaming")] public class MtApi5Client { #region MT Constants @@ -117,13 +116,22 @@ namespace MtApi5 return false; } - var commandParameters = request.ToArrayList(); + var response = SendRequest(new OrderSendRequest + { + TradeRequest = request + }); - var strResult = SendCommand(Mt5CommandType.OrderSend, commandParameters); + result = response?.Value?.TradeResult; + return response?.Value != null && response.Value.RetVal; - Log.Debug($"OrderSend: strResult = {strResult}"); - return strResult.ParseResult(ParamSeparator, out result); + //var commandParameters = request.ToArrayList(); + + //var strResult = SendCommand(Mt5CommandType.OrderSend, commandParameters); + + //Log.Debug($"OrderSend: strResult = {strResult}"); + + //return strResult.ParseResult(ParamSeparator, out result); } /// @@ -2398,7 +2406,7 @@ namespace MtApi5 } var responseValue = response.GetValue(); - return responseValue != null ? (T)responseValue : default(T); + return (T) responseValue; } private T SendRequest(RequestBase request) where T : ResponseBase, new() diff --git a/MtApi5/Responses/ICustomResponse.cs b/MtApi5/Responses/ICustomResponse.cs index 4116f209..aaaf864e 100644 --- a/MtApi5/Responses/ICustomResponse.cs +++ b/MtApi5/Responses/ICustomResponse.cs @@ -1,4 +1,5 @@ -namespace MtApi5.Responses +// ReSharper disable InconsistentNaming +namespace MtApi5.Responses { internal class ICustomResponse: ResponseBase { diff --git a/MtApi5/Responses/OrderSendResponse.cs b/MtApi5/Responses/OrderSendResponse.cs new file mode 100644 index 00000000..f3a0a3ea --- /dev/null +++ b/MtApi5/Responses/OrderSendResponse.cs @@ -0,0 +1,13 @@ +namespace MtApi5.Responses +{ + internal class OrderSendResult + { + public bool RetVal { get; set; } + public MqlTradeResult TradeResult { get; set; } + } + + internal class OrderSendResponse: ResponseBase + { + public OrderSendResult Value { get; set; } + } +} \ No newline at end of file diff --git a/TestClients/MtApi5TestClient/ViewModel.cs b/TestClients/MtApi5TestClient/ViewModel.cs index afccdc97..6aeb4233 100755 --- a/TestClients/MtApi5TestClient/ViewModel.cs +++ b/TestClients/MtApi5TestClient/ViewModel.cs @@ -269,15 +269,14 @@ namespace MtApi5TestClient private async void ExecuteOrderSend(object o) { var request = TradeRequest.GetMqlTradeRequest(); - + MqlTradeResult result = null; var retVal = await Execute(() => { - MqlTradeResult result; var ok = _mtApiClient.OrderSend(request, out result); - return ok ? result : null; + return ok; }); - var message = retVal != null ? $"OrderSend successed. {MqlTradeResultToString(retVal)}" : "OrderSend failed."; + var message = retVal ? $"OrderSend excute successed. {MqlTradeResultToString(result)}" : $"OrderSend execute failed. {MqlTradeResultToString(result)}"; AddLog(message); } diff --git a/mq5/MtApi5.ex5 b/mq5/MtApi5.ex5 index 3547d3c3..e50b4d47 100755 Binary files a/mq5/MtApi5.ex5 and b/mq5/MtApi5.ex5 differ diff --git a/mq5/MtApi5.mq5 b/mq5/MtApi5.mq5 index 90d50a39..10c389fc 100755 --- a/mq5/MtApi5.mq5 +++ b/mq5/MtApi5.mq5 @@ -39,7 +39,7 @@ bool getBooleanValue(int expertHandle, int paramIndex, bool& res, string& err); #import -//#define __DEBUG_LOG__ +#define __DEBUG_LOG__ input int Port = 8228; @@ -5562,7 +5562,7 @@ string OnRequest(string json) if(jv == NULL) { - PrintFormat("OnRequest [ERROR]: %d - %s", (string)parser.getErrorCode(), parser.getErrorMessage()); + PrintFormat("%s [ERROR]: %d - %s", __FUNCTION__, (string)parser.getErrorCode(), parser.getErrorMessage()); } else { @@ -5579,8 +5579,11 @@ string OnRequest(string json) case 2: //iCustom response = ExecuteRequest_iCustom(jo); break; + case 3: //OrderSend + response = ExecuteRequest_OrderSend(jo); + break; default: - PrintFormat("OnRequest [WARNING]: Unknown request type %d", requestType); + PrintFormat("%s [WARNING]: Unknown request type %d", __FUNCTION__, requestType); response = CreateErrorResponse(-1, "Unknown request type"); break; } @@ -5770,4 +5773,121 @@ int iCustomT(string symbol, ENUM_TIMEFRAMES timeframe, string name, T &p[], int default: return 0; } +} + +#define PRINT_MSG_AND_RETURN_VALUE(msg,value) PrintFormat("%s: %s",__FUNCTION__,msg);return value +#define CHECK_JSON_VALUE(jo, name_value, return_fail_result) if (jo.getValue(name_value) == NULL) { PRINT_MSG_AND_RETURN_VALUE(StringFormat("failed to get %s from JSON!", name_value), return_fail_result); } + +bool JsonToMqlTradeRequest(JSONObject *jo, MqlTradeRequest& request) +{ + //Action + CHECK_JSON_VALUE(jo, "Action", false); + request.action = (ENUM_TRADE_REQUEST_ACTIONS) jo.getInt("Action"); + + //Magic + CHECK_JSON_VALUE(jo, "Magic", false); + request.magic = jo.getLong("Magic"); + + //Order + CHECK_JSON_VALUE(jo, "Order", false); + request.order = jo.getLong("Magic"); + + //Symbol + CHECK_JSON_VALUE(jo, "Symbol", false); + StringInit(request.symbol, 100, 0); + request.symbol = jo.getString("Symbol"); + + //Volume + CHECK_JSON_VALUE(jo, "Volume", false); + request.volume = jo.getDouble("Volume"); + + //Price + CHECK_JSON_VALUE(jo, "Price", false); + request.price = jo.getDouble("Price"); + + //Stoplimit + CHECK_JSON_VALUE(jo, "Stoplimit", false); + request.stoplimit = jo.getDouble("Stoplimit"); + + //Sl + CHECK_JSON_VALUE(jo, "Sl", false); + request.sl = jo.getDouble("Sl"); + + //Tp + CHECK_JSON_VALUE(jo, "Tp", false); + request.tp = jo.getDouble("Tp"); + + //Deviation + CHECK_JSON_VALUE(jo, "Deviation", false); + request.deviation = jo.getLong("Deviation"); + + //Type + CHECK_JSON_VALUE(jo, "Type", false); + request.type = (ENUM_ORDER_TYPE)jo.getInt("Type"); + + //Type_filling + CHECK_JSON_VALUE(jo, "Type_filling", false); + request.type_filling = (ENUM_ORDER_TYPE_FILLING)jo.getInt("Type_filling"); + + //Type_time + CHECK_JSON_VALUE(jo, "Type_time", false); + request.type_time = (ENUM_ORDER_TYPE_TIME)jo.getInt("Type_time"); + + //Expiration + CHECK_JSON_VALUE(jo, "Expiration", false); + request.expiration = (datetime)jo.getInt("MtExpiration"); + + //Comment + CHECK_JSON_VALUE(jo, "Comment", false); + StringInit(request.comment, 1000, 0); + request.comment = jo.getString("Comment"); + + //Position + CHECK_JSON_VALUE(jo, "Position", false); + request.position = jo.getLong("Position"); + + //PositionBy + CHECK_JSON_VALUE(jo, "PositionBy", false); + request.position_by = jo.getLong("PositionBy"); + + return true; +} + +JSONObject* MqlTradeResultToJson(MqlTradeResult& result) +{ + JSONObject* jo = new JSONObject(); + + jo.put("Retcode", new JSONNumber(result.retcode)); + jo.put("Deal", new JSONNumber(result.deal)); + jo.put("Order", new JSONNumber(result.order)); + jo.put("Volume", new JSONNumber(result.volume)); + jo.put("Price", new JSONNumber(result.price)); + jo.put("Bid", new JSONNumber(result.bid)); + jo.put("Ask", new JSONNumber(result.ask)); + jo.put("Comment", new JSONString(result.comment)); + jo.put("Request_id", new JSONNumber(result.request_id)); + + return jo; +} + +string ExecuteRequest_OrderSend(JSONObject *jo) +{ + CHECK_JSON_VALUE(jo, "TradeRequest", CreateErrorResponse(-1, "Undefinded mandatory parameter TradeRequest")); + JSONObject* trade_request_jo = jo.getObject("TradeRequest"); + + MqlTradeRequest trade_request = {0}; + JsonToMqlTradeRequest(trade_request_jo, trade_request); + + MqlTradeResult trade_result = {0}; + bool ok = OrderSend(trade_request, trade_result); + + JSONObject* result_value_jo = new JSONObject(); + result_value_jo.put("RetVal", new JSONBool(ok)); + result_value_jo.put("TradeResult", MqlTradeResultToJson(trade_result)); + +#ifdef __DEBUG_LOG__ + PrintFormat("%s: return value = %s", __FUNCTION__, ok ? "true" : "false"); +#endif + + return CreateSuccessResponse("Value", result_value_jo); } \ No newline at end of file