Compare commits

...

36 Commits

Author SHA1 Message Date
Viacheslav Demydiuk a77c08258e Merge branch 'dev' 2026-04-07 11:37:39 +03:00
Viacheslav Demydiuk 3699b73cf7 Issue #290: provide information about Period (Timeframe) in event Mt5TimeBar 2026-04-06 21:55:59 +03:00
Viacheslav Demydiuk 9d178280d0 Issue #290: MQL5 - added Timeframe into event MtTimeBarEvent 2026-04-06 21:53:50 +03:00
Viacheslav Demydiuk a8bb1a3af9 Issue #261: MQL5 - reset flag _is_ticks_locked in function Execute_UnlockTicks 2026-04-06 21:23:48 +03:00
Viacheslav Demydiuk fa1e6b6c62 Issue #296: MtApi5 - Added property CommandTimeout to define time for waiting result of response from MetaTrader. Default value 30 sec 2026-04-06 20:22:10 +03:00
Viacheslav Demydiuk 9e26a1d262 Merge branch 'dev' 2025-12-05 23:49:05 +02:00
Viacheslav Demydiuk 249b0f9fbb Issue #262: function GetQuotes load data from MT instead of using cached quotes 2025-12-05 23:43:27 +02:00
Viacheslav Demydiuk 0a1ec30b84 Merge branch 'dev' 2025-10-08 16:30:01 +03:00
Viacheslav Demydiuk 0c874773e5 Issue #241: fixed issue of incorrect value of CloseTime in orders received from TradeMonitor 2025-10-08 16:23:16 +03:00
Viacheslav Demydiuk 2c4d9b130b MQL4: update function OrderClose to avoid compile warnings 2025-10-08 10:59:05 +03:00
Viacheslav Demydiuk a900ea8968 Merge branch 'dev' 2025-10-07 17:04:48 +03:00
Viacheslav Demydiuk a5b8e33611 Issue #246: fixed type of parameter 'Deviation' in functions iBands, iBandsOnArray (MT4) 2025-10-07 17:03:02 +03:00
Viacheslav Demydiuk b5309fb9a4 Merge branch 'dev' 2025-10-06 23:27:30 +03:00
Viacheslav Demydiuk 2f0ccae238 MQL5: fixed warnings of compiling json.mqh 2025-10-06 23:26:48 +03:00
Viacheslav Demydiuk 371c14b4b7 Merge branch 'dev' 2025-10-06 12:08:02 +03:00
Viacheslav Demydiuk 565735c3c5 MtService: fixed crash on disconnect last expert in MT terminal 2025-10-06 12:07:41 +03:00
Viacheslav Demydiuk 1bb9c7b418 Merge branch 'dev' 2025-10-05 20:59:00 +03:00
Viacheslav Demydiuk 7b5f740a77 MtApi5: added fleld 'Flags' into MqlTick 2025-10-05 20:58:24 +03:00
Viacheslav Demydiuk 22b0f695c6 Merge branch 'dev' 2025-09-30 16:28:30 +03:00
Viacheslav Demydiuk c536585cd2 Issue #284: MtApi5/MQL5 - added function GetSymbols 2025-09-30 16:14:13 +03:00
Viacheslav Demydiuk 29ce645975 Merge branch 'dev' 2025-09-27 17:33:41 +03:00
Viacheslav Demydiuk 92322e866e Issue #284: MtApi4/MQL4 - added function GetSymbols 2025-09-27 17:29:00 +03:00
Viacheslav Demydiuk 34072905d2 Merge branch 'dev' 2025-09-23 12:01:52 +03:00
Viacheslav Demydiuk 96674d8763 MQL5: fixed parsing arguments of function iCustom 2025-09-23 11:31:43 +03:00
Viacheslav Demydiuk 5808756113 MQL4: fixed parsing arguments of function iCustom 2025-09-23 11:26:58 +03:00
Viacheslav Demydiuk fe8ac339b6 MtApi5: set version to 2.0.1 2025-07-28 23:29:01 +03:00
Viacheslav Demydiuk 972df57028 Merge branch 'master' into dev 2025-07-28 23:20:33 +03:00
Viacheslav Demydiuk 6c1cb92f1b MtApi5: fixed typo in function iStochastic 2025-07-28 23:12:21 +03:00
Viacheslav Demydiuk ff871e5e06 MtApi5: implement function iFractals instead of mistake function iForce 2025-07-28 22:57:46 +03:00
Viacheslav Demydiuk c7b8956c99 MtApi5: fixed typo in function iChaikin 2025-07-28 22:51:35 +03:00
Viacheslav Demydiuk db3db18391 MQL5: fixed typo in function iSAR 2025-07-28 22:37:15 +03:00
Viacheslav Demydiuk 143cc33c60 MtApi5: fix type in function iStochastic 2025-07-28 22:34:28 +03:00
Viacheslav Demydiuk 541fc2364b MQL5: don't use EMPTY_VALUE as initial value for times 2025-07-25 17:52:06 +03:00
Viacheslav Demydiuk 78b4b7039b MQL5: changed MQL5_DLLS_ALLOWED to MQL_DLLS_ALLOWED 2025-07-25 17:49:30 +03:00
Viacheslav Demydiuk 4a61ab079c MQL5: fixed parameter in function iChaikin 2025-07-25 17:43:07 +03:00
Viacheslav Demydiuk 69d98b66b3 MtApi5: updated paramter's names in function iCustom 2025-07-25 17:11:55 +03:00
29 changed files with 2323 additions and 1928 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ namespace MtApi.Monitors
{
//get closed orders from history with actual values
var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY) ?? [];
closedOrders = closeOrdersTemp.Where(cot => historyOrders.Find(a => a.Ticket == cot.Ticket) != null).ToList();
closedOrders = historyOrders.Where(cot => closeOrdersTemp.Find(a => a.Ticket == cot.Ticket) != null).ToList();
}
}
+8 -2
View File
@@ -502,6 +502,12 @@ namespace MtApi
Dictionary<string, object> cmdParams = new() { { "Pool", (int)pool} };
return SendCommand<List<MtOrder>>(ExecutorHandle, MtCommandType.GetOrders, cmdParams);
}
public List<string>? GetSymbols(bool selected)
{
Dictionary<string, object> cmdParams = new() { { "Selected", selected } };
return SendCommand<List<string>>(ExecutorHandle, MtCommandType.GetSymbols, cmdParams);
}
#endregion
#region Checkup
@@ -1131,7 +1137,7 @@ namespace MtApi
return SendCommand<double>(ExecutorHandle, MtCommandType.iBearsPower, cmdParams);
}
public double iBands(string symbol, int timeframe, int period, int deviation, int bandsShift, int appliedPrice, int mode, int shift)
public double iBands(string symbol, int timeframe, int period, double deviation, int bandsShift, int appliedPrice, int mode, int shift)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol },
{ "Timeframe", timeframe }, { "Period", period },
@@ -1141,7 +1147,7 @@ namespace MtApi
return SendCommand<double>(ExecutorHandle, MtCommandType.iBands, cmdParams);
}
public double iBandsOnArray(double[] array, int total, int period, int deviation, int bandsShift, int mode, int shift)
public double iBandsOnArray(double[] array, int total, int period, double deviation, int bandsShift, int mode, int shift)
{
Dictionary<string, object> cmdParams = new() { { "Total", total },
{ "Period", period }, { "Deviation", deviation },
+2 -1
View File
@@ -287,6 +287,7 @@
SymbolInfoTick = 288,
SymbolInfoDouble = 289,
GetQuote = 290
GetQuote = 290,
GetSymbols = 291
}
}
+8
View File
@@ -5,12 +5,18 @@ namespace MtApi5
public class MqlTick
{
public MqlTick(DateTime time, double bid, double ask, double last, ulong volume)
: this(time, bid, ask, last, volume, 0)
{
}
public MqlTick(DateTime time, double bid, double ask, double last, ulong volume, ENUM_TICK_FLAGS flags)
{
MtTime = Mt5TimeConverter.ConvertToMtTime(time);
this.bid = bid;
this.ask = ask;
this.last = last;
this.volume = volume;
this.flags = flags;
}
public MqlTick()
@@ -27,6 +33,7 @@ namespace MtApi5
last = tick.Last;
volume = tick.Volume;
volume_real = tick.VolumeReal;
flags = (ENUM_TICK_FLAGS)tick.Flags;
}
}
@@ -37,6 +44,7 @@ namespace MtApi5
public double last { get; set; } // Price of the last deal (Last)
public ulong volume { get; set; } // Volume for the current Last price
public double volume_real { get; set; } // Volume for the current Last price with greater accuracy
public ENUM_TICK_FLAGS flags { get; set; } // Tick flags (used for analyzing to find out what data have been changed)
public DateTime time => Mt5TimeConverter.ConvertFromMtTime(MtTime);
}
+12
View File
@@ -862,6 +862,18 @@ namespace MtApi5
STO_CLOSECLOSE = 1 //Calculation is based on Close/Close prices
}
[Flags]
public enum ENUM_TICK_FLAGS
{
TICK_FLAG_NONE = 0,
TICK_FLAG_BID = 2, // Tick has changed a Bid price
TICK_FLAG_ASK = 4, // Tick has changed an Ask price
TICK_FLAG_LAST = 8, // Tick has changed the last deal price
TICK_FLAG_VOLUME = 16, // Tick has changed a volume
TICK_FLAG_BUY = 32, // Tick is a result of a buy deal
TICK_FLAG_SELL = 64 // Tick is a result of a sell deal
}
#endregion //Price Constants
#region Smoothing Methods
+3 -1
View File
@@ -4,15 +4,17 @@ namespace MtApi5
{
public class Mt5TimeBarArgs: EventArgs
{
internal Mt5TimeBarArgs(int expertHandle, string symbol, MqlRates rates)
internal Mt5TimeBarArgs(int expertHandle, string symbol, ENUM_TIMEFRAMES timeframe, MqlRates rates)
{
ExpertHandle = expertHandle;
Rates = rates;
Symbol = symbol;
Timeframe = timeframe;
}
public int ExpertHandle { get; }
public string Symbol { get; }
public ENUM_TIMEFRAMES Timeframe { get; }
public MqlRates Rates { get; }
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<VersionPrefix>2.0.0</VersionPrefix>
<VersionPrefix>2.0.1</VersionPrefix>
<BaseOutputPath>$(SolutionDir)build\products</BaseOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
+68 -35
View File
@@ -2,6 +2,7 @@
using MtClient;
using MtApi5.MtProtocol;
using MtApi5.MtProtocol.ICustomRequest;
using System.Data;
namespace MtApi5
{
@@ -31,11 +32,24 @@ namespace MtApi5
private HashSet<int> _experts = [];
private Dictionary<int, Mt5Quote> _quotes = [];
private volatile int _command_timeout = 30000; // 30 seconds
#endregion
#region Public Methods
private IMtLogger Log { get; }
// Time in milliseconds to wait for a response from MetaTrader for a command. Default is 30 seconds.
public int CommandTimeout
{
get => _command_timeout;
set
{
if (value <= 0)
throw new ArgumentException("Command timeout must be greater than zero.");
_command_timeout = value;
}
}
public MtApi5Client(IMtLogger? log = null)
{
_mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent;
@@ -122,14 +136,7 @@ namespace MtApi5
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
}
// Load quotes
Dictionary<int, Mt5Quote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(client, handle);
if (quote != null)
quotes[handle] = quote;
}
var quotes = LoadQuotes(client, experts);
lock (_locker)
{
@@ -159,6 +166,18 @@ namespace MtApi5
}
}
private Dictionary<int, Mt5Quote> LoadQuotes(MtRpcClient client, HashSet<int> experts)
{
Dictionary<int, Mt5Quote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(client, handle);
if (quote != null)
quotes[handle] = quote;
}
return quotes;
}
///<summary>
///Disconnect from MetaTrader API. Async method.
///</summary>
@@ -182,10 +201,31 @@ namespace MtApi5
///</summary>
public IEnumerable<Mt5Quote> GetQuotes()
{
MtRpcClient? client;
HashSet<int> experts;
lock (_locker)
{
return _quotes.Values.ToList();
client = _client;
experts = new HashSet<int>(_experts);
}
if (client == null)
{
Log.Warn("GetQuotes: No connection");
throw new Exception("No connection");
}
var quotes = LoadQuotes(client, experts);
return quotes.Values.ToList();
}
///<summary>
///Load symbols
///</summary>
public List<string>? GetSymbols(bool selected)
{
Dictionary<string, object> cmdParams = new() { { "Selected", selected } };
return SendCommand<List<string>>(ExecutorHandle, Mt5CommandType.GetSymbols, cmdParams);
}
///<summary>
@@ -2664,7 +2704,7 @@ namespace MtApi5
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
{ "FastMaPeriod", fastMaPeriod }, { "SlowMaPeriod", slowMaPeriod},
{ "MaMethod", (int)maMethod }, { "appliedVolume", (int)appliedVolume } };
{ "MaMethod", (int)maMethod }, { "AppliedVolume", (int)appliedVolume } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iChaikin, cmdParams);
}
@@ -2730,14 +2770,14 @@ namespace MtApi5
}
///<summary>
///The function returns the handle of the Force Index indicator.
///The function returns the handle of the Fractals indicator.
///</summary>
///<param name="symbol">The symbol name of the security, the data of which should be used to calculate the indicator.</param>
///<param name="period">The value of the period can be one of the ENUM_TIMEFRAMES enumeration values, 0 means the current timeframe.</param>
public int iForce(string symbol, ENUM_TIMEFRAMES period)
public int iFractals(string symbol, ENUM_TIMEFRAMES period)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iForce, cmdParams);
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iFractals, cmdParams);
}
///<summary>
@@ -2969,7 +3009,7 @@ namespace MtApi5
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
{ "Kperiod", Kperiod }, { "Dperiod", Dperiod }, { "Slowing", slowing },
{ "MaMethod", (int)maMethod }, { "priceField", (int)priceField } };
{ "MaMethod", (int)maMethod }, { "PriceField", (int)priceField } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iStochastic, cmdParams);
}
@@ -3055,8 +3095,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, double[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty},
{ "Parameters", parameters }, { "ParamsType", ParametersType.Double} };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty},
{ "Params", parameters }, { "ParamsType", ParametersType.Double} };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3070,8 +3110,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, int[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty }, { "Parameters", parameters },
{ "ParamsType", ParametersType.Int } };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty }, { "Parameters", parameters },
{ "Params", ParametersType.Int } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3085,8 +3125,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, string[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty },
{ "Parameters", parameters }, { "ParamsType", ParametersType.String } };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
{ "Params", parameters }, { "ParamsType", ParametersType.String } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3100,8 +3140,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, bool[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty },
{ "Parameters", parameters }, { "ParamsType", ParametersType.Boolean } };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
{ "Params", parameters }, { "ParamsType", ParametersType.Boolean } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3392,11 +3432,6 @@ namespace MtApi5
var quote = GetQuote(Client, handle);
if (quote != null)
{
lock (_locker)
{
_quotes[handle] = quote;
}
QuoteAdded?.Invoke(this, new Mt5QuoteEventArgs(quote));
}
else
@@ -3411,19 +3446,18 @@ namespace MtApi5
{
Log.Debug($"ProcessExpertRemoved: {handle}");
Mt5Quote? quote = null;
Mt5Quote? quote;
lock (_locker)
{
_experts.Remove(handle);
if (_quotes.TryGetValue(handle, out quote))
_quotes.TryGetValue(handle, out quote);
_quotes.Remove(handle);
_experts.Remove(handle);
if (_executorHandle == handle)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
}
if (quote != null)
QuoteRemoved?.Invoke(this, new Mt5QuoteEventArgs(quote));
QuoteRemoved?.Invoke(this, new Mt5QuoteEventArgs(new Mt5Quote { Instrument = quote.Instrument, ExpertHandle = quote.ExpertHandle }));
}
private Mt5Quote? GetQuote(MtRpcClient? client, int expertHandle)
@@ -3512,7 +3546,7 @@ namespace MtApi5
var e = JsonConvert.DeserializeObject<OnLastTimeBarEvent>(payload);
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Rates == null)
return;
OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandle, e.Instrument, e.Rates));
OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandle, e.Instrument, e.Timeframe, e.Rates));
}
private void ReceivedOnLockTicksEvent(int expertHandle, string payload)
@@ -3540,7 +3574,6 @@ namespace MtApi5
client = _client;
_client = null;
_quotes.Clear();
_experts.Clear();
_executorHandle = 0;
}
@@ -3568,7 +3601,7 @@ namespace MtApi5
var payloadJson = payload == null ? string.Empty : JsonConvert.SerializeObject(payload);
Log.Debug($"SendCommand: sending '{payloadJson}' ...");
var responseJson = client.SendCommand(expertHandle, (int)commandType, payloadJson);
var responseJson = client.SendCommand(expertHandle, (int)commandType, payloadJson, CommandTimeout);
Log.Debug($"SendCommand: received response JSON [{responseJson}]");
+1
View File
@@ -8,5 +8,6 @@
public double Last { get; set; } // Price of the last deal (Last)
public ulong Volume { get; set; } // Volume for the current Last price
public double VolumeReal { get; set; } // Volume for the current Last price with greater accuracy
public uint Flags { get; set; } // Tick flags
}
}
+2 -1
View File
@@ -259,6 +259,7 @@ namespace MtApi5.MtProtocol
OrderSendAsync = 302,
OrderCheck = 303,
Buy = 304,
Sell = 305
Sell = 305,
GetSymbols = 306
}
}
+1
View File
@@ -4,6 +4,7 @@
{
public MqlRates? Rates { get; set; }
public string? Instrument { get; set; }
public ENUM_TIMEFRAMES Timeframe { get; set; }
public int ExpertHandle { get; set; }
}
}
+7 -7
View File
@@ -8,12 +8,12 @@
ExpertList = 3,
ExpertAdded = 4,
ExpertRemoved = 5,
Notification = 6
ServiceRequest = 6
}
internal enum MtNotificationType
internal enum ServiceRequestType
{
ClientReady = 0
ExpertList = 0
}
internal abstract class MtMessage
@@ -43,16 +43,16 @@
}
}
internal class MtNotification(MtNotificationType notificationType) : MtMessage
internal class MtServiceRequest(ServiceRequestType requestType) : MtMessage
{
public override MessageType MsgType => MessageType.Notification;
public override MessageType MsgType => MessageType.ServiceRequest;
protected override string GetMessageBody()
{
return $"{(int)NotificationType}";
return $"{(int)ServiceRequestType}";
}
public MtNotificationType NotificationType { private set; get; } = notificationType;
public ServiceRequestType ServiceRequestType { private set; get; } = requestType;
}
internal class MtEvent(int expertHandle, int eventType, string payload) : MtMessage
+13 -13
View File
@@ -65,7 +65,7 @@ namespace MtClient
logger_.Debug($"MtRpcClient.Disconnect: success");
}
public string? SendCommand(int expertHandle, int commandType, string payload)
public string? SendCommand(int expertHandle, int commandType, string payload, int timeout = 10000) // 10 sec
{
CommandTask<string> commandTask = new();
int commandId;
@@ -78,7 +78,7 @@ namespace MtClient
MtCommand command = new(expertHandle, commandType, commandId, payload);
Send(command);
var response = commandTask.WaitResponse(10000); // 10 sec
var response = commandTask.WaitResponse(timeout);
lock (tasks_)
{
tasks_.Remove(commandId);
@@ -89,19 +89,19 @@ namespace MtClient
public HashSet<int>? RequestExpertsList()
{
CommandTask<object> notificationTask = new();
lock (notification_tasks_)
CommandTask<object> requestTask = new();
lock (service_requests_)
{
notification_tasks_[MtNotificationType.ClientReady] = notificationTask;
service_requests_[ServiceRequestType.ExpertList] = requestTask;
}
MtNotification notification = new(MtNotificationType.ClientReady);
Send(notification);
MtServiceRequest request = new(ServiceRequestType.ExpertList);
Send(request);
var response = notificationTask.WaitResponse(10000); // 10 sec
lock (notification_tasks_)
var response = requestTask.WaitResponse(10000); // 10 sec
lock (service_requests_)
{
notification_tasks_.Remove(MtNotificationType.ClientReady);
service_requests_.Remove(ServiceRequestType.ExpertList);
}
return response as HashSet<int>;
@@ -277,9 +277,9 @@ namespace MtClient
{
logger_.Debug($"MtRpcClient.ProcessExpertList: experts count - {experts.Count}");
lock (notification_tasks_)
lock (service_requests_)
{
if (notification_tasks_.TryGetValue(MtNotificationType.ClientReady, out CommandTask<object>? value))
if (service_requests_.TryGetValue(ServiceRequestType.ExpertList, out CommandTask<object>? value))
value.SetResponse(experts);
}
}
@@ -301,7 +301,7 @@ namespace MtClient
private int nextCommandId = 0;
private readonly Dictionary<int, CommandTask<string>> tasks_ = [];
private readonly Dictionary<MtNotificationType, CommandTask<object>> notification_tasks_ = [];
private readonly Dictionary<ServiceRequestType, CommandTask<object>> service_requests_ = [];
private readonly IRpcLogger logger_;
}
+6
View File
@@ -107,6 +107,12 @@ void MtConnection::OnRead(
return;
}
if (ec == boost::asio::error::eof)
{
log_.Info("%s: %s. Remote peer gracefully closes the connection.", __FUNCTION__, ec.message().c_str());
return;
}
if (ec)
{
log_.Error("%s: %s", __FUNCTION__, ec.message().c_str());
-1
View File
@@ -44,6 +44,5 @@ private:
std::string host_;
std::string read_text_;
boost::beast::flat_buffer read_buffer_;
//std::string send_text_;
std::queue<std::string> send_queue_;
};
+6 -6
View File
@@ -38,7 +38,7 @@ std::unique_ptr<MtCommand> MtCommand::Parse(const std::string& msg)
return command;
}
std::unique_ptr<MtNotification> MtNotification::Parse(const std::string& msg)
std::unique_ptr<MtServiceRequest> MtServiceRequest::Parse(const std::string& msg)
{
std::string::size_type pos = msg.find(';');
@@ -47,17 +47,17 @@ std::unique_ptr<MtNotification> MtNotification::Parse(const std::string& msg)
using rule = qi::rule<std::string::const_iterator>;
std::string message_type;
std::string notification_type;
std::string request_type;
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
rule message_type_p = word_p[boost::phoenix::ref(message_type) = qi::_1];
rule notification_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(notification_type) = qi::_1];
rule notification_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(request_type) = qi::_1];
std::unique_ptr<MtNotification> command;
std::unique_ptr<MtServiceRequest> request;
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -notification_type_p);
if (ok)
command = std::make_unique<MtNotification>((NotificationType)std::stoi(notification_type));
request = std::make_unique<MtServiceRequest>((ServiceRequestType)std::stoi(request_type));
return command;
return request;
}
+11 -11
View File
@@ -14,12 +14,12 @@ enum MessageType
EXPERT_LIST = 3,
EXPERT_ADDED = 4,
EXPERT_REMOVED = 5,
NOTIFICATION = 6
SERVICE_REQUEST = 6
};
enum NotificationType
enum ServiceRequestType
{
CLIENT_READY = 0
EXPERTS = 0
};
class MtMessage
@@ -111,25 +111,25 @@ private:
std::string payload_;
};
class MtNotification : public MtMessage
class MtServiceRequest : public MtMessage
{
public:
MtNotification(NotificationType type)
: notification_type_(type)
MtServiceRequest(ServiceRequestType type)
: request_type_(type)
{
}
NotificationType GetNotificationType() const
ServiceRequestType GetServiceRequestType() const
{
return notification_type_;
return request_type_;
}
static std::unique_ptr<MtNotification> Parse(const std::string& msg);
static std::unique_ptr<MtServiceRequest> Parse(const std::string& msg);
private:
MessageType GetType() const override
{
return MessageType::NOTIFICATION;
return MessageType::SERVICE_REQUEST;
}
std::string GetBody() const override
@@ -137,7 +137,7 @@ private:
return "";
}
NotificationType notification_type_;
ServiceRequestType request_type_;
};
class MtEvent : public MtMessage
+5 -5
View File
@@ -288,12 +288,12 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
else
log_.Warning("%s: Failed to parse command from message: %s", __FUNCTION__, msg.c_str());
}
else if (msg_type == MessageType::NOTIFICATION)
else if (msg_type == MessageType::SERVICE_REQUEST)
{
auto notification = MtNotification::Parse(msg);
if (notification)
auto request = MtServiceRequest::Parse(msg);
if (request)
{
if (notification->GetNotificationType() == NotificationType::CLIENT_READY)
if (request->GetServiceRequestType() == ServiceRequestType::EXPERTS)
{
std::vector<int> expert_list;
for (const auto& e : experts_)
@@ -306,7 +306,7 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
}
}
else
log_.Warning("%s: Failed to parse notification from message: %s", __FUNCTION__, msg.c_str());
log_.Warning("%s: Failed to parse service request from message: %s", __FUNCTION__, msg.c_str());
}
else
{
+21 -1
View File
@@ -166,6 +166,8 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Quotes" Background="LightYellow" />
<ListView Grid.Row="1" Margin="2"
@@ -181,6 +183,12 @@
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="2" Content="Refresh Quotes" Margin="2" Command="{Binding RefreshQuotesCommand}"/>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Left" Margin="2">
<TextBlock Text="Command timeout (ms):" VerticalAlignment="Center" Margin="2"/>
<TextBox Text="{Binding CommandTimeout}" Width="100" Margin="2"/>
<Button Content="Apply" Margin="2" Command="{Binding TimeoutApplyCommand}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
@@ -473,7 +481,13 @@
</TabItem>
<TabItem Header="Market Info">
<WrapPanel VerticalAlignment="Top" Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" VerticalAlignment="Top" Margin="5">
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
<Button Command="{Binding SymbolSelectCommand}" Content="SymbolSelect" Margin="2"/>
@@ -489,6 +503,12 @@
<Button Command="{Binding MarketBookReleaseCommand}" Content="MarketBookRelease" Margin="2"/>
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
</WrapPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="GetSymbols" Command="{Binding GetSymbolsCommand}" Width="100" Margin="2"/>
<CheckBox Content="Selected" IsChecked="{Binding GetSymbolsSelected}" Margin="5" />
</StackPanel>
<ListBox Grid.Row="2" ItemsSource="{Binding Symbols}" Height="Auto" Width="200" HorizontalAlignment="Left"/>
</Grid>
</TabItem>
<TabItem Header="CTrade (Positions)">
+71 -2
View File
@@ -160,6 +160,11 @@ namespace MtApi5TestClient
public DelegateCommand GlobalVariablesTotalCommand { get; private set; }
public DelegateCommand UnlockTicksCommand { get; private set; }
public DelegateCommand GetSymbolsCommand { get; private set; }
public DelegateCommand RefreshQuotesCommand { get; private set; }
public DelegateCommand TimeoutApplyCommand { get; private set; }
#endregion
#region Properties
@@ -207,6 +212,17 @@ namespace MtApi5TestClient
}
}
private int _command_timeout;
public int CommandTimeout
{
get { return _command_timeout; }
set
{
_command_timeout = value;
OnPropertyChanged("CommandTimeout");
}
}
public ObservableCollection<QuoteViewModel> Quotes { get; } = new ObservableCollection<QuoteViewModel>();
private QuoteViewModel _selectedQuote;
@@ -314,6 +330,19 @@ namespace MtApi5TestClient
OnPropertyChanged("PositionTicketValue");
}
}
public bool GetSymbolsSelected { get; set; } = false;
private List<string> _symbols;
public List<string> Symbols
{
get { return _symbols; }
set
{
_symbols = value;
OnPropertyChanged("Symbols");
}
}
#endregion
#region Public Methods
@@ -334,6 +363,7 @@ namespace MtApi5TestClient
ConnectionState = _mtApiClient.ConnectionState;
ConnectionMessage = "Disconnected";
Port = 8228; //default local port
CommandTimeout = _mtApiClient.CommandTimeout;
InitCommands();
@@ -475,6 +505,11 @@ namespace MtApi5TestClient
GlobalVariablesTotalCommand = new DelegateCommand(ExecuteGlobalVariablesTotal);
UnlockTicksCommand = new DelegateCommand(ExecuteUnlockTicks);
GetSymbolsCommand = new DelegateCommand(ExecuteGetSymbols);
RefreshQuotesCommand = new DelegateCommand(ExecuteRefreshQuotes);
TimeoutApplyCommand = new DelegateCommand(ExecuteTimeoutApply);
}
private bool CanExecuteConnect(object o)
@@ -1054,7 +1089,7 @@ namespace MtApi5TestClient
{
foreach (var v in result)
{
var tickStr = $"time = {v.time}, bid = {v.bid}, ask = {v.ask}, last = {v.last}, volume = {v.volume}";
var tickStr = $"time = {v.time}, bid = {v.bid}, ask = {v.ask}, last = {v.last}, volume = {v.volume}, flags = {v.flags}";
TimeSeriesResults.Add(tickStr);
}
});
@@ -1142,6 +1177,7 @@ namespace MtApi5TestClient
AddLog($"SymbolInfoTick(EURUSD) tick.last = {result.last}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume = {result.volume}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume_real = {result.volume_real}");
AddLog($"SymbolInfoTick(EURUSD) tick.flags = {result.flags}");
}
private async void ExecuteSymbolInfoSessionQuote(object o)
@@ -1726,6 +1762,39 @@ namespace MtApi5TestClient
_mtApiClient.UnlockTicks();
}
private async void ExecuteGetSymbols(object o)
{
var result = await Execute(() => _mtApiClient.GetSymbols(GetSymbolsSelected));
if (result == null)
return;
AddLog($"ChartScreenShot: {result.Count} count of symbols");
RunOnUiThread(() =>
{
Symbols = result;
});
}
private async void ExecuteRefreshQuotes(object o)
{
_quotesMap.Clear();
Quotes.Clear();
var quotes = await Execute(() => _mtApiClient.GetQuotes());
if (quotes != null)
{
foreach (var quote in quotes)
{
AddQuote(quote);
}
}
}
private void ExecuteTimeoutApply(object o)
{
_mtApiClient.CommandTimeout = CommandTimeout;
AddLog($"TimeoutApply: timeout = {CommandTimeout} milliseconds");
}
private static void RunOnUiThread(Action action)
{
Application.Current?.Dispatcher.Invoke(action);
@@ -1804,7 +1873,7 @@ namespace MtApi5TestClient
private void _mtApiClient_OnLastTimeBar(object sender, Mt5TimeBarArgs e)
{
AddLog($"OnLastTimeBarEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
AddLog($"OnLastTimeBarEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, Timeframe = {e.Timeframe}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
}
private void _mtApiClient_OnLockTicks(object sender, Mt5LockTicksEventArgs e)
File diff suppressed because it is too large Load Diff
+18 -39
View File
@@ -1,45 +1,10 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using MtApi;
using MtApi;
using MtApi.Monitors;
using System.Globalization;
using System.Runtime.InteropServices;
namespace TestApiClientUI
{
class MtLogger : IMtLogger
{
public void Debug(object message)
{
Write("DEBUG", message);
}
public void Error(object message)
{
Write("ERROR", message);
}
public void Fatal(object message)
{
Write("FATAL", message);
}
public void Info(object message)
{
Write("INFO", message);
}
public void Warn(object message)
{
Write("WARN", message);
}
private void Write(string level, object message)
{
Console.WriteLine($"[{Environment.CurrentManagedThreadId}] [{level}] {message}");
}
}
public partial class Form1 : Form
{
#region Fields
@@ -1120,12 +1085,12 @@ namespace TestApiClientUI
{
if (e.Opened != null)
{
PrintLog($"{sender.GetType()}: Opened orders - {string.Join(", ", e.Opened.Select(o => o.Ticket).ToList())}");
PrintLog($"{sender.GetType()}: Opened orders - {string.Join(", ", e.Opened.Select(o => new { o.Ticket, o.Symbol, o.OpenPrice, o.OpenTime }).ToList())}");
}
if (e.Closed != null)
{
PrintLog($"{sender.GetType()}: Closed orders - {string.Join(", ", e.Closed.Select(o => o.Ticket).ToList())}");
PrintLog($"{sender.GetType()}: Closed orders - {string.Join(", ", e.Closed.Select(o => new { o.Ticket, o.Symbol, o.ClosePrice, o.CloseTime }).ToList())}");
}
}
@@ -1544,5 +1509,19 @@ namespace TestApiClientUI
PrintLog($"iBarShift result1 = {result1}, time = {time1}");
PrintLog($"iBarShift result2 = {result2}, time = {time2}");
}
private async void button74_Click(object sender, EventArgs e)
{
listBoxAllSymbols.Items.Clear();
var result = await Execute(() => _apiClient.GetSymbols(checkBox3.Checked));
if (result != null)
{
foreach (string? r in result)
listBoxAllSymbols.Items.Add(r);
}
int count = result != null ? result.Count : 0;
PrintLog($"GetSymbols: {count}");
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using MtApi;
namespace TestApiClientUI
{
class MtLogger : IMtLogger
{
public void Debug(object message)
{
Write("DEBUG", message);
}
public void Error(object message)
{
Write("ERROR", message);
}
public void Fatal(object message)
{
Write("FATAL", message);
}
public void Info(object message)
{
Write("INFO", message);
}
public void Warn(object message)
{
Write("WARN", message);
}
private void Write(string level, object message)
{
Console.WriteLine($"[{Environment.CurrentManagedThreadId}] [{level}] {message}");
}
}
}
BIN
View File
Binary file not shown.
+48 -10
View File
@@ -1330,6 +1330,9 @@ int ExecuteCommand()
case 290: //GetQuote
response = Execute_GetQuote();
break;
case 291: //GetSymbols
response = Execute_GetSymbols();
break;
default:
Print("WARNING: Unknown command type = ", command_type);
@@ -2269,7 +2272,7 @@ string Execute_iBands()
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
GET_INT_JSON_VALUE(jo, "Timeframe", timeframe);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "Deviation", deviation);
GET_DOUBLE_JSON_VALUE(jo, "Deviation", deviation);
GET_INT_JSON_VALUE(jo, "BandsShift", bands_shift);
GET_INT_JSON_VALUE(jo, "AppliedPrice", applied_price);
GET_INT_JSON_VALUE(jo, "Mode", mode);
@@ -2284,7 +2287,7 @@ string Execute_iBandsOnArray()
GET_JSON_PAYLOAD(jo);
GET_INT_JSON_VALUE(jo, "Total", total);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "Deviation", deviation);
GET_DOUBLE_JSON_VALUE(jo, "Deviation", deviation);
GET_INT_JSON_VALUE(jo, "BandsShift", bands_shift);
GET_INT_JSON_VALUE(jo, "Mode", mode);
GET_INT_JSON_VALUE(jo, "Shift", shift);
@@ -3793,15 +3796,24 @@ bool OrderCloseAll()
if (OrderSelect(i, SELECT_BY_POS))
{
int type = OrderType();
bool order_closed = true;
switch(type)
{
//Close opened long positions
case OP_BUY: OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
break;
//Close opened short positions
case OP_SELL: OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red );
case OP_BUY:
{
order_closed = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
break;
}
//Close opened short positions
case OP_SELL:
{
order_closed = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red );
break;
}
}
if (order_closed == false)
Print("Failed to close order ", OrderTicket());
}
}
@@ -3961,10 +3973,8 @@ string Execute_iCustom()
{
int intParams[];
ArrayResize(intParams, size);
for (int i = 0; i < size; i++)
{
intParams[i] = jaParams.getInt(i);
}
for (int it_i = 0; it_i < size; it_i++)
intParams[it_i] = jaParams.getInt(it_i);
result = iCustomT(symbol, timeframe, name, intParams, size, mode, shift);
}
break;
@@ -3972,6 +3982,8 @@ string Execute_iCustom()
{
double doubleParams[];
ArrayResize(doubleParams, size);
for (int it_d = 0; it_d < size; it_d++)
doubleParams[it_d] = jaParams.getDouble(it_d);
result = iCustomT(symbol, timeframe, name, doubleParams, size, mode, shift);
}
break;
@@ -3979,6 +3991,8 @@ string Execute_iCustom()
{
string stringParams[];
ArrayResize(stringParams, size);
for (int it_s = 0; it_s < size; it_s++)
stringParams[it_s] = jaParams.getString(it_s);
result = iCustomT(symbol, timeframe, name, stringParams, size, mode, shift);
}
break;
@@ -3986,6 +4000,8 @@ string Execute_iCustom()
{
bool boolParams[];
ArrayResize(boolParams, size);
for (int it_b = 0; it_b < size; it_b++)
boolParams[it_b] = jaParams.getBool(it_b);
result = iCustomT(symbol, timeframe, name, boolParams, size, mode, shift);
}
break;
@@ -4183,3 +4199,25 @@ string Execute_GetQuote()
MtQuote quote(Symbol(), tick);
return CreateSuccessResponse(quote.CreateJson());
}
string Execute_GetSymbols()
{
GET_JSON_PAYLOAD(jo);
GET_BOOL_JSON_VALUE(jo, "Selected", selected);
const int symbolsCount = SymbolsTotal(selected);
JSONArray* jaSymbols = new JSONArray();
int idx = 0;
for(int idxSymbol = 0; idxSymbol < symbolsCount; idxSymbol++)
{
string symbol = SymbolName(idxSymbol, selected);
string firstChar = StringSubstr(symbol, 0, 1);
if(firstChar != "#" && StringLen(symbol) == 6)
{
jaSymbols.put(idx, new JSONString(symbol));
idx++;
}
}
return CreateSuccessResponse(jaSymbols);
}
Regular → Executable
BIN
View File
Binary file not shown.
+60 -13
View File
@@ -1,7 +1,7 @@
#property copyright "Vyacheslav Demidyuk"
#property link ""
#property version "2.0"
#property version "2.1"
#property description "MtApi (MT5) connection expert"
#include <json.mqh>
@@ -82,7 +82,7 @@ void OnTick()
MqlRates rates_array[];
CopyRates(symbol, Period(), 1, 1, rates_array);
MtTimeBarEvent time_bar(symbol, rates_array[0]);
MtTimeBarEvent time_bar(symbol, (int)Period(), rates_array[0]);
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
}
lastbar_time_changed = true;
@@ -380,6 +380,7 @@ int preinit()
ADD_EXECUTOR(303, OrderCheck);
ADD_EXECUTOR(304, Buy);
ADD_EXECUTOR(305, Sell);
ADD_EXECUTOR(306, GetSymbols);
return (0);
}
@@ -408,14 +409,14 @@ int init()
isCrashed = true;
return (1);
}
if (MQL5InfoInteger(MQL5_DLLS_ALLOWED) == false)
if (MQLInfoInteger(MQL_DLLS_ALLOWED) == false)
{
MessageBox("Libraries not allowed.", "MtApi", 0);
isCrashed = true;
return (1);
}
if (MQL5InfoInteger(MQL5_TRADE_ALLOWED) == false)
if (MQLInfoInteger(MQL_TRADE_ALLOWED) == false)
{
MessageBox("Trade not allowed.", "MtApi", 0);
isCrashed = true;
@@ -1829,7 +1830,7 @@ string Execute_ObjectCreate()
datetime times[30];
double prices[30];
ArrayInitialize(times, EMPTY_VALUE);
ArrayInitialize(times, 0);
ArrayInitialize(prices, EMPTY_VALUE);
JSONArray* times_jo = jo.p.getArray("Times");
@@ -2168,10 +2169,10 @@ string Execute_iChaikin()
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "FastMaPeriod", fast_ma_period);
GET_INT_JSON_VALUE(jo, "SlowMaPeriod", slow_ma_period);
GET_INT_JSON_VALUE(jo, "MaPeriod", ma_period);
GET_INT_JSON_VALUE(jo, "MaMethod", ma_method);
GET_INT_JSON_VALUE(jo, "AppliedVolume", applied_volume);
int result = iChaikin(symbol, (ENUM_TIMEFRAMES)period, fast_ma_period, slow_ma_period, (ENUM_MA_METHOD)ma_period, (ENUM_APPLIED_VOLUME) applied_volume);
int result = iChaikin(symbol, (ENUM_TIMEFRAMES)period, fast_ma_period, slow_ma_period, (ENUM_MA_METHOD)ma_method, (ENUM_APPLIED_VOLUME) applied_volume);
return CreateSuccessResponse(new JSONNumber(result));
}
@@ -2377,7 +2378,7 @@ string Execute_iSAR()
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_DOUBLE_JSON_VALUE(jo, "Step", step);
GET_DOUBLE_JSON_VALUE(jo, "Mamimum", maximum);
GET_DOUBLE_JSON_VALUE(jo, "Maximum", maximum);
int result = iSAR(symbol, (ENUM_TIMEFRAMES)period, step, maximum);
return CreateSuccessResponse(new JSONNumber(result));
@@ -2959,6 +2960,7 @@ string Execute_UnlockTicks()
return CreateErrorResponse(-1, "UnlockTicks can be used only for backtesting");
}
_is_ticks_locked = false;
return CreateSuccessResponse();
}
@@ -3065,15 +3067,15 @@ string Execute_iCustom()
int intParams[];
ArrayResize(intParams, size);
for (int i = 0; i < size; i++)
{
intParams[i] = jaParams.getInt(i);
}
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, intParams, size);
}
break;
case 1: //Double
{
int doubleParams[];
double doubleParams[];
for (int i = 0; i < size; i++)
doubleParams[i] = jaParams.getDouble(i);
ArrayResize(doubleParams, size);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, doubleParams, size);
}
@@ -3082,13 +3084,17 @@ string Execute_iCustom()
{
string stringParams[];
ArrayResize(stringParams, size);
for (int i = 0; i < size; i++)
stringParams[i] = jaParams.getString(i);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, stringParams, size);
}
break;
case 3: //Boolean
{
string boolParams[];
bool boolParams[];
ArrayResize(boolParams, size);
for (int i = 0; i < size; i++)
boolParams[i] = jaParams.getBool(i);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, boolParams, size);
}
break;
@@ -3446,6 +3452,28 @@ string Execute_Sell()
return CreateSuccessResponse(result_value_jo);
}
string Execute_GetSymbols()
{
GET_JSON_PAYLOAD(jo);
GET_BOOL_JSON_VALUE(jo, "Selected", selected);
const int symbolsCount = SymbolsTotal(selected);
JSONArray* jaSymbols = new JSONArray();
int idx = 0;
for(int idxSymbol = 0; idxSymbol < symbolsCount; idxSymbol++)
{
string symbol = SymbolName(idxSymbol, selected);
string firstChar = StringSubstr(symbol, 0, 1);
if(firstChar != "#" && StringLen(symbol) == 6)
{
jaSymbols.put(idx, new JSONString(symbol));
idx++;
}
}
return CreateSuccessResponse(jaSymbols);
}
int PositionCloseAll()
{
CTrade trade;
@@ -3635,9 +3663,10 @@ private:
class MtTimeBarEvent: public MtObject
{
public:
MtTimeBarEvent(string symbol, const MqlRates& rates)
MtTimeBarEvent(string symbol, int timeframe, const MqlRates& rates)
{
_symbol = symbol;
_timeframe = timeframe;
_rates = rates;
}
@@ -3646,12 +3675,14 @@ public:
JSONObject *jo = new JSONObject();
jo.put("Rates", MqlRatesToJson(_rates));
jo.put("Instrument", new JSONString(_symbol));
jo.put("Timeframe", new JSONNumber(_timeframe));
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
return jo;
}
private:
string _symbol;
int _timeframe;
MqlRates _rates;
};
@@ -3774,6 +3805,21 @@ bool JsonToMqlTradeRequest(JSONObject *jo, MqlTradeRequest& request)
JSONObject* MqlTickToJson(const MqlTick& tick)
{
// MT5 can add some additional non-documented flags, so we need to filter required documented flags only
int summ=0;
if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID)
summ+=TICK_FLAG_BID;
if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK)
summ+=TICK_FLAG_ASK;
if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST)
summ+=TICK_FLAG_LAST;
if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME)
summ+=TICK_FLAG_VOLUME;
if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY)
summ+=TICK_FLAG_BUY;
if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL)
summ+=TICK_FLAG_SELL;
JSONObject *jo = new JSONObject();
jo.put("Time", new JSONNumber((long)tick.time));
jo.put("Bid", new JSONNumber(tick.bid));
@@ -3781,6 +3827,7 @@ JSONObject* MqlTickToJson(const MqlTick& tick)
jo.put("Last", new JSONNumber(tick.last));
jo.put("Volume", new JSONNumber(tick.volume));
jo.put("VolumeReal", new JSONNumber(tick.volume_real));
jo.put("Flags", new JSONNumber(summ));
return jo;
}
+10 -10
View File
@@ -324,27 +324,27 @@ public:
/// Lookup key and get associated string value, return false if failure.
bool getString(string key,string &out)
{
return getString(getValue(key),out);
return JSONValue::getString(getValue(key),out);
}
/// Lookup key and get associated bool value, return false if failure.
bool getBool(string key,bool &out)
{
return getBool(getValue(key),out);
return JSONValue::getBool(getValue(key),out);
}
/// Lookup key and get associated double value, return false if failure.
bool getDouble(string key,double &out)
{
return getDouble(getValue(key),out);
return JSONValue::getDouble(getValue(key),out);
}
/// Lookup key and get associated long value, return false if failure.
bool getLong(string key,long &out)
{
return getLong(getValue(key),out);
return JSONValue::getLong(getValue(key),out);
}
/// Lookup key and get associated int value, return false if failure.
bool getInt(string key,int &out)
{
return getInt(getValue(key),out);
return JSONValue::getInt(getValue(key),out);
}
/// Lookup key and get associated array, NULL if not present. Cast failure if not an Array.
@@ -451,27 +451,27 @@ public:
/// Lookup JSONString by array index. NULL if not present. Cast failure if not an Object.
bool getString(int index,string &out)
{
return getString(getValue(index),out);
return JSONValue::getString(getValue(index),out);
}
/// Lookup JSONBool by array index. NULL if not present. Cast failure if not an Object.
bool getBool(int index,bool &out)
{
return getBool(getValue(index),out);
return JSONValue::getBool(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getDouble(int index,double &out)
{
return getDouble(getValue(index),out);
return JSONValue::getDouble(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getLong(int index,long &out)
{
return getLong(getValue(index),out);
return JSONValue::getLong(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getInt(int index,int &out)
{
return getInt(getValue(index),out);
return JSONValue::getInt(getValue(index),out);
}
/// Lookup array child by index, NULL if not present. Cast failure if not an Array.