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
35 changed files with 2323 additions and 4547 deletions
-3
View File
@@ -188,6 +188,3 @@ UpgradeLog*.htm
# Microsoft Fakes
FakesAssemblies/
# Python cache
__pycache__/
+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)
{
_quotes.TryGetValue(handle, out quote);
_quotes.Remove(handle);
_experts.Remove(handle);
if (_quotes.TryGetValue(handle, out quote))
_quotes.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
{
-609
View File
@@ -1,609 +0,0 @@
import logging
import os
import os.path
import signal
import sys
import time
from functools import partial
from threading import Thread
import mt5enums
from mt5apiclient import Mt5ApiClient
logger = logging.getLogger(__name__)
def signal_handler(mtapi, _, __):
del __
if mtapi.is_connected():
mtapi.disconnect()
class Mt5ApiApp:
def __init__(self, address, port):
self.__address = address
self.__port = port
self.cmd_functions = {
"AccountInfoDouble": self.process_account_info_double,
"AccountInfoInteger": self.process_account_info_integer,
"AccountInfoString": self.process_account_info_string,
"SeriesInfoInteger": self.process_series_info_integer,
"Bars": self.process_bars,
"BarsPeriod": self.process_bars_period,
"BarsCalculated": self.process_bars_calculated,
"IndicatorCreate": self.process_indicator_create,
"IndicatorRelease": self.process_indicator_release,
"SymbolsTotal": self.process_symbols_total,
"SymbolName": self.process_symbol_name,
"SymbolSelect": self.process_symbol_select,
"SymbolIsSynchronized": self.process_symbol_is_synchronized,
"SymbolInfoDouble": self.process_symbol_info_double,
"SymbolInfoInteger": self.process_symbol_info_integer,
"SymbolInfoString": self.process_symbol_info_string,
"SymbolInfoTick": self.process_symbol_info_tick,
"SymbolInfoSessionQuote": self.process_symbol_info_session_quote,
"SymbolInfoSessionTrade": self.process_symbol_info_session_trade,
"MarketBookAdd": self.process_market_book_add,
"MarketBookRelease": self.process_market_book_release,
"MarketBookGet": self.process_market_book_get,
"CopyBuffer": self.process_copy_buffer,
"CopyRates": self.process_copy_rates,
"CopyTime": self.process_copy_time,
"CopyOpen": self.process_copy_open,
"CopyHigh": self.process_copy_high,
"CopyLow": self.process_copy_low,
"CopyClose": self.process_copy_close,
"CopyTickVolume": self.process_copy_tick_volume,
"CopyRealVolume": self.process_copy_real_volume,
"CopySpread": self.process_copy_spread,
"CopyTicks": self.process_copy_ticks,
"ChartId": self.process_chart_id,
"ChartRedraw": self.process_chart_redraw,
"ChartApplyTemplate": self.process_chart_apply_template,
"ChartSaveTemplate": self.process_chart_save_template,
"ChartWindowFind": self.process_chart_window_find,
"ChartTimePriceToXY": self.process_chart_time_price_to_xy,
"ChartXYToTimePrice": self.process_chart_xy_to_time_price,
"ChartOpen": self.process_chart_open,
"ChartFirst": self.process_chart_first,
"ChartNext": self.process_chart_next,
"ChartClose": self.process_chart_close,
"ChartSymbol": self.process_chart_symbol,
"ChartPeriod": self.process_chart_period,
"ChartSetDouble": self.process_chart_set_double,
"ChartSetInteger": self.process_chart_set_integer,
"ChartSetString": self.process_chart_set_string,
"ChartGetDouble": self.process_chart_get_double,
"ChartGetInteger": self.process_chart_get_integer,
}
def on_disconnect(self, error_msg=None):
if error_msg is not None:
print(f"> Disconnected with error: {error_msg}")
else:
print("> Normal disconnected")
os.kill(os.getpid(), signal.SIGINT)
def on_quote_update(self, quote):
print(f"> update quote: {quote}")
def on_quote_added(self, quote):
print(f"> added quote: {quote}")
def on_quote_removed(self, quote):
print(f"> removed quote: {quote}")
def on_book_event(self, expert_handle, symbol):
print(f"> received book event: {expert_handle} - {symbol}")
def on_last_time_bar(self, expert_handle, instrument, rates):
print(f"> received last time bar event: {expert_handle} - {instrument}, {rates}")
def on_trade_transaction(self, expert_handle, trade_transaction, trade_request, trade_result):
print(
f"> received trade transaction event: {expert_handle} - {trade_transaction}, {trade_request}, {trade_result}"
)
def process_command(self, mtapi, command):
pieces = command.split(" ", 1)
if len(pieces) == 0 or len(pieces) > 2:
print(f"! Invalid command format: {command.rstrip()}")
return
command_name = pieces[0].rstrip()
if command_name not in self.cmd_functions:
print(f"! Unknown command: '{command_name}'")
return
if len(pieces) == 1:
pieces.append("")
params = pieces[1].rstrip()
try:
self.cmd_functions[command_name](mtapi, params)
except Exception as e:
print(f"Failed to process command {command.rstrip()}: {e}")
def process_account_info_double(self, mtapi, parameters):
property_id = mt5enums.ENUM_ACCOUNT_INFO_DOUBLE(int(parameters))
result = mtapi.account_info_double(property_id)
print(f"> AccountInfoDouble {property_id}: result = {result}")
def process_account_info_integer(self, mtapi, parameters):
property_id = mt5enums.ENUM_ACCOUNT_INFO_INTEGER(int(parameters))
value = mtapi.account_info_integer(property_id)
print(f"> AccountInfoInteger {property_id}: response = {value}")
def process_account_info_string(self, mtapi, parameters):
property_id = mt5enums.ENUM_ACCOUNT_INFO_STRING(int(parameters))
result = mtapi.account_info_string(property_id)
print(f"> AccountInfoString {property_id}: result = {result}")
def process_series_info_integer(self, mtpapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command SeriesInfoInteger: {parameters}")
return
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
prop_id = mt5enums.ENUM_SERIES_INFO_INTEGER(int(pieces[2]))
result = mtpapi.series_info_integer(pieces[0], timeframe, prop_id)
print(f"> SeriesInfoInteger: result = {result}")
def process_bars(self, mtpapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command Bars: {parameters}")
return
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
result = mtpapi.bars(pieces[0], timeframe)
print(f"> Bars: result = {result}")
def process_bars_period(self, mtpapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command BarsPeriod: {parameters}")
return
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_time = int(pieces[2])
stop_time = int(pieces[3])
result = mtpapi.bars_period(pieces[0], timeframe, start_time, stop_time)
print(f"> Bars: result = {result}")
def process_bars_calculated(self, mtpapi, parameters):
if not parameters:
print(f"! Invalid parameters for command BarsCalculated: {parameters}")
return
indicator_handle = int(parameters)
result = mtpapi.bars_calculated(indicator_handle)
print(f"> BarsCalculated: result = {result}")
def process_indicator_create(self, mtpapi, parameters):
pieces = parameters.split(" ")
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command IndicatorCreate: {parameters}")
return
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
indicator_type = mt5enums.ENUM_INDICATOR(int(pieces[2]))
result = mtpapi.indicator_create(pieces[0], timeframe, indicator_type)
print(f"> IndicatorCreate: result = {result}")
def process_indicator_release(self, mtpapi, parameters):
if not parameters:
print(f"! Invalid parameters for command IndicatorRelease: {parameters}")
return
indicator_handle = int(parameters)
result = mtpapi.indicator_release(indicator_handle)
print(f"> IndicatorRelease: response = {result}")
def process_symbols_total(self, mtpapi, parameters):
if not parameters or len(parameters) == 0:
print(f"! Invalid parameters for command SymbolsTotal: {parameters}")
return
selected = parameters == "True"
result = mtpapi.symbols_total(selected)
print(f"> SymbolsTotal: response = {result}")
def process_symbol_name(self, mtpapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1] or len(pieces[1]) == 0:
print(f"! Invalid parameters for command SymbolName: {parameters}")
return
pos = int(pieces[0])
selected = pieces[1] == "True"
result = mtpapi.symbol_name(pos, selected)
print(f"> SymbolName: response = {result}")
def process_symbol_select(self, mtpapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1] or len(pieces[1]) == 0:
print(f"! Invalid parameters for command SymbolSelect: {parameters}")
return
selected = pieces[1] == "True"
result = mtpapi.symbol_select(pieces[0], selected)
print(f"> SymbolSelect: response = {result}")
def process_symbol_is_synchronized(self, mtpapi, parameters):
if not parameters or len(parameters) == 0:
print(f"! Invalid parameters for command SymbolIsSynchronized: {parameters}")
return
symbol = parameters
result = mtpapi.symbol_is_synchronized(symbol)
print(f"> SymbolIsSynchronized: response = {result}")
def process_symbol_info_double(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command SymbolInfoDouble: {parameters}")
return
symbol = pieces[0]
prop_id = mt5enums.ENUM_SYMBOL_INFO_DOUBLE(int(pieces[1]))
result = mtapi.symbol_info_double(symbol, prop_id)
print(f"> SymbolInfoDouble: response = {result}")
def process_symbol_info_integer(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command SymbolInfoInteger: {parameters}")
return
symbol = pieces[0]
prop_id = mt5enums.ENUM_SYMBOL_INFO_INTEGER(int(pieces[1]))
result = mtapi.symbol_info_integer(symbol, prop_id)
print(f"> SymbolInfoInteger: response = {result}")
def process_symbol_info_string(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command SymbolInfoString: {parameters}")
return
symbol = pieces[0]
prop_id = mt5enums.ENUM_SYMBOL_INFO_STRING(int(pieces[1]))
result = mtapi.symbol_info_string(symbol, prop_id)
print(f"> SymbolInfoString: response = {result}")
def process_symbol_info_tick(self, mtapi, parameters):
if len(parameters) == 0:
print(f"! Invalid parameters for command SymbolInfoTick: {parameters} - {len(parameters)}")
return
symbol = parameters
result = mtapi.symbol_info_tick(symbol)
print(f"> SymbolInfoTick: response = {result}")
def process_symbol_info_session_quote(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command SymbolInfoSessionQuote: {parameters}")
return
symbol = pieces[0]
day_of_week = mt5enums.ENUM_DAY_OF_WEEK(int(pieces[1]))
session_index = int(pieces[2])
result = mtapi.symbol_info_session_quote(symbol, day_of_week, session_index)
print(f"> SymbolInfoSessionQuote: response = {result}")
def process_symbol_info_session_trade(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command SymbolInfoSessionTrade: {parameters}")
return
symbol = pieces[0]
day_of_week = mt5enums.ENUM_DAY_OF_WEEK(int(pieces[1]))
session_index = int(pieces[2])
result = mtapi.symbol_info_session_trade(symbol, day_of_week, session_index)
print(f"> SymbolInfoSessionTrade: response = {result}")
def process_market_book_add(self, mtapi, parameters):
if len(parameters) == 0:
print(f"! Invalid parameters for command MarketBookAdd: {parameters} - {len(parameters)}")
return
symbol = parameters
result = mtapi.market_book_add(symbol)
print(f"> MarketBookAdd: response = {result}")
def process_market_book_release(self, mtapi, parameters):
if len(parameters) == 0:
print(f"! Invalid parameters for command MarketBookRelease: {parameters} - {len(parameters)}")
return
symbol = parameters
result = mtapi.market_book_release(symbol)
print(f"> MarketBookRelease: response = {result}")
def process_market_book_get(self, mtapi, parameters):
if len(parameters) == 0:
print(f"! Invalid parameters for command MarketBookGet: {parameters} - {len(parameters)}")
return
symbol = parameters
result = mtapi.market_book_get(symbol)
print(f"> MarketBookGet: response = {result}")
def process_copy_buffer(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyBuffer: {parameters}")
return
indicator_handle = int(pieces[0])
buffer_num = int(pieces[1])
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_buffer(indicator_handle, buffer_num, start_pos, count)
print(f"> CopyBuffer: response = {result}")
def process_copy_rates(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyRates: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_rates(symbol_name, timeframe, start_pos, count)
print(f"> CopyRates: response = {result}")
def process_copy_time(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyTime: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_time(symbol_name, timeframe, start_pos, count)
print(f"> CopyTime: response = {result}")
def process_copy_open(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyOpen: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_open(symbol_name, timeframe, start_pos, count)
print(f"> CopyOpen: response = {result}")
def process_copy_high(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyHigh: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_high(symbol_name, timeframe, start_pos, count)
print(f"> CopyHigh: response = {result}")
def process_copy_low(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyLow: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_low(symbol_name, timeframe, start_pos, count)
print(f"> CopyLow: response = {result}")
def process_copy_close(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyClose: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_close(symbol_name, timeframe, start_pos, count)
print(f"> CopyClose: response = {result}")
def process_copy_tick_volume(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyTickVolume: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_tick_volume(symbol_name, timeframe, start_pos, count)
print(f"> CopyTickVolume: response = {result}")
def process_copy_real_volume(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyRealVolume: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_real_volume(symbol_name, timeframe, start_pos, count)
print(f"> CopyRealVolume: response = {result}")
def process_copy_spread(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopySpread: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
start_pos = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_spread(symbol_name, timeframe, start_pos, count)
print(f"> CopySpread: response = {result}")
def process_copy_ticks(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command CopyTicks: {parameters}")
return
symbol_name = pieces[0]
timeframe = mt5enums.CopyTicksFlag(int(pieces[1]))
from_date = int(pieces[2])
count = int(pieces[3])
result = mtapi.copy_ticks(symbol_name, timeframe, from_date, count)
print(f"> CopyTicks: response = {result}")
def process_chart_id(self, mtapi, parameters):
result = mtapi.chart_id(int(parameters))
print(f"> ChatId: response = {result}")
def process_chart_redraw(self, mtapi, parameters):
mtapi.chart_redraw(int(parameters))
print(f"> ChartRedraw: success")
def process_chart_apply_template(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command ChartApplyTemplate: {parameters}")
return
result = mtapi.chart_apply_template(int(pieces[0]), pieces[1])
print(f"> ChartApplyTemplate: response = {result}")
def process_chart_save_template(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command ChartSaveTemplate: {parameters}")
return
result = mtapi.chart_save_template(int(pieces[0]), pieces[1])
print(f"> ChartSaveTemplate: response = {result}")
def process_chart_window_find(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command ChartWindowFind: {parameters}")
return
result = mtapi.chart_window_find(int(pieces[0]), pieces[1])
print(f"> ChartWindowFind: response = {result}")
def process_chart_time_price_to_xy(self, mtapi, parameters):
pieces = parameters.split(" ", 3)
if len(pieces) != 4 or not pieces[0] or not pieces[1] or not pieces[2] or not pieces[3]:
print(f"! Invalid parameters for command ChartTimePriceToXY: {parameters}")
return
result = mtapi.chart_time_price_to_xy(int(pieces[0]), int(pieces[1]), int(pieces[2]), float(pieces[3]))
print(f"> ChartTimePriceToXY: response = {result}")
def process_chart_xy_to_time_price(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartXYToTimePrice: {parameters}")
return
result = mtapi.chart_xy_to_time_price(int(pieces[0]), int(pieces[1]), int(pieces[2]))
print(f"> ChartXYToTimePrice: response = {result}")
def process_chart_open(self, mtapi, parameters):
pieces = parameters.split(" ", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
print(f"! Invalid parameters for command ChartOpen: {parameters}")
return
period = mt5enums.ENUM_TIMEFRAMES(int(pieces[1]))
result = mtapi.chart_open(pieces[0], period)
print(f"> ChartOpen: response = {result}")
def process_chart_first(self, mtapi, _):
result = mtapi.chart_first()
print(f"> ChartFirst: response = {result}")
def process_chart_next(self, mtapi, parameters):
result = mtapi.chart_next(int(parameters))
print(f"> ChartNext: response = {result}")
def process_chart_close(self, mtapi, parameters):
result = mtapi.chart_close(int(parameters))
print(f"> ChartClose: response = {result}")
def process_chart_symbol(self, mtapi, parameters):
result = mtapi.chart_symbol(int(parameters))
print(f"> ChartSymbol: response = {result}")
def process_chart_period(self, mtapi, parameters):
result = mtapi.chart_period(int(parameters))
print(f"> ChartPeriod: response = {result}")
def process_chart_set_double(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartSetDouble: {parameters}")
return
prop_id = mt5enums.ENUM_CHART_PROPERTY_DOUBLE(int(pieces[1]))
result = mtapi.chart_set_double(int(pieces[0]), prop_id, float(pieces[2]))
print(f"> ChartSetDouble: response = {result}")
def process_chart_set_integer(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartSetInteger: {parameters}")
return
prop_id = mt5enums.ENUM_CHART_PROPERTY_INTEGER(int(pieces[1]))
result = mtapi.chart_set_integer(int(pieces[0]), prop_id, int(pieces[2]))
print(f"> ChartSetInteger: response = {result}")
def process_chart_set_string(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartSetString: {parameters}")
return
prop_id = mt5enums.ENUM_CHART_PROPERTY_STRING(int(pieces[1]))
result = mtapi.chart_set_string(int(pieces[0]), prop_id, pieces[2])
print(f"> ChartSetString: response = {result}")
def process_chart_get_double(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartGetDouble: {parameters}")
return
prop_id = mt5enums.ENUM_CHART_PROPERTY_DOUBLE(int(pieces[1]))
result = mtapi.chart_get_double(int(pieces[0]), prop_id, int(pieces[2]))
print(f"> ChartGetDouble: response = {result}")
def process_chart_get_integer(self, mtapi, parameters):
pieces = parameters.split(" ", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
print(f"! Invalid parameters for command ChartGetInteger: {parameters}")
return
prop_id = mt5enums.ENUM_CHART_PROPERTY_INTEGER(int(pieces[1]))
result = mtapi.chart_get_integer(int(pieces[0]), prop_id, int(pieces[2]))
print(f"> ChartGetInteger: response = {result}")
def mtapi_command_thread(self, mtapi):
while mtapi.is_connected():
filename = "client.cmd"
if os.path.isfile(filename):
f = open("client.cmd", "r")
command = f.read()
f.close()
os.remove(filename)
self.process_command(mtapi, command)
time.sleep(0.5)
def run(self):
with Mt5ApiClient(self.__address, self.__port, self) as mtapi:
print(f"> Connected to {self.__address}:{self.__port}")
signal.signal(signal.SIGINT, partial(signal_handler, mtapi))
quotes = mtapi.get_quotes()
print(f"> quotes: {quotes}")
command_thread = Thread(target=self.mtapi_command_thread, args=(mtapi,))
command_thread.start()
while mtapi.is_connected():
signal.pause()
command_thread.join()
def main():
logging.basicConfig(filename="client.log", filemode="w", level=logging.DEBUG)
logger.info("Started")
args_num = len(sys.argv)
if args_num != 3:
print("Incorrect arguments. For using input:\n\tclient <address> <port>")
exit(1)
address = sys.argv[1]
port = int(sys.argv[2])
app = Mt5ApiApp(address, port)
app.run()
if __name__ == "__main__":
main()
-685
View File
@@ -1,685 +0,0 @@
import asyncio
import json
import logging
from enum import IntEnum
from threading import Lock, Thread
from mt5commandtype import Mt5CommandType
from mt5enums import *
from mtrpcclient import MtRpcClient
class Mt5EventType(IntEnum):
OnTradeTransaction = 1
OnBookEvent = 2
OnTick = 3
OnLastTimeBar = 4
OnLockTicks = 5
class Mt5Quote:
def __init__(self, quote_json):
self.instrument = quote_json["Instrument"]
self.expert_handle = quote_json["ExpertHandle"]
self.bid = quote_json["Tick"]["Bid"]
self.ask = quote_json["Tick"]["Ask"]
self.volume = quote_json["Tick"]["Volume"]
def __repr__(self):
return f"{self.expert_handle}-{self.instrument}: Bid = {self.bid}, Ask = {self.ask}, Volume = {self.volume}"
class MqlTick:
def __init__(self, tick_json):
self.bid = tick_json["Bid"]
self.ask = tick_json["Ask"]
self.last = tick_json["Last"]
self.volume = tick_json["Volume"]
self.time = tick_json["Time"]
def __repr__(self):
return f"Bid = {self.bid}, Ask = {self.ask}, Last = {self.last}, Volume = {self.volume}, Time = {self.time}"
class MqlRates:
def __init__(self, mql_rates_json):
self.time = mql_rates_json["mt_time"]
self.open = mql_rates_json["open"]
self.high = mql_rates_json["high"]
self.low = mql_rates_json["low"]
self.close = mql_rates_json["close"]
self.tick_volume = mql_rates_json["tick_volume"]
self.spread = mql_rates_json["spread"]
self.real_volume = mql_rates_json["real_volume"]
def __repr__(self):
return f"time = {self.time}, open = {self.open}, high = {self.high}, low = {self.low}, close = {self.close}, tick_volume = {self.tick_volume}, spread = {self.spread}, real_volume = {self.real_volume}"
class MqlTradeTransaction:
def __init__(self, mql_trade_transaction_json):
self.deal = mql_trade_transaction_json["Deal"]
self.order = mql_trade_transaction_json["Order"]
self.symbol = mql_trade_transaction_json["Symbol"]
self.transaction_type = mql_trade_transaction_json["Type"]
self.order_type = mql_trade_transaction_json["OrderType"]
self.order_state = mql_trade_transaction_json["OrderState"]
self.deal_type = mql_trade_transaction_json["DealType"]
self.time_type = mql_trade_transaction_json["TimeType"]
self.price = mql_trade_transaction_json["Price"]
self.price_trigger = mql_trade_transaction_json["PriceTrigger"]
self.price_sl = mql_trade_transaction_json["PriceSl"]
self.price_tp = mql_trade_transaction_json["PriceTp"]
self.volume = mql_trade_transaction_json["Volume"]
self.position = mql_trade_transaction_json["Position"]
self.position_by = mql_trade_transaction_json["PositionBy"]
self.time_expiration = mql_trade_transaction_json["MtTimeExpiration"]
def __repr__(self):
return (
f"deal = {self.deal}, order = {self.order}, symbol = {self.symbol}, transaction_type = {self.transaction_type}, "
f"order_type = {self.order_type}, order_state = {self.order_state}, deal_type = {self.deal_type}, time_type = {self.time_type}, "
f"price = {self.price}, price_trigger = {self.price_trigger}, price_sl = {self.price_sl}, price_tp = {self.price_tp}, volume = {self.volume}, "
f"position = {self.position}, position_by = {self.position_by}, time_expiration = {self.time_expiration}"
)
class MqlTradeRequest:
def __init__(self, mql_trade_request_json):
self.action = mql_trade_request_json["Action"]
self.magic = mql_trade_request_json["Magic"]
self.order = mql_trade_request_json["Order"]
self.symbol = mql_trade_request_json["Symbol"]
self.volume = mql_trade_request_json["Volume"]
self.price = mql_trade_request_json["Price"]
self.stop_limit = mql_trade_request_json["Stoplimit"]
self.sl = mql_trade_request_json["Sl"]
self.tp = mql_trade_request_json["Tp"]
self.deviation = mql_trade_request_json["Deviation"]
self.order_type = mql_trade_request_json["Type"]
self.type_filling = mql_trade_request_json["Type_filling"]
self.type_time = mql_trade_request_json["Type_time"]
self.expiration = mql_trade_request_json["MtExpiration"]
self.comment = mql_trade_request_json["Comment"]
# self.position = mql_trade_request_json["Position"]
# self.position_by = mql_trade_request_json["PositionBy"]
def __repr__(self):
return (
f"action = {self.action}, magic = {self.magic}, order = {self.order}, symbol = {self.symbol}, volume = {self.volume}, "
f"price = {self.price}, stop_limit = {self.stop_limit}, sl = {self.sl}, tp = {self.tp}, deviation = {self.deviation}, "
f"order_type = {self.order_type}, type_filling = {self.type_filling}, type_time = {self.type_time}, expiration = {self.expiration}, "
f"comment = {self.comment}"
)
class MqlTradeResult:
def __init__(self, mql_trade_result_json):
self.retcode = mql_trade_result_json["Retcode"]
self.deal = mql_trade_result_json["Deal"]
self.order = mql_trade_result_json["Order"]
self.volume = mql_trade_result_json["Volume"]
self.price = mql_trade_result_json["Price"]
self.bid = mql_trade_result_json["Bid"]
self.ask = mql_trade_result_json["Ask"]
self.comment = mql_trade_result_json["Comment"]
self.request_id = mql_trade_result_json["Request_id"]
def __repr__(self):
return (
f"retcode = {self.retcode}, deal = {self.deal}, order = {self.order}, volume = {self.volume}, price = {self.price}, "
f"bid = {self.bid}, ask = {self.ask}, comment = {self.comment}, request_id = {self.request_id}"
)
class MqlBookInfo:
def __init__(self, mql_book_info):
self.book_type = ENUM_BOOK_TYPE(mql_book_info["type"])
self.price = mql_book_info["price"]
self.volume = mql_book_info["volume"]
self.volume_real = mql_book_info["volume_real"]
def __repr__(self):
return f"book_type = {self.book_type}, price = {self.price}, volume = {self.volume}, volume_real = {self.volume_real}"
class Mt5ApiClient:
def __init__(self, address, port, callback=None):
self.__address = address
self.__port = port
self.__callback = callback
self.__logger = logging.getLogger(__name__)
self.__rpcclient = MtRpcClient(self)
self.__is_connected = False
self.__quotes = dict()
self.__experts = list()
self.__lock = Lock()
def __enter__(self):
self.connect()
return self
def __exit__(self, *_):
self.disconnect()
def connect(self):
self.__logger.info(f"Connecting to {self.__address}:{self.__port}")
url = f"ws://{self.__address}:{self.__port}"
self.__rpcclient.connect(url)
experts = self.__rpcclient.request_expert_list()
if experts is None:
self.__rpcclient.disconnect()
raise Exception("Failed to load expert list")
self.__logger.info(f"loaded exerts {self.__experts}")
for expert_handle in experts:
quote = self.__get_quote(expert_handle)
if quote is not None:
self.__experts.append(expert_handle)
self.__quotes[expert_handle] = quote
self.__logger.info(f"loaded quotes {self.__quotes}")
# TODO: send backtesting ready
self.__event_loop = asyncio.new_event_loop()
self.__event_thread = Thread(target=self.__event_thread_func)
self.__event_thread.start()
self.__is_connected = True
def disconnect(self):
self.__rpcclient.disconnect()
self.__event_loop.call_soon_threadsafe(self.__event_loop.stop)
self.__event_thread.join()
self.__quotes.clear()
self.__experts.clear()
def is_connected(self):
with self.__lock:
return self.__is_connected
def get_quotes(self):
with self.__lock:
return list(self.__quotes.values())
def is_testing(self):
return False
# Account Information functions
# AccountInfoDouble
def account_info_double(self, property_id: ENUM_ACCOUNT_INFO_DOUBLE):
cmd_params = {"PropertyId": property_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoDouble, cmd_params)
# AccountInfoInteger
def account_info_integer(self, property_id: ENUM_ACCOUNT_INFO_INTEGER):
cmd_params = {"PropertyId": property_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoInteger, cmd_params)
# AccountInfoString
def account_info_string(self, property_id: ENUM_ACCOUNT_INFO_STRING):
cmd_params = {"PropertyId": property_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoString, cmd_params)
# Timeseries and Indicators Access
# SeriesInfoInteger
def series_info_integer(self, symbol_name, timeframe: ENUM_TIMEFRAMES, prop_id: ENUM_SERIES_INFO_INTEGER):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "PropId": prop_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SeriesInfoInteger, cmd_params)
# Bars
def bars(self, symbol_name, timeframe: ENUM_TIMEFRAMES):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars, cmd_params)
# Bars (for a specified period)
def bars_period(self, symbol_name, timeframe: ENUM_TIMEFRAMES, start_time: int, stop_time: int):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "StartTime": start_time, "StopTime": stop_time}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars2, cmd_params)
# BarsCalculated
def bars_calculated(self, indicator_handle: int):
cmd_params = {"IndicatorHandle": indicator_handle}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.BarsCalculated, cmd_params)
# CopyBuffer
def copy_buffer(self, indicator_handle: int, buffer_num: int, start_pos: int, count: int):
cmd_params = {
"IndicatorHandle": indicator_handle,
"BufferNum": buffer_num,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyBuffer, cmd_params)
# CopyRates
def copy_rates(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyRates, cmd_params)
rates = [MqlRates(obj) for obj in res]
return rates
# CopyTime
def copy_time(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyTime, cmd_params)
# CopyOpen
def copy_open(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyOpen, cmd_params)
# CopyHigh
def copy_high(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyHigh, cmd_params)
# CopyLow
def copy_low(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyLow, cmd_params)
# CopyClose
def copy_close(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyClose, cmd_params)
# CopyTickVolume
def copy_tick_volume(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyTickVolume, cmd_params)
# CopyRealVolume
def copy_real_volume(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyRealVolume, cmd_params)
# CopySpread
def copy_spread(self, symbol_name: str, timeframe: ENUM_TIMEFRAMES, start_pos: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Timeframe": timeframe,
"StartPos": start_pos,
"Count": count,
}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.CopySpread, cmd_params)
# CopyTicks
def copy_ticks(self, symbol_name: str, flags: CopyTicksFlag, from_date: int, count: int):
cmd_params = {
"Symbol": symbol_name,
"Flags": flags,
"From": from_date,
"Count": count,
}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.CopyTicks, cmd_params)
if res is None:
return None
ticks = [MqlTick(obj) for obj in res]
return ticks
# IndicatorCreate
def indicator_create(
self, symbol: str, period: ENUM_TIMEFRAMES, indicator_type: ENUM_INDICATOR, parameters: list = []
):
cmd_params = {"Period": period, "IndicatorType": indicator_type}
if symbol is not None:
cmd_params["Symbol"] = symbol
if len(parameters) != 0:
cmd_params["Parameters"] = parameters
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorCreate, cmd_params)
# IndicatorRelease
def indicator_release(self, indicator_handle: int):
cmd_params = {"IndicatorHandle": indicator_handle}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorRelease, cmd_params)
# Market Info
# SymbolsTotal
def symbols_total(self, selected: bool):
cmd_params = {"Selected": selected}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolsTotal, cmd_params)
# SymbolName
def symbol_name(self, pos: int, selected: bool):
cmd_params = {"Pos": pos, "Selected": selected}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolName, cmd_params)
# SymbolSelect
def symbol_select(self, symbol_name: str, selected: bool):
cmd_params = {"Symbol": symbol_name, "Selected": selected}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolSelect, cmd_params)
# SymbolIsSynchronized
def symbol_is_synchronized(self, symbol_name: str):
cmd_params = {"Symbol": symbol_name}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolIsSynchronized, cmd_params)
# SymbolInfoDouble
def symbol_info_double(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_DOUBLE):
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoDouble, cmd_params)
# SymbolInfoInteger
def symbol_info_integer(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_INTEGER):
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoInteger, cmd_params)
# SymbolInfoString
def symbol_info_string(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_STRING):
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoString, cmd_params)
# SymbolInoTick
def symbol_info_tick(self, symbol_name: str):
cmd_params = {"Symbol": symbol_name}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoTick, cmd_params)
if res is not None and res["RetVal"] == True:
return MqlTick(res["Result"])
return None
# SymbolInfoSessionQuote
def symbol_info_session_quote(self, name: str, day_of_week: ENUM_DAY_OF_WEEK, session_index: int):
cmd_params = {"Symbol": name, "DayOfWeek": day_of_week, "SessionIndex": session_index}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoSessionQuote, cmd_params)
if res is not None and res["RetVal"] == True:
return (res["Result"]["From"], res["Result"]["To"])
return None
# SymbolInfoSessionTrade
def symbol_info_session_trade(self, name: str, day_of_week: ENUM_DAY_OF_WEEK, session_index: int):
cmd_params = {"Symbol": name, "DayOfWeek": day_of_week, "SessionIndex": session_index}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoSessionTrade, cmd_params)
if res is not None and res["RetVal"] == True:
return (res["Result"]["From"], res["Result"]["To"])
return None
# MarketBookAdd
def market_book_add(self, symbol: str):
cmd_params = {"Symbol": symbol}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.MarketBookAdd, cmd_params)
# MarketBookRelease
def market_book_release(self, symbol: str):
cmd_params = {"Symbol": symbol}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.MarketBookRelease, cmd_params)
# MarketBookGet
def market_book_get(self, symbol: str):
cmd_params = {"Symbol": symbol}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.MarketBookGet, cmd_params)
# ChartId
def chart_id(self, expert_handle=0):
if expert_handle == 0:
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartId)
else:
return self.__send_command(expert_handle, Mt5CommandType.ChartId)
# ChartRedraw
def chart_redraw(self, chart_id=0):
cmd_params = {"ChartId": chart_id}
self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartRedraw, cmd_params)
# ChartApplyTemplate
def chart_apply_template(self, chart_id, filename: str):
cmd_params = {"ChartId": chart_id, "TemplateFileName": filename}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartApplyTemplate, cmd_params)
# ChartSaveTemplate
def chart_save_template(self, chart_id, filename: str):
cmd_params = {"ChartId": chart_id, "TemplateFileName": filename}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartSaveTemplate, cmd_params)
# ChartWindowFind
def chart_window_find(self, chart_id, indicator_short_name: str):
cmd_params = {"ChartId": chart_id, "IndicatorShortname": indicator_short_name}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartWindowFind, cmd_params)
# ChartTimePriceToXY
def chart_time_price_to_xy(self, chart_id, sub_window, time, price):
cmd_params = {"ChartId": chart_id, "SubWindow": sub_window, "Time": time, "Price": price}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartTimePriceToXY, cmd_params)
if res is not None and res["RetVal"] == True:
return (res["Result"]["X"], res["Result"]["Y"])
return None
# ChartXYToTimePrice
def chart_xy_to_time_price(self, chart_id, x, y):
cmd_params = {"ChartId": chart_id, "X": x, "Y": y}
res = self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartXYToTimePrice, cmd_params)
if res is not None and res["RetVal"] == True:
return (res["Result"]["SubWindow"], res["Result"]["Time"], res["Result"]["Price"])
return None
# ChartOpen
def chart_open(self, symbol: str, period: ENUM_TIMEFRAMES):
cmd_params = {"Symbol": symbol, "Timeframe": period}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartOpen, cmd_params)
# ChartFirst
def chart_first(self):
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartFirst)
# ChartNext
def chart_next(self, chart_id):
cmd_params = {"ChartId": chart_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartNext, cmd_params)
# ChartClose
def chart_close(self, chart_id):
cmd_params = {"ChartId": chart_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartClose, cmd_params)
# ChartSymbol
def chart_symbol(self, chart_id):
cmd_params = {"ChartId": chart_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartSymbol, cmd_params)
# ChartPeriod
def chart_period(self, chart_id):
cmd_params = {"ChartId": chart_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartPeriod, cmd_params)
# ChartSetDouble
def chart_set_double(self, chart_id, prop_id: ENUM_CHART_PROPERTY_DOUBLE, value):
cmd_params = {"ChartId": chart_id, "PropId": prop_id, "Value": value}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartSetDouble, cmd_params)
# ChartSetInteger
def chart_set_integer(self, chart_id, prop_id: ENUM_CHART_PROPERTY_INTEGER, value):
cmd_params = {"ChartId": chart_id, "PropId": prop_id, "Value": value}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartSetInteger, cmd_params)
# ChartSetString
def chart_set_string(self, chart_id, prop_id: ENUM_CHART_PROPERTY_STRING, value):
cmd_params = {"ChartId": chart_id, "PropId": prop_id, "Value": value}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartSetString, cmd_params)
# ChartGetDouble
def chart_get_double(self, chart_id, prop_id: ENUM_CHART_PROPERTY_DOUBLE, sub_window=0):
cmd_params = {"ChartId": chart_id, "PropId": prop_id, "SubWindow": sub_window}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartGetDouble, cmd_params)
# ChartGetInteger
def chart_get_integer(self, chart_id, prop_id: ENUM_CHART_PROPERTY_INTEGER, sub_window=0):
cmd_params = {"ChartId": chart_id, "PropId": prop_id, "SubWindow": sub_window}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.ChartGetInteger, cmd_params)
# Private methods
def __event_thread_func(self):
self.__logger.debug(f"__event_thread started")
asyncio.set_event_loop(self.__event_loop)
self.__event_loop.run_forever()
self.__logger.debug(f"__event_thread stopped")
def __get_quote(self, expert_handle):
response = self.__send_command(expert_handle, Mt5CommandType.GetQuote)
quote = Mt5Quote(response) if response is not None else None
return quote
def __get_default_expert(self):
with self.__lock:
if len(self.__experts) > 0:
return self.__experts[0]
return 0
def __send_command(self, expert_handle, command_type, payload=None):
payload_json = None if payload is None else json.dumps(payload)
response = self.__rpcclient.send_command(expert_handle, command_type, payload_json)
if response is None:
self.__logger.warning("Failed to send commad. Result is None")
raise Exception("Failed to send commad. Result is None")
response_json = json.loads(response)
error_code = int(response_json["ErrorCode"])
if error_code != 0:
error_message = response_json["ErrorMessage"]
self.__logger.warning(f"send_command: ErrorCode = {error_code}. {error_message}")
raise Exception(f"Failed to send command: ErrorCode = {error_code}. {error_message} ")
if "Value" in response_json:
return response_json["Value"]
return None
def __process_tick_event(self, payload):
quote_json = json.loads(payload)
if quote_json is not None:
quote = Mt5Quote(quote_json)
with self.__lock:
self.__quotes[quote.expert_handle] = quote
if self.__callback is not None:
self.__callback.on_quote_update(quote)
def __process_event_disconnect(self, error_msg=None):
with self.__lock:
self.__is_connected = False
if self.__callback is not None:
self.__callback.on_disconnect(error_msg)
def __process_expert_added(self, expert_handle):
quote = self.__get_quote(expert_handle)
if quote is not None:
with self.__lock:
self.__quotes[expert_handle] = quote
self.__experts.append(expert_handle)
if self.__callback is not None:
self.__callback.on_quote_added(quote)
def __process_expert_removed(self, expert_handle):
quote = None
with self.__lock:
self.__experts.remove(expert_handle)
if expert_handle in self.__quotes:
quote = self.__quotes.pop(expert_handle)
if quote is not None and self.__callback is not None:
self.__callback.on_quote_removed(quote)
def __process_on_book_event(self, expert_handle, payload):
book_event_json = json.loads(payload)
if book_event_json is None:
self.__logger.error("Failed to parse book event json")
return
symbol = book_event_json["Symbol"]
if self.__callback is not None:
self.__callback.on_book_event(expert_handle, symbol)
def __process_on_last_time_bar(self, expert_handle, payload):
last_time_bar_event_json = json.loads(payload)
if last_time_bar_event_json is None:
self.__logger.error("Failed to parse last time bar event json")
return
instrument = last_time_bar_event_json["Instrument"]
rates = MqlRates(last_time_bar_event_json["Rates"])
if self.__callback is not None:
self.__callback.on_last_time_bar(expert_handle, instrument, rates)
def __process_on_lock_tick(self, expert_handle, payload):
# TODO: must be implemented
self.__logger.warning(f"event type OnLockTicks is not supported. {expert_handle} - {payload}")
def __process_on_trade_transaction(self, expert_handle, payload):
trade_transaction_json = json.loads(payload)
trade_transaction = MqlTradeTransaction(trade_transaction_json["Trans"])
trade_request = MqlTradeRequest(trade_transaction_json["Request"])
trade_result = MqlTradeResult(trade_transaction_json["Result"])
if self.__callback is not None:
self.__callback.on_trade_transaction(expert_handle, trade_transaction, trade_request, trade_result)
# RPC event handlers
def mt_rpc_on_event(self, expert_handle, event_type, payload):
self.__logger.debug(f"received event from {expert_handle}: {event_type}, {payload}")
mt_event_type = Mt5EventType(int(event_type))
if mt_event_type == Mt5EventType.OnTick:
self.__event_loop.call_soon_threadsafe(self.__process_tick_event, payload)
elif mt_event_type == Mt5EventType.OnBookEvent:
self.__event_loop.call_soon_threadsafe(self.__process_on_book_event, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnLastTimeBar:
self.__event_loop.call_soon_threadsafe(self.__process_on_last_time_bar, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnLockTicks:
self.__event_loop.call_soon_threadsafe(self.__process_on_lock_tick, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnTradeTransaction:
self.__event_loop.call_soon_threadsafe(self.__process_on_trade_transaction, expert_handle, payload)
else:
self.__logger.warning(f"received unsupported event {event_type}")
def mt_rcp_on_disconnect(self):
self.__logger.info("normal disconnected")
self.__event_loop.call_soon_threadsafe(self.__process_event_disconnect)
def mt_rpc_on_connection_failed(self, error_msg=None):
self.__logger.info(f"connection failed: {error_msg}")
self.__event_loop.call_soon_threadsafe(self.__process_event_disconnect, error_msg)
def mt_rpc_on_expert_added(self, expert_handle):
self.__logger.info(f"expert added: {expert_handle}")
self.__event_loop.call_soon_threadsafe(self.__process_expert_added, expert_handle)
def mt_rpc_on_expert_removed(self, expert_handle):
self.__logger.info(f"expert removed: {expert_handle}")
self.__event_loop.call_soon_threadsafe(self.__process_expert_removed, expert_handle)
-254
View File
@@ -1,254 +0,0 @@
from enum import IntEnum
class Mt5CommandType(IntEnum):
# NoCommand = 0
GetQuote = 1
#trade operations
OrderCalcMargin = 2
OrderCalcProfit = 3
PositionsTotal = 6
PositionGetSymbol = 7
PositionSelect = 8
PositionGetDouble = 9
PositionGetInteger = 10
PositionGetString = 11
PositionGetTicket = 4
OrdersTotal = 12
OrderGetTicket = 13
OrderSelect = 14
OrderGetDouble = 15
OrderGetInteger = 16
OrderGetString = 17
HistorySelect = 18
HistorySelectByPosition = 19
HistoryOrderSelect = 20
HistoryOrdersTotal = 21
HistoryOrderGetTicket = 22
HistoryOrderGetDouble = 23
HistoryOrderGetInteger = 24
HistoryOrderGetString = 25
HistoryDealSelect = 26
HistoryDealsTotal = 27
HistoryDealGetTicket = 28
HistoryDealGetDouble = 29
HistoryDealGetInteger = 30
HistoryDealGetString = 31
#Account Information
AccountInfoDouble = 32
AccountInfoInteger = 33
AccountInfoString = 34
#Access to Timeseries and Indicator Data
SeriesInfoInteger = 35
Bars = 36
Bars2 = 1036
BarsCalculated = 37
IndicatorCreate = 38
IndicatorRelease = 39
CopyBuffer = 40
CopyBuffer1 = 1040
CopyBuffer2 = 1140
CopyRates = 41
CopyRates1 = 1041
CopyRates2 = 1141
CopyTime = 42
CopyTime1 = 1042
CopyTime2 = 1142
CopyOpen = 43
CopyOpen1 = 1043
CopyOpen2 = 1143
CopyHigh = 44
CopyHigh1 = 1044
CopyHigh2 = 1144
CopyLow = 45
CopyLow1 = 1045
CopyLow2 = 1145
CopyClose = 46
CopyClose1 = 1046
CopyClose2 = 1146
CopyTickVolume = 47
CopyTickVolume1 = 1047
CopyTickVolume2 = 1147
CopyRealVolume = 48
CopyRealVolume1 = 1048
CopyRealVolume2 = 1148
CopySpread = 49
CopySpread1 = 1049
CopySpread2 = 1149
#Market Information
SymbolsTotal = 50
SymbolName = 51
SymbolSelect = 52
SymbolIsSynchronized = 53
SymbolInfoDouble = 54
SymbolInfoInteger = 55
SymbolInfoString = 56
SymbolInfoString2 = 1056
SymbolInfoTick = 57
SymbolInfoSessionQuote = 58
SymbolInfoSessionTrade = 59
MarketBookAdd = 60
MarketBookRelease = 61
MarketBookGet = 62
OrderCloseAll = 63
#CTrade
PositionClose = 64
PositionOpen = 65
PositionOpen2 = 1065
PositionModify = 6066
PositionClosePartial_bySymbol = 6067
PositionClosePartial_byTicket = 6068
#Backtesting
BacktestingReady = 66
IsTesting = 67
PositionSelectByTicket = 69
ObjectCreate = 70
ObjectName = 71
ObjectDelete = 72
ObjectsDeleteAll = 73
ObjectFind = 74
ObjectGetTimeByValue = 75
ObjectGetValueByTime = 76
ObjectMove = 77
ObjectsTotal = 78
ObjectGetDouble = 79
ObjectGetInteger = 80
ObjectGetString = 81
ObjectSetDouble = 82
ObjectSetInteger = 83
ObjectSetString = 84
iAC = 88
iAD = 89
iADX = 90
iADXWilder = 91
iAlligator = 92
iAMA = 93
iAO = 94
iATR = 95
iBearsPower = 96
iBands = 97
iBullsPower = 98
iCCI = 99
iChaikin = 100
iCustom = 101
iDEMA = 102
iDeMarker = 103
iEnvelopes = 104
iForce = 105
iFractals = 106
iFrAMA = 107
iGator = 108
iIchimoku = 109
iBWMFI = 110
iMomentum = 111
iMFI = 112
iMA = 113
iOsMA = 114
iMACD = 115
iOBV = 116
iSAR = 117
iRSI = 118
iRVI = 119
iStdDev = 120
iStochastic = 121
iTEMA = 122
iTriX = 123
iWPR = 124
iVIDyA = 125
iVolumes = 126
#Date and Time
TimeCurrent = 127
TimeTradeServer = 128
TimeLocal = 129
TimeGMT = 130
#Chart Operations
ChartId = 206
ChartRedraw = 207
ChartApplyTemplate = 236
ChartSaveTemplate = 237
ChartWindowFind = 238
ChartTimePriceToXY = 239
ChartXYToTimePrice = 240
ChartOpen = 241
ChartFirst = 242
ChartNext = 243
ChartClose = 244
ChartSymbol = 245
ChartPeriod = 246
ChartSetDouble = 247
ChartSetInteger = 248
ChartSetString = 249
ChartGetDouble = 250
ChartGetInteger = 251
ChartGetString = 252
ChartNavigate = 253
ChartIndicatorDelete = 254
ChartIndicatorName = 255
ChartIndicatorsTotal = 256
ChartWindowOnDropped = 257
ChartPriceOnDropped = 258
ChartTimeOnDropped = 259
ChartXOnDropped = 260
ChartYOnDropped = 261
ChartSetSymbolPeriod = 262
ChartScreenShot = 263
ChartIndicatorAdd = 280
ChartIndicatorGet = 281
# Terminal Operations
TerminalCompany = 68
TerminalName = 69
TerminalPath = 70
#Checkup
GetLastError = 132
TerminalInfoString = 153
TerminalInfoInteger = 204
TerminalInfoDouble = 205
#Common Functions
Alert = 136
Comment = 137
GetTickCount = 138
GetMicrosecondCount = 139
MessageBox = 140
PeriodSeconds = 141
PlaySound = 142
Print = 68
ResetLastError = 143
SendNotification = 144
SendMail = 145
#Global Variables
GlobalVariableCheck = 146
GlobalVariableTime = 147
GlobalVariableDel = 148
GlobalVariableGet = 149
GlobalVariableName = 150
GlobalVariableSet = 151
GlobalVariablesFlush = 152
GlobalVariableTemp = 154
GlobalVariableSetOnCondition = 156
GlobalVariablesDeleteAll = 157
GlobalVariablesTotal = 158
UnlockTicks = 159
PositionCloseAll = 160
TesterStop = 161
CopyTicks = 300
OrderSend = 301
OrderSendAsync = 302
OrderCheck = 303
Buy = 304
Sell = 305
-901
View File
@@ -1,901 +0,0 @@
from enum import IntEnum
# Chart Timeframes
class ENUM_TIMEFRAMES(IntEnum):
PERIOD_CURRENT = 0
PERIOD_M1 = 1
PERIOD_M2 = 2
PERIOD_M3 = 3
PERIOD_M4 = 4
PERIOD_M5 = 5
PERIOD_M6 = 6
PERIOD_M10 = 10
PERIOD_M12 = 12
PERIOD_M15 = 15
PERIOD_M20 = 20
PERIOD_M30 = 30
PERIOD_H1 = 16385
PERIOD_H2 = 16386
PERIOD_H3 = 16387
PERIOD_H4 = 16388
PERIOD_H6 = 16390
PERIOD_H8 = 16392
PERIOD_H12 = 1639
PERIOD_D1 = 16408
PERIOD_W1 = 32769
PERIOD_MN1 = 49153
# Charts Properties
class ENUM_CHART_PROPERTY_DOUBLE(IntEnum):
CHART_SHIFT_SIZE = 3
CHART_FIXED_POSITION = 41
CHART_FIXED_MAX = 8
CHART_FIXED_MIN = 9
CHART_POINTS_PER_BAR = 11
CHART_PRICE_MIN = 108
CHART_PRICE_MAX = 109
class ENUM_CHART_PROPERTY_INTEGER(IntEnum):
CHART_SHOW = 46
CHART_IS_OBJECT = 111
CHART_BRING_TO_TOP = 35
CHART_CONTEXT_MENU = 50
CHART_CROSSHAIR_TOOL = 49
CHART_MOUSE_SCROLL = 42
CHART_EVENT_MOUSE_WHEEL = 48
CHART_EVENT_MOUSE_MOVE = 40
CHART_EVENT_OBJECT_CREATE = 38
CHART_EVENT_OBJECT_DELETE = 39
CHART_MODE = 0
CHART_FOREGROUND = 1
CHART_SHIFT = 2
CHART_AUTOSCROLL = 4
CHART_KEYBOARD_CONTROL = 47
CHART_QUICK_NAVIGATION = 45
CHART_SCALE = 5
CHART_SCALEFIX = 6
CHART_SCALEFIX_11 = 7
CHART_SCALE_PT_PER_BAR = 10
CHART_SHOW_OHLC = 12
CHART_SHOW_BID_LINE = 13
CHART_SHOW_ASK_LINE = 14
CHART_SHOW_LAST_LINE = 15
CHART_SHOW_PERIOD_SEP = 16
CHART_SHOW_GRID = 17
CHART_SHOW_VOLUMES = 18
CHART_SHOW_OBJECT_DESCR = 19
CHART_VISIBLE_BARS = 100
CHART_WINDOWS_TOTAL = 101
CHART_WINDOW_IS_VISIBLE = 102
CHART_WINDOW_HANDLE = 103
CHART_WINDOW_YDISTANCE = 110
CHART_FIRST_VISIBLE_BAR = 104
CHART_WIDTH_IN_BARS = 105
CHART_WIDTH_IN_PIXELS = 106
CHART_HEIGHT_IN_PIXELS = 107
CHART_COLOR_BACKGROUND = 21
CHART_COLOR_FOREGROUND = 22
CHART_COLOR_GRID = 23
CHART_COLOR_VOLUME = 24
CHART_COLOR_CHART_UP = 25
CHART_COLOR_CHART_DOWN = 26
CHART_COLOR_CHART_LINE = 27
CHART_COLOR_CANDLE_BULL = 28
CHART_COLOR_CANDLE_BEAR = 29
CHART_COLOR_BID = 30
CHART_COLOR_ASK = 31
CHART_COLOR_LAST = 32
CHART_COLOR_STOP_LEVEL = 33
CHART_SHOW_TRADE_LEVELS = 34
CHART_DRAG_TRADE_LEVELS = 43
CHART_SHOW_DATE_SCALE = 36
CHART_SHOW_PRICE_SCALE = 37
CHART_SHOW_ONE_CLICK = 44
CHART_IS_MAXIMIZED = 115
CHART_IS_MINIMIZED = 116
class ENUM_CHART_PROPERTY_STRING(IntEnum):
CHART_COMMENT = 20
CHART_EXPERT_NAME = 113
CHART_SCRIPT_NAME = 114
class ENUM_CHART_POSITION(IntEnum):
CHART_BEGIN = 0 # Chart beginning (the oldest prices)
CHART_CURRENT_POS = 1 # Current position
CHART_END = 2 # Chart end (the latest prices)
# Client Terminal Properties
class ENUM_TERMINAL_INFO_INTEGER(IntEnum):
TERMINAL_BUILD = 5
TERMINAL_COMMUNITY_ACCOUNT = 23
TERMINAL_COMMUNITY_CONNECTION = 24
TERMINAL_CONNECTED = 6
TERMINAL_DLLS_ALLOWED = 7
TERMINAL_TRADE_ALLOWED = 8
TERMINAL_EMAIL_ENABLED = 9
TERMINAL_FTP_ENABLED = 10
TERMINAL_NOTIFICATIONS_ENABLED = 26
TERMINAL_MAXBARS = 11
TERMINAL_MQID = 22
TERMINAL_CODEPAGE = 12
TERMINAL_CPU_CORES = 21
TERMINAL_DISK_SPACE = 20
TERMINAL_MEMORY_PHYSICAL = 14
TERMINAL_MEMORY_TOTAL = 15
TERMINAL_MEMORY_AVAILABLE = 16
TERMINAL_MEMORY_USED = 17
TERMINAL_X64 = 18
TERMINAL_OPENCL_SUPPORT = 19
TERMINAL_SCREEN_DPI = 27
TERMINAL_PING_LAST = 29
class ENUM_TERMINAL_INFO_DOUBLE(IntEnum):
TERMINAL_COMMUNITY_BALANCE = 25
class ENUM_TERMINAL_INFO_STRING(IntEnum):
TERMINAL_LANGUAGE = 13
TERMINAL_COMPANY = 0
TERMINAL_NAME = 1
TERMINAL_PATH = 2
TERMINAL_DATA_PATH = 3
TERMINAL_COMMONDATA_PATH = 4
# Symbol Properties
class ENUM_SYMBOL_INFO_INTEGER(IntEnum):
SYMBOL_CUSTOM = 78
SYMBOL_BACKGROUND_COLOR = 79
SYMBOL_CHART_MODE = 80
SYMBOL_SELECT = 0
SYMBOL_VISIBLE = 76
SYMBOL_SESSION_DEALS = 56
SYMBOL_SESSION_BUY_ORDERS = 60
SYMBOL_SESSION_SELL_ORDERS = 62
SYMBOL_VOLUME = 10
SYMBOL_VOLUMEHIGH = 11
SYMBOL_VOLUMELOW = 12
SYMBOL_TIME = 15
SYMBOL_DIGITS = 17
SYMBOL_SPREAD_FLOAT = 41
SYMBOL_SPREAD = 18
SYMBOL_TICKS_BOOKDEPTH = 25
SYMBOL_TRADE_CALC_MODE = 29
SYMBOL_TRADE_MODE = 30
SYMBOL_START_TIME = 51
SYMBOL_EXPIRATION_TIME = 52
SYMBOL_TRADE_STOPS_LEVEL = 31
SYMBOL_TRADE_FREEZE_LEVEL = 32
SYMBOL_TRADE_EXEMODE = 33
SYMBOL_SWAP_MODE = 37
SYMBOL_SWAP_ROLLOVER3DAYS = 40
SYMBOL_MARGIN_HEDGED_USE_LEG = 82
SYMBOL_EXPIRATION_MODE = 49
SYMBOL_FILLING_MODE = 50
SYMBOL_ORDER_MODE = 71
SYMBOL_ORDER_GTC_MODE = 81
SYMBOL_ORDER_CLOSEBY = 64
SYMBOL_OPTION_MODE = 75
SYMBOL_OPTION_RIGHT = 74
class ENUM_SYMBOL_INFO_DOUBLE(IntEnum):
SYMBOL_BID = 1
SYMBOL_BIDHIGH = 2
SYMBOL_BIDLOW = 3
SYMBOL_ASK = 4
SYMBOL_ASKHIGH = 5
SYMBOL_ASKLOW = 6
SYMBOL_LAST = 7
SYMBOL_LASTHIGH = 8
SYMBOL_LASTLOW = 9
SYMBOL_VOLUME_REAL = 10
SYMBOL_VOLUMEHIGH_REAL = 11
SYMBOL_VOLUMELOW_REAL = 12
SYMBOL_OPTION_STRIKE = 72
SYMBOL_POINT = 16
SYMBOL_TRADE_TICK_VALUE = 26
SYMBOL_TRADE_TICK_VALUE_PROFIT = 53
SYMBOL_TRADE_TICK_VALUE_LOSS = 54
SYMBOL_TRADE_TICK_SIZE = 27
SYMBOL_TRADE_CONTRACT_SIZE = 28
SYMBOL_TRADE_ACCRUED_INTEREST = 87
SYMBOL_TRADE_FACE_VALUE = 86
SYMBOL_TRADE_LIQUIDITY_RATE = 85
SYMBOL_VOLUME_MIN = 34
SYMBOL_VOLUME_MAX = 35
SYMBOL_VOLUME_STEP = 36
SYMBOL_VOLUME_LIMIT = 55
SYMBOL_SWAP_LONG = 38
SYMBOL_SWAP_SHORT = 39
SYMBOL_MARGIN_INITIAL = 42
SYMBOL_MARGIN_MAINTENANCE = 43
SYMBOL_MARGIN_LONG = 44 # FIXME: Undocumented!
SYMBOL_MARGIN_SHORT = 45 # FIXME: Undocumented!
SYMBOL_MARGIN_LIMIT = 46 # FIXME: Undocumented!
SYMBOL_MARGIN_STOP = 47 # FIXME: Undocumented!
SYMBOL_MARGIN_STOPLIMIT = 48 # FIXME: Undocumented!
SYMBOL_SESSION_VOLUME = 57
SYMBOL_SESSION_TURNOVER = 58
SYMBOL_SESSION_INTEREST = 59
SYMBOL_SESSION_BUY_ORDERS_VOLUME = 61
SYMBOL_SESSION_SELL_ORDERS_VOLUME = 63
SYMBOL_SESSION_OPEN = 64
SYMBOL_SESSION_CLOSE = 65
SYMBOL_SESSION_AW = 66
SYMBOL_SESSION_PRICE_SETTLEMENT = 67
SYMBOL_SESSION_PRICE_LIMIT_MIN = 68
SYMBOL_SESSION_PRICE_LIMIT_MAX = 69
SYMBOL_MARGIN_HEDGED = 77
class ENUM_SYMBOL_INFO_STRING(IntEnum):
SYMBOL_BASIS = 73
SYMBOL_CURRENCY_BASE = 22
SYMBOL_CURRENCY_PROFIT = 23
SYMBOL_CURRENCY_MARGIN = 24
SYMBOL_BANK = 19
SYMBOL_DESCRIPTION = 20
SYMBOL_FORMULA = 84
SYMBOL_PAGE = 83
SYMBOL_ISIN = 70
SYMBOL_PATH = 21
class ENUM_SYMBOL_CHART_MODE(IntEnum):
SYMBOL_CHART_MODE_BID = 0
SYMBOL_CHART_MODE_LAST = 1
class ENUM_SYMBOL_ORDER_GTC_MODE(IntEnum):
SYMBOL_ORDERS_GTC = 0
SYMBOL_ORDERS_DAILY = 1
SYMBOL_ORDERS_DAILY_EXCLUDING_STOPS = 2
class ENUM_SYMBOL_CALC_MODE(IntEnum):
SYMBOL_CALC_MODE_FOREX = 0
SYMBOL_CALC_MODE_FUTURES = 1
SYMBOL_CALC_MODE_CFD = 2
SYMBOL_CALC_MODE_CFDINDEX = 3
SYMBOL_CALC_MODE_CFDLEVERAGE = 4
SYMBOL_CALC_MODE_EXCH_STOCKS = 32
SYMBOL_CALC_MODE_EXCH_FUTURES = 33
SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS = 34
SYMBOL_CALC_MODE_SERV_COLLATERAL = 64
class ENUM_SYMBOL_TRADE_MODE(IntEnum):
SYMBOL_TRADE_MODE_DISABLED = 0
SYMBOL_TRADE_MODE_LONGONLY = 1
SYMBOL_TRADE_MODE_SHORTONLY = 2
SYMBOL_TRADE_MODE_CLOSEONLY = 3
SYMBOL_TRADE_MODE_FULL = 4
class ENUM_SYMBOL_TRADE_EXECUTION(IntEnum):
SYMBOL_TRADE_EXECUTION_REQUEST = 0
SYMBOL_TRADE_EXECUTION_INSTANT = 1
SYMBOL_TRADE_EXECUTION_MARKET = 2
SYMBOL_TRADE_EXECUTION_EXCHANGE = 3
class ENUM_SYMBOL_SWAP_MODE(IntEnum):
SYMBOL_SWAP_MODE_DISABLED = 0
SYMBOL_SWAP_MODE_POINTS = 1
SYMBOL_SWAP_MODE_CURRENCY_SYMBOL = 2
SYMBOL_SWAP_MODE_CURRENCY_MARGIN = 3
SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT = 4
SYMBOL_SWAP_MODE_INTEREST_CURRENT = 5
SYMBOL_SWAP_MODE_INTEREST_OPEN = 6
SYMBOL_SWAP_MODE_REOPEN_CURRENT = 7
SYMBOL_SWAP_MODE_REOPEN_BID = 8
class ENUM_DAY_OF_WEEK(IntEnum):
SUNDAY = 0
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
class ENUM_SYMBOL_OPTION_RIGHT(IntEnum):
SYMBOL_OPTION_RIGHT_CALL = 0
SYMBOL_OPTION_RIGHT_PUT = 1
class ENUM_SYMBOL_OPTION_MODE(IntEnum):
SYMBOL_OPTION_MODE_EUROPEAN = 0
SYMBOL_OPTION_MODE_AMERICAN = 1
# Account Properties
class ENUM_ACCOUNT_INFO_INTEGER(IntEnum):
ACCOUNT_LOGIN = 0 # Account number
ACCOUNT_TRADE_MODE = 32 # Account trade mode
ACCOUNT_LEVERAGE = 35 # Account leverage
ACCOUNT_LIMIT_ORDERS = 47 # Maximum allowed number of active pending orders
ACCOUNT_MARGIN_SO_MODE = 44 # Mode for setting the minimal allowed margin
ACCOUNT_TRADE_ALLOWED = 33 # Allowed trade for the current account
ACCOUNT_TRADE_EXPERT = 34 # Allowed trade for an Expert Advisor
ACCOUNT_MARGIN_MODE = 53 # Margin calculation mode
class ENUM_ACCOUNT_INFO_DOUBLE(IntEnum):
ACCOUNT_BALANCE = 37 # Account balance in the deposit currency
ACCOUNT_CREDIT = 38 # Account credit in the deposit currency
ACCOUNT_PROFIT = 39 # Current profit of an account in the deposit currency
ACCOUNT_EQUITY = 40 # Account equity in the deposit currency
ACCOUNT_MARGIN = 41 # Account margin used in the deposit currency
ACCOUNT_MARGIN_FREE = 42 # Free margin of an account in the deposit currency
ACCOUNT_MARGIN_LEVEL = 43 # Account margin level in percents
ACCOUNT_MARGIN_SO_CALL = 45 # Margin call level
ACCOUNT_MARGIN_SO_SO = 46 # Margin stop out level
ACCOUNT_MARGIN_INITIAL = 48 # Initial margin
ACCOUNT_MARGIN_MAINTENANCE = 49 # Maintenance margin
ACCOUNT_ASSETS = 50 # The current assets of an account
ACCOUNT_LIABILITIES = 51 # The current liabilities on an account
ACCOUNT_COMMISSION_BLOCKED = 52 # The current blocked commission amount on an account
class ENUM_ACCOUNT_INFO_STRING(IntEnum):
ACCOUNT_NAME = 1 # Client name
ACCOUNT_SERVER = 3 # Trade server name
ACCOUNT_CURRENCY = 36 # Account currency
ACCOUNT_COMPANY = 2 # Name of a company that serves the account
class ENUM_ACCOUNT_TRADE_MODE(IntEnum):
ACCOUNT_TRADE_MODE_DEMO = 0 # Demo account
ACCOUNT_TRADE_MODE_CONTEST = 1 # Contest account
ACCOUNT_TRADE_MODE_REAL = 2 # Real account
class ENUM_ACCOUNT_STOPOUT_MODE(IntEnum):
ACCOUNT_STOPOUT_MODE_PERCENT = 0 # Account stop out mode in percents
ACCOUNT_STOPOUT_MODE_MONEY = 1 # Account stop out mode in money
class ENUM_ACCOUNT_MARGIN_MODE(IntEnum):
ACCOUNT_MARGIN_MODE_RETAIL_NETTING = 0 # Used for the OTC markets to interpret positions in the "netting" mode
ACCOUNT_MARGIN_MODE_EXCHANGE = 1 # Used for the exchange markets
ACCOUNT_MARGIN_MODE_RETAIL_HEDGING = 2 # Used for the exchange markets where individual positions are possible
# Trade Constants:
# History Database Properties
class ENUM_SERIES_INFO_INTEGER(IntEnum):
SERIES_BARS_COUNT = 0 # Bars count for the symbol-period for the current moment
SERIES_FIRSTDATE = 1 # The very first date for the symbol-period for the current moment
SERIES_LASTBAR_DATE = 5 # Open time of the last bar of the symbol-period
SERIES_SERVER_FIRSTDATE = (
2 # The very first date in the history of the symbol on the server regardless of the timeframe
)
SERIES_TERMINAL_FIRSTDATE = (
3 # The very first date in the history of the symbol in the client terminal, regardless of the timeframe
)
SERIES_SYNCHRONIZED = 4 # S ymbol/period data synchronization flag for the current moment
# Order Properties
class ENUM_ORDER_PROPERTY_INTEGER(IntEnum):
ORDER_TICKET = 22 # Order ticket. Unique number assigned to each order
ORDER_TIME_SETUP = 1 # Order setup time
ORDER_TYPE = 4 # Order type
ORDER_STATE = 14 # Order state
ORDER_TIME_EXPIRATION = 2 # Order expiration time
ORDER_TIME_DONE = 3 # Order execution or cancellation time
ORDER_TIME_SETUP_MSC = 18 # The time of placing an order for execution in milliseconds since 01.01.1970
ORDER_TIME_DONE_MSC = 19 # Order execution/cancellation time in milliseconds since 01.01.1970
ORDER_TYPE_FILLING = 5 # Order filling type
ORDER_TYPE_TIME = 6 # Order lifetime
ORDER_MAGIC = 15 # ID of an Expert Advisor that has placed the order (designed to ensure that each Expert Advisor places its own unique number)
ORDER_REASON = 23 # The reason or source for placing an order
ORDER_POSITION_ID = 17 # Position identifier that is set to an order as soon as it is executed.
# Each executed order results in a deal that opens or modifies an already existing position. The identifier of exactly this position is set to the executed order at this moment.
ORDER_POSITION_BY_ID = 21 # Identifier of an opposite position used for closing by order ORDER_TYPE_CLOSE_BY
class ENUM_ORDER_PROPERTY_DOUBLE(IntEnum):
ORDER_VOLUME_INITIAL = 7 # Order initial volume
ORDER_VOLUME_CURRENT = 8 # Order current volume
ORDER_PRICE_OPEN = 9 # Price specified in the order
ORDER_SL = 12 # Stop Loss value
ORDER_TP = 13 # Take Profit value
ORDER_PRICE_CURRENT = 10 # The current price of the order symbol
ORDER_PRICE_STOPLIMIT = 11 # The Limit order price for the StopLimit order
class ENUM_ORDER_PROPERTY_STRING(IntEnum):
ORDER_SYMBOL = 0 # Symbol of the order
ORDER_COMMENT = 16 # Order comment
ORDER_EXTERNAL_ID = 20 # Order identifier in an external trading system (on the Exchange)
class ENUM_ORDER_TYPE(IntEnum):
ORDER_TYPE_BUY = 0 # Market Buy order
ORDER_TYPE_SELL = 1 # Market Sell order
ORDER_TYPE_BUY_LIMIT = 2 # Buy Limit pending order
ORDER_TYPE_SELL_LIMIT = 3 # Sell Limit pending order
ORDER_TYPE_BUY_STOP = 4 # Buy Stop pending order
ORDER_TYPE_SELL_STOP = 5 # Sell Stop pending order
ORDER_TYPE_BUY_STOP_LIMIT = (
6 # Upon reaching the order price, a pending Buy Limit order is places at the StopLimit price
)
ORDER_TYPE_SELL_STOP_LIMIT = (
7 # Upon reaching the order price, a pending Sell Limit order is places at the StopLimit price
)
ORDER_TYPE_CLOSE_BY = 8 # Order to close a position by an opposite one
class ENUM_ORDER_STATE(IntEnum):
ORDER_STATE_STARTED = 0 # Order checked, but not yet accepted by broker
ORDER_STATE_PLACED = 1 # Order accepted
ORDER_STATE_CANCELED = 2 # Order canceled by client
ORDER_STATE_PARTIAL = 3 # Order partially executed
ORDER_STATE_FILLED = 4 # Order fully executed
ORDER_STATE_REJECTED = 5 # Order rejected
ORDER_STATE_EXPIRED = 6 # Order expired
ORDER_STATE_REQUEST_ADD = 7 # Order is being registered (placing to the trading system)
ORDER_STATE_REQUEST_MODIFY = 8 # Order is being modified (changing its parameters)
ORDER_STATE_REQUEST_CANCEL = 9 # Order is being deleted (deleting from the trading system)
class ENUM_ORDER_TYPE_FILLING(IntEnum):
ORDER_FILLING_FOK = 0
ORDER_FILLING_IOC = 1
ORDER_FILLING_RETURN = 2
class ENUM_ORDER_TYPE_TIME(IntEnum):
ORDER_TIME_GTC = 0
ORDER_TIME_DAY = 1
ORDER_TIME_SPECIFIED = 2
ORDER_TIME_SPECIFIED_DAY = 3
class ENUM_ORDER_REASON(IntEnum):
ORDER_REASON_CLIENT = 0 # The order was placed from a desktop terminal
ORDER_REASON_MOBILE = 1 # The order was placed from a mobile application
ORDER_REASON_WEB = 2 # The order was placed from a web platform
ORDER_REASON_EXPERT = 3 # The order was placed from an MQL5-program, i.e. by an Expert Advisor or a script
ORDER_REASON_SL = 4 # The order was placed as a result of Stop Loss activation
ORDER_REASON_TP = 5 # The order was placed as a result of Take Profit activation
ORDER_REASON_SO = 6 # The order was placed as a result of the Stop Out event
# Position Properties
class ENUM_POSITION_PROPERTY_INTEGER(IntEnum):
POSITION_TICKET = 17 # Position ticket
POSITION_TIME = 1 # Position open time
POSITION_TIME_MSC = 14 # Position opening time in milliseconds since 01.01.1970
POSITION_TIME_UPDATE = 15 # Position changing time in seconds since 01.01.1970
POSITION_TIME_UPDATE_MSC = 16 # Position changing time in milliseconds since 01.01.1970
POSITION_TYPE = 2 # Position type
POSITION_MAGIC = 12 # Position magic number
POSITION_IDENTIFIER = 13 # Position identifier is a unique number that is assigned to every newly opened position
# and doesn't change during the entire lifetime of the position. Position turnover doesn't change its identifier.
POSITION_REASON = 18 # The reason for opening a position
class ENUM_POSITION_PROPERTY_DOUBLE(IntEnum):
POSITION_VOLUME = 3 # Position volume
POSITION_PRICE_OPEN = 4 # Position open price
POSITION_SL = 6 # Stop Loss level of opened position
POSITION_TP = 7 # Take Profit level of opened position
POSITION_PRICE_CURRENT = 5 # Current price of the position symbol
POSITION_SWAP = 9 # Cumulative swap
POSITION_PROFIT = 10 # Current profit
class ENUM_POSITION_PROPERTY_STRING(IntEnum):
POSITION_SYMBOL = 0 # Symbol of the position
POSITION_COMMENT = 11 # Position comment
class ENUM_POSITION_TYPE(IntEnum):
POSITION_TYPE_BUY = 0 # Buy
POSITION_TYPE_SELL = 1 # Sell
class ENUM_POSITION_REASON(IntEnum):
POSITION_REASON_CLIENT = (
0 # The position was opened as a result of activation of an order placed from a desktop terminal
)
POSITION_REASON_MOBILE = (
1 # The position was opened as a result of activation of an order placed from a mobile application
)
POSITION_REASON_WEB = (
2 # The position was opened as a result of activation of an order placed from the web platform
)
POSITION_REASON_EXPERT = (
3 # The position was opened as a result of activation of an order placed from an MQL5 program
)
# Deal Properties
class ENUM_DEAL_PROPERTY_INTEGER(IntEnum):
DEAL_TICKET = 15 # Deal ticket. Unique number assigned to each deal
DEAL_ORDER = 1 # Deal order number
DEAL_TIME = 2 # Deal time
DEAL_TIME_MSC = 13 # The time of a deal execution in milliseconds since 01.01.1970
DEAL_TYPE = 3 # Deal type
DEAL_ENTRY = 4 # Deal entry - entry in, entry out, reverse
DEAL_MAGIC = 11 # Deal magic number
DEAL_REASON = 16 # The reason or source for deal execution
DEAL_POSITION_ID = 12 # Identifier of a position
class ENUM_DEAL_PROPERTY_DOUBLE(IntEnum):
DEAL_VOLUME = 5 # Deal volume
DEAL_PRICE = 6 # Deal price
DEAL_COMMISSION = 7 # Deal commission
DEAL_SWAP = 8 # Cumulative swap on close
DEAL_PROFIT = 9 # Deal profit
class ENUM_DEAL_PROPERTY_STRING(IntEnum):
DEAL_SYMBOL = 0 # Deal symbol
DEAL_COMMENT = 10 # Deal comment
DEAL_EXTERNAL_ID = 14 # Deal identifier in an external trading system (on the Exchange)
class ENUM_DEAL_TYPE(IntEnum):
DEAL_TYPE_BUY = 0 # Buy
DEAL_TYPE_SELL = 1 # Sell
DEAL_TYPE_BALANCE = 2 # Balance
DEAL_TYPE_CREDIT = 3 # Credit
DEAL_TYPE_CHARGE = 4 # Additional charge
DEAL_TYPE_CORRECTION = 5 # Correction
DEAL_TYPE_BONUS = 6 # Bonus
DEAL_TYPE_COMMISSION = 7 # Additional commission
DEAL_TYPE_COMMISSION_DAILY = 8 # Daily commission
DEAL_TYPE_COMMISSION_MONTHLY = 9 # Monthly commission
DEAL_TYPE_COMMISSION_AGENT_DAILY = 10 # Daily agent commission
DEAL_TYPE_COMMISSION_AGENT_MONTHLY = 11 # Monthly agent commission
DEAL_TYPE_INTEREST = 12 # Interest rate
DEAL_TYPE_BUY_CANCELED = 13 # Canceled buy deal
DEAL_TYPE_SELL_CANCELED = 14 # Canceled sell deal
DEAL_DIVIDEND = 15 # Dividend operations
DEAL_DIVIDEND_FRANKED = 16 # Franked (non-taxable) dividend operations
DEAL_TAX = 17 # Tax charges
class ENUM_DEAL_ENTRY(IntEnum):
DEAL_ENTRY_IN = 0 # Entry in
DEAL_ENTRY_OUT = 1 # Entry out
DEAL_ENTRY_INOUT = 2 # Reverse
DEAL_ENTRY_STATE = 255 # Close a position by an opposite one
class ENUM_DEAL_REASON(IntEnum):
DEAL_REASON_CLIENT = 0 # The deal was executed as a result of activation of an order placed from a desktop terminal
DEAL_REASON_MOBILE = (
1 # The deal was executed as a result of activation of an order placed from a mobile application
)
DEAL_REASON_WEB = 2 # The deal was executed as a result of activation of an order placed from the web platform
DEAL_REASON_EXPERT = 3 # The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script
DEAL_REASON_SL = 4 # The deal was executed as a result of Stop Loss activation
DEAL_REASON_TP = 5 # The deal was executed as a result of Take Profit activation
DEAL_REASON_SO = 6 # The deal was executed as a result of the Stop Out event
DEAL_REASON_ROLLOVER = 7 # The deal was executed due to a rollover
DEAL_REASON_VMARGIN = 8 # The deal was executed after charging the variation margin
DEAL_REASON_SPLIT = 9 # The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement
# Trade Operation Types
class ENUM_TRADE_REQUEST_ACTIONS(IntEnum):
TRADE_ACTION_DEAL = 1 # Place a trade order for an immediate execution with the specified parameters (market order)
TRADE_ACTION_PENDING = 5 # Place a trade order for the execution under specified conditions (pending order)
TRADE_ACTION_SLTP = 6 # Modify Stop Loss and Take Profit values of an opened position
TRADE_ACTION_MODIFY = 7 # Modify the parameters of the order placed previously
TRADE_ACTION_REMOVE = 8 # Delete the pending order placed previously
TRADE_ACTION_CLOSE_BY = 10 # Close a position by an opposite one
# Trade Transaction Types
class ENUM_TRADE_TRANSACTION_TYPE(IntEnum):
TRADE_TRANSACTION_ORDER_ADD = 0 # Adding a new open order
TRADE_TRANSACTION_ORDER_UPDATE = (
1 # Updating an open order. The updates include not only evident changes from the client terminal
)
# or a trade server sides but also changes of an order state when setting it
# (for example, transition from ORDER_STATE_STARTED to ORDER_STATE_PLACED or from ORDER_STATE_PLACED to ORDER_STATE_PARTIAL, etc.).
TRADE_TRANSACTION_ORDER_DELETE = 2 # Removing an order from the list of the open ones. An order can be deleted from the open ones as a result of setting an appropriate request
# or execution (filling) and moving to the history.
TRADE_TRANSACTION_DEAL_ADD = 6 # Adding a deal to the history. The action is performed as a result of an order execution or performing operations with an account balance.
TRADE_TRANSACTION_DEAL_UPDATE = (
7 # Updating a deal in the history. There may be cases when a previously executed deal is changed on a server.
)
# For example, a deal has been changed in an external trading system (exchange) where it was previously transferred by a broker.
TRADE_TRANSACTION_DEAL_DELETE = 8 # Deleting a deal from the history. There may be cases when a previously executed deal is deleted from a server.
# For example, a deal has been deleted in an external trading system (exchange) where it was previously transferred by a broker.
TRADE_TRANSACTION_HISTORY_ADD = 3 # Adding an order to the history as a result of execution or cancellation.
TRADE_TRANSACTION_HISTORY_UPDATE = 4 # Changing an order located in the orders history. This type is provided for enhancing functionality on a trade server side.
TRADE_TRANSACTION_HISTORY_DELETE = 5 # Deleting an order from the orders history. This type is provided for enhancing functionality on a trade server side.
TRADE_TRANSACTION_POSITION = 9 # Changing a position not related to a deal execution. This type of transaction shows that a position has been changed on a trade server side.
# Position volume, open price, Stop Loss and Take Profit levels can be changed. Data on changes are submitted in MqlTradeTransaction structure via OnTradeTransaction handler.
# Position change (adding, changing or closing), as a result of a deal execution, does not lead to the occurrence of TRADE_TRANSACTION_POSITION transaction.
TRADE_TRANSACTION_REQUEST = 10 # Notification of the fact that a trade request has been processed by a server and processing result has been received.
# Only type field (trade transaction type) must be analyzed for such transactions in MqlTradeTransaction structure.
# The second and third parameters of OnTradeTransaction (request and result) must be analyzed for additional data.
# Trade Orders in Depth Of Market
class ENUM_BOOK_TYPE(IntEnum):
BOOK_TYPE_SELL = 1 # Sell order (Offer)
BOOK_TYPE_BUY = 2 # Buy order (Bid)
BOOK_TYPE_SELL_MARKET = 3 # Sell order by Market
BOOK_TYPE_BUY_MARKET = 4 # Buy order by Market
# Object Types
class ENUM_OBJECT(IntEnum):
OBJ_VLINE = 0 # Vertical Line
OBJ_HLINE = 1 # Horizontal Line
OBJ_TREND = 2 # Trend Line
OBJ_TRENDBYANGLE = 3 # Trend Line By Angle
OBJ_CYCLES = 4 # Cycle Lines
OBJ_ARROWED_LINE = 108 # Arrowed Line
OBJ_CHANNEL = 5 # Equidistant Channel
OBJ_STDDEVCHANNEL = 6 # Standard Deviation Channel
OBJ_REGRESSION = 7 # Linear Regression Channel
OBJ_PITCHFORK = 8 # Andrews’ Pitchfork
OBJ_GANNLINE = 9 # Gann Line
OBJ_GANNFAN = 10 # Gann Fan
OBJ_GANNGRID = 11 # Gann Grid
OBJ_FIBO = 12 # Fibonacci Retracement
OBJ_FIBOTIMES = 13 # Fibonacci Time Zones
OBJ_FIBOFAN = 14 # Fibonacci Fan
OBJ_FIBOARC = 15 # Fibonacci Arcs
OBJ_FIBOCHANNEL = 16 # Fibonacci Channel
OBJ_EXPANSION = 17 # Fibonacci Expansion
OBJ_ELLIOTWAVE5 = 18 # Elliott Motive Wave
OBJ_ELLIOTWAVE3 = 19 # Elliott Correction Wave
OBJ_RECTANGLE = 20 # Rectangle
OBJ_TRIANGLE = 21 # Triangle
OBJ_ELLIPSE = 22 # Ellipse
OBJ_ARROW_THUMB_UP = 23 # Thumbs Up
OBJ_ARROW_THUMB_DOWN = 24 # Thumbs Down
OBJ_ARROW_UP = 25 # Arrow Up
OBJ_ARROW_DOWN = 26 # Arrow Down
OBJ_ARROW_STOP = 27 # Stop Sign
OBJ_ARROW_CHECK = 28 # Check Sign
OBJ_ARROW_LEFT_PRICE = 29 # Left Price Label
OBJ_ARROW_RIGHT_PRICE = 30 # Right Price Label
OBJ_ARROW_BUY = 31 # Buy Sign
OBJ_ARROW_SELL = 32 # Sell Sign
OBJ_ARROW = 100 # Arrow
OBJ_TEXT = 101 # Text
OBJ_LABEL = 102 # Label
OBJ_BUTTON = 103 # Button
OBJ_CHART = 104 # Chart
OBJ_BITMAP = 105 # Bitmap
OBJ_BITMAP_LABEL = 106 # Bitmap Label
OBJ_EDIT = 107 # Edit
OBJ_EVENT = 109 # The "Event" object corresponding to an event in the economic calendar
OBJ_RECTANGLE_LABEL = 110 # The "Rectangle label" object for creating and designing the custom graphical interface.
# Object Properties
class ENUM_OBJECT_PROPERTY_DOUBLE(IntEnum):
OBJPROP_PRICE = 9 # Price coordinate
OBJPROP_LEVELVALUE = 204 # Level value
OBJPROP_SCALE = 1006 # Scale (properties of Gann objects and Fibonacci Arcs)
OBJPROP_ANGLE = 1007 # Angle. For the objects with no angle specified, created from a program, the value is equal to EMPTY_VALUE
OBJPROP_DEVIATION = 1010 # Deviation for the Standard Deviation Channel
class ENUM_OBJECT_PROPERTY_INTEGER(IntEnum):
OBJPROP_COLOR = 0 # Color
OBJPROP_STYLE = 1 # Style
OBJPROP_WIDTH = 2 # Line thickness
OBJPROP_BACK = 3 # Object in the background
OBJPROP_ZORDER = (
207 # Priority of a graphical object for receiving events of clicking on a chart (CHARTEVENT_CLICK).
)
# The default zero value is set when creating an object; the priority can be increased if necessary.
# When objects are placed one atop another, only one of them with the highest priority will receive the CHARTEVENT_CLICK event.
OBJPROP_FILL = 1031 # Fill an object with color (for OBJ_RECTANGLE, OBJ_TRIANGLE, OBJ_ELLIPSE, OBJ_CHANNEL, OBJ_STDDEVCHANNEL, OBJ_REGRESSION)
OBJPROP_HIDDEN = 208 # Prohibit showing of the name of a graphical object in the list of objects from the terminal menu "Charts" - "Objects" - "List of objects".
# The true value allows to hide an object from the list. By default, true is set to the objects that display calendar events,
# trading history and to the objects created from MQL5 programs. To see such graphical objects and access their properties, click on the "All" button in the "List of objects" window.
OBJPROP_SELECTED = 4 # Object is selected
OBJPROP_READONLY = 1028 # Ability to edit text in the Edit object
OBJPROP_TYPE = 7 # Object type
OBJPROP_TIME = 8 # Time coordinate
OBJPROP_SELECTABLE = 10 # Object availability
OBJPROP_CREATETIME = 11 # Time of object creation
OBJPROP_LEVELS = 200 # Number of levels
OBJPROP_LEVELCOLOR = 201 # Color of the line-level
OBJPROP_LEVELSTYLE = 202 # Style of the line-level
OBJPROP_LEVELWIDTH = 203 # Thickness of the line-level
OBJPROP_ALIGN = 1036 # Horizontal text alignment in the "Edit" object (OBJ_EDIT)
OBJPROP_FONTSIZE = 1002 # Font size
OBJPROP_RAY_LEFT = 1003 # Ray goes to the left
OBJPROP_RAY_RIGHT = 1004 # Ray goes to the right
OBJPROP_RAY = 1032 # A vertical line goes through all the windows of a chart
OBJPROP_ELLIPSE = 1005 # Showing the full ellipse of the Fibonacci Arc object (OBJ_FIBOARC)
OBJPROP_ARROWCODE = 1008 # Arrow code for the Arrow object
OBJPROP_TIMEFRAMES = 12 # Visibility of an object at timeframes
OBJPROP_ANCHOR = 1011 # Location of the anchor point of a graphical object
OBJPROP_XDISTANCE = 1012 # The distance in pixels along the X axis from the binding corner
OBJPROP_YDISTANCE = 1013 # The distance in pixels along the Y axis from the binding corner
OBJPROP_DIRECTION = 1014 # Trend of the Gann object
OBJPROP_DEGREE = 1015 # Level of the Elliott Wave Marking
OBJPROP_DRAWLINES = 1016 # Displaying lines for marking the Elliott Wave
OBJPROP_STATE = 1018 # Button state (pressed / depressed)
OBJPROP_CHART_ID = 1030 # ID of the "Chart" object (OBJ_CHART). It allows working with the properties of this object like with a normal chart using the functions described in Chart Operations, but there some exceptions.
OBJPROP_XSIZE = 1019 # The object's width along the X axis in pixels. Specified for OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT, OBJ_RECTANGLE_LABEL objects.
OBJPROP_YSIZE = 1020 # The object's height along the Y axis in pixels. Specified for OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT, OBJ_RECTANGLE_LABEL objects.
OBJPROP_XOFFSET = 1033 # The X coordinate of the upper left corner of the rectangular visible area in the graphical objects "Bitmap Label" and "Bitmap" (OBJ_BITMAP_LABEL and OBJ_BITMAP).
# The value is set in pixels relative to the upper left corner of the original image.
OBJPROP_YOFFSET = 1034 # The Y coordinate of the upper left corner of the rectangular visible area in the graphical objects "Bitmap Label" and "Bitmap" (OBJ_BITMAP_LABEL and OBJ_BITMAP).
# The value is set in pixels relative to the upper left corner of the original image.
OBJPROP_PERIOD = 1022 # Timeframe for the Chart object
OBJPROP_DATE_SCALE = 1023 # Displaying the time scale for the Chart object
OBJPROP_PRICE_SCALE = 1024 # Displaying the price scale for the Chart object
OBJPROP_CHART_SCALE = 1027 # The scale for the Chart object
OBJPROP_BGCOLOR = 1025 # The background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
OBJPROP_CORNER = 1026 # The corner of the chart to link a graphical object
OBJPROP_BORDER_TYPE = 1029 # Border type for the "Rectangle label" object
OBJPROP_BORDER_COLOR = 1035 # Border color for the OBJ_EDIT and OBJ_BUTTON objects
class ENUM_OBJECT_PROPERTY_STRING(IntEnum):
OBJPROP_NAME = 5 # Object name
OBJPROP_TEXT = 6 # Description of the object (the text contained in the object)
OBJPROP_TOOLTIP = 206 # The text of a tooltip. If the property is not set, then the tooltip generated automatically by the terminal is shown. A tooltip can be disabled by setting the "\n" (line feed) value to it
OBJPROP_LEVELTEXT = 205 # Level description
OBJPROP_FONT = 1001 # Font
OBJPROP_BMPFILE = 1017 # The name of BMP-file for Bitmap Label.
OBJPROP_SYMBOL = 1021 # Symbol for the Chart object
class ENUM_BORDER_TYPE(IntEnum):
BORDER_FLAT = 0 # Flat form
BORDER_RAISED = 1 # Prominent form
BORDER_SUNKEN = 2 # Concave form
class ENUM_ALIGN_MODE(IntEnum):
ALIGN_LEFT = 1 # Left alignment
ALIGN_CENTER = 2 # Centered (only for the Edit object)
ALIGN_RIGHT = 0 # Right alignment
# Price Constants
class ENUM_APPLIED_PRICE(IntEnum):
PRICE_CLOSE = 1 # Close price
PRICE_OPEN = 2 # Open price
PRICE_HIGH = 3 # The maximum price for the period
PRICE_LOW = 4 # The minimum price for the period
PRICE_MEDIAN = 5 # Median price, (high + low)/2
PRICE_TYPICAL = 6 # Typical price, (high + low + close)/3
PRICE_WEIGHTED = 7 # Average price, (high + low + close + close)/4
class ENUM_APPLIED_VOLUME(IntEnum):
VOLUME_TICK = 0 # Tick volume
VOLUME_REAL = 1 # Trade volume
class ENUM_STO_PRICE(IntEnum):
STO_LOWHIGH = 0 # Calculation is based on Low/High prices
STO_CLOSECLOSE = 1 # Calculation is based on Close/Close prices
# Smoothing Methods
class ENUM_MA_METHOD(IntEnum):
MODE_SMA = 0 # Simple averaging
MODE_EMA = 1 # Exponential averaging
MODE_SMMA = 2 # Smoothed averaging
MODE_LWMA = 3 # Linear-weighted averaging
# Indicator constants
class ENUM_INDICATOR(IntEnum):
IND_AC = 5 # Accelerator Oscillator
IND_AD = 6 # Accumulation/Distribution
IND_ADX = 8 # Average Directional Index
IND_ADXW = 9 # ADX by Welles Wilder
IND_ALLIGATOR = 7 # Alligator
IND_AMA = 40 # Adaptive Moving Average
IND_AO = 11 # Awesome Oscillator
IND_ATR = 10 # Average True Range
IND_BANDS = 13 # Bollinger Bands®
IND_BEARS = 12 # Bears Power
IND_BULLS = 14 # Bulls Power
IND_BWMFI = 22 # Market Facilitation Index
IND_CCI = 15 # Commodity Channel Index
IND_CHAIKIN = 41 # Chaikin Oscillator
IND_CUSTOM = 43 # Custom indicator
IND_DEMA = 36 # Double Exponential Moving Average
IND_DEMARKER = 16 # DeMarker
IND_ENVELOPES = 17 # Envelopes
IND_FORCE = 18 # Force Index
IND_FRACTALS = 19 # Fractals
IND_FRAMA = 39 # Fractal Adaptive Moving Average
IND_GATOR = 20 # Gator Oscillator
IND_ICHIMOKU = 21 # Ichimoku Kinko Hyo
IND_MA = 26 # Moving Average
IND_MACD = 23 # MACD
IND_MFI = 25 # Money Flow Index
IND_MOMENTUM = 24 # Momentum
IND_OBV = 28 # On Balance Volume
IND_OSMA = 27 # OsMA
IND_RSI = 30 # Relative Strength Index
IND_RVI = 31 # Relative Vigor Index
IND_SAR = 29 # Parabolic SAR
IND_STDDEV = 32 # Standard Deviation
IND_STOCHASTIC = 33 # Stochastic Oscillator
IND_TEMA = 37 # Triple Exponential Moving Average
IND_TRIX = 38 # Triple Exponential Moving Averages Oscillator
IND_VIDYA = 42 # Variable Index Dynamic Average
IND_VOLUMES = 34 # Volumes
IND_WPR = 35 # Williams' Percent Ranges
class ENUM_DATATYPE(IntEnum):
TYPE_BOOL = 1
TYPE_CHAR = 2
TYPE_UCHAR = 3
TYPE_SHORT = 4
TYPE_USHORT = 5
TYPE_COLOR = 6
TYPE_INT = 7
TYPE_UINT = 8
TYPE_DATETIME = 9
TYPE_LONG = 10
TYPE_ULONG = 11
TYPE_FLOAT = 12
TYPE_DOUBLE = 13
TYPE_STRING = 14
class CopyTicksFlag(IntEnum):
Info = 1 # ticks with Bid and/or Ask changes
Trade = 2 # ticks with changes in Last and Volume
All = -1 # all ticks
-167
View File
@@ -1,167 +0,0 @@
import logging
from enum import IntEnum
from threading import Condition, Lock, Thread
import websockets
from websockets.sync.client import connect as ws_connect
class MtNotification(IntEnum):
ClientReady = 0
class MtMessageType(IntEnum):
Command = 0
Response = 1
Event = 2
ExpertList = 3
ExpertAdded = 4
ExpertRemoved = 5
Notification = 6
class CommandTask:
def __init__(self):
self.locker = Lock()
self.waiter = Condition()
self.response = None
def wait_response(self, time):
with self.waiter:
self.waiter.wait(time)
with self.locker:
return self.response
def set_response(self, response):
with self.locker:
self.response = response
with self.waiter:
self.waiter.notify()
class MtRpcClient:
def __init__(self, callback=None):
self.__logger = logging.getLogger(__name__)
self.__callback = callback
self.__notification_tasks = dict()
self.__tasks = dict()
self.__next_command_id = 0
self.__lock = Lock()
def connect(self, url):
self.__logger.debug(f"connecting to {url}")
self.__ws = ws_connect(url)
self.__receive_thread = Thread(target=self.__receive_messages_thread)
self.__receive_thread.start()
def disconnect(self):
self.__ws.close()
self.__receive_thread.join()
self.__logger.debug("disconnected")
def request_expert_list(self):
task = CommandTask()
with self.__lock:
self.__notification_tasks[MtNotification.ClientReady] = task
self.__ws.send(self.__create_notification(MtNotification.ClientReady))
response = task.wait_response(10)
with self.__lock:
self.__notification_tasks.pop(MtNotification.ClientReady)
return response
def send_command(self, expert_handle, command_type, payload=None):
command_id = self.__next_command_id
self.__next_command_id += 1
task = CommandTask()
with self.__lock:
self.__tasks[command_id] = task
self.__ws.send(self.__create_mt_command(expert_handle, command_id, command_type, payload))
response = task.wait_response(10)
with self.__lock:
self.__tasks.pop(command_id)
return response
# Private methods
def __process_message(self, message):
self.__logger.debug(f"process_message: {message}")
pieces = message.split(";", 1)
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
self.__logger.warning("process_message: Invalid message format")
return
message_type = MtMessageType(int(pieces[0]))
if message_type == MtMessageType.ExpertList:
self.__process_expert_list(pieces[1])
elif message_type == MtMessageType.Event:
self.__process_event(pieces[1])
elif message_type == MtMessageType.Response:
self.__process_response(pieces[1])
elif message_type == MtMessageType.ExpertAdded:
self.__process_expert_added(pieces[1])
elif message_type == MtMessageType.ExpertRemoved:
self.__process_expert_removed(pieces[1])
else:
self.__logger.warning(f"received unknown message type: {message_type}")
def __process_expert_list(self, payload):
pieces = payload.split(",")
experts = list()
for p in pieces:
experts.append(int(p))
with self.__lock:
task = self.__notification_tasks.get(MtNotification.ClientReady)
if task is not None:
task.set_response(experts)
def __process_event(self, payload):
pieces = payload.split(";", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
self.__logger.warning("process_event: Invalid message format")
return
if self.__callback is not None:
self.__callback.mt_rpc_on_event(int(pieces[0]), int(pieces[1]), pieces[2])
def __process_response(self, payload):
pieces = payload.split(";", 2)
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
self.__logger.warning("process_response: Invalid message format")
return
command_id = int(pieces[1])
with self.__lock:
task = self.__tasks.get(command_id)
if task is not None:
task.set_response(pieces[2])
def __process_expert_added(self, payload):
if self.__callback is not None:
self.__callback.mt_rpc_on_expert_added(int(payload))
def __process_expert_removed(self, payload):
if self.__callback is not None:
self.__callback.mt_rpc_on_expert_removed(int(payload))
def __receive_messages_thread(self):
self.__logger.debug("started receive_messages thread")
while True:
try:
message = self.__ws.recv()
self.__process_message(message)
except websockets.exceptions.ConnectionClosed:
self.__logger.info("Connection closed")
if self.__callback is not None:
self.__callback.mt_rcp_on_disconnect()
break
except Exception as e:
self.__logger.error(e)
if self.__callback is not None:
self.__callback.mt_rpc_on_connection_failed(str(e))
break
self.__logger.debug("function receive_messages finished")
def __create_notification(self, notification_type):
return f"{int(MtMessageType.Notification)};{notification_type}"
def __create_mt_command(self, expert_handle, command_id, command_type, payload):
if payload is None:
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type}"
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type};{payload}"
+36 -16
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,22 +481,34 @@
</TabItem>
<TabItem Header="Market Info">
<WrapPanel 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"/>
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
<Button Command="{Binding SymbolInfoTickCommand}" Content="SymbolInfoTick" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionQuoteCommand}" Content="SymbolInfoSessionQuote" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionTradeCommand}" Content="SymbolInfoSessionTrade" Margin="2"/>
<Button Command="{Binding MarketBookAddCommand}" Content="MarketBookAdd" Margin="2"/>
<Button Command="{Binding MarketBookReleaseCommand}" Content="MarketBookRelease" Margin="2"/>
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
</WrapPanel>
<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"/>
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
<Button Command="{Binding SymbolInfoTickCommand}" Content="SymbolInfoTick" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionQuoteCommand}" Content="SymbolInfoSessionQuote" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionTradeCommand}" Content="SymbolInfoSessionTrade" Margin="2"/>
<Button Command="{Binding MarketBookAddCommand}" Content="MarketBookAdd" Margin="2"/>
<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
+23 -44
View File
@@ -1,51 +1,16 @@
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
private readonly List<Action> _groupOrderCommands = [];
private readonly MtApiClient _apiClient = new (new MtLogger());
private readonly MtApiClient _apiClient = new(new MtLogger());
private readonly TimerTradeMonitor _timerTradeMonitor;
private readonly TimeframeTradeMonitor _timeframeTradeMonitor;
@@ -742,7 +707,7 @@ namespace TestApiClientUI
var symbol = textBoxOrderSymbol.Text;
var cmd = (TradeOperation) comboBoxOrderCommand.SelectedIndex;
var cmd = (TradeOperation)comboBoxOrderCommand.SelectedIndex;
double volume;
double.TryParse(textBoxOrderVolume.Text, out volume);
@@ -750,7 +715,7 @@ namespace TestApiClientUI
double price;
double.TryParse(textBoxOrderPrice.Text, out price);
var slippage = (int) numericOrderSlippage.Value;
var slippage = (int)numericOrderSlippage.Value;
double stoploss;
double.TryParse(textBoxOrderStoploss.Text, out stoploss);
@@ -805,8 +770,8 @@ namespace TestApiClientUI
private async void button16_Click(object sender, EventArgs e)
{
var ticket = int.Parse(textBoxIndexTicket.Text);
var selectMode = (OrderSelectMode) comboBox1.SelectedIndex;
var selectSource = (OrderSelectSource) comboBox2.SelectedIndex;
var selectMode = (OrderSelectMode)comboBox1.SelectedIndex;
var selectSource = (OrderSelectSource)comboBox2.SelectedIndex;
var order = await Execute(() => _apiClient.GetOrder(ticket, selectMode, selectSource));
@@ -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}");
}
}
}
+25 -25
View File
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
+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.
+47 -9
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);
@@ -3792,16 +3795,25 @@ bool OrderCloseAll()
{
if (OrderSelect(i, SELECT_BY_POS))
{
int type = OrderType();
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 );
case OP_BUY:
{
order_closed = 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_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.