mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 02:57:56 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a77c08258e | |||
| 3699b73cf7 | |||
| 9d178280d0 | |||
| a8bb1a3af9 | |||
| fa1e6b6c62 | |||
| 9e26a1d262 | |||
| 249b0f9fbb | |||
| 0a1ec30b84 | |||
| 0c874773e5 | |||
| 2c4d9b130b | |||
| a900ea8968 | |||
| a5b8e33611 | |||
| b5309fb9a4 | |||
| 2f0ccae238 | |||
| 371c14b4b7 | |||
| 565735c3c5 | |||
| 1bb9c7b418 | |||
| 7b5f740a77 | |||
| 22b0f695c6 | |||
| c536585cd2 | |||
| 29ce645975 | |||
| 92322e866e | |||
| 34072905d2 | |||
| 96674d8763 | |||
| 5808756113 | |||
| fe8ac339b6 | |||
| 972df57028 | |||
| 6c1cb92f1b | |||
| ff871e5e06 | |||
| c7b8956c99 | |||
| db3db18391 | |||
| 143cc33c60 | |||
| 541fc2364b | |||
| 78b4b7039b | |||
| 4a61ab079c | |||
| 69d98b66b3 | |||
| 6b3d54b9d5 | |||
| ba1754d59b | |||
| b89f00d310 | |||
| 19d9cb23d3 |
@@ -89,7 +89,7 @@ namespace MtApi.Monitors
|
|||||||
{
|
{
|
||||||
//get closed orders from history with actual values
|
//get closed orders from history with actual values
|
||||||
var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY) ?? [];
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-52
@@ -27,7 +27,6 @@ namespace MtApi
|
|||||||
private readonly Dictionary<MtEventTypes, Action<int, string>> _mtEventHandlers = [];
|
private readonly Dictionary<MtEventTypes, Action<int, string>> _mtEventHandlers = [];
|
||||||
private HashSet<int> _experts = [];
|
private HashSet<int> _experts = [];
|
||||||
private Dictionary<int, MtQuote> _quotes = [];
|
private Dictionary<int, MtQuote> _quotes = [];
|
||||||
private readonly EventWaitHandle _quotesWaiter = new AutoResetEvent(false);
|
|
||||||
|
|
||||||
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
|
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
|
||||||
private int _executorHandle;
|
private int _executorHandle;
|
||||||
@@ -83,7 +82,6 @@ namespace MtApi
|
|||||||
///</summary>
|
///</summary>
|
||||||
public List<MtQuote> GetQuotes()
|
public List<MtQuote> GetQuotes()
|
||||||
{
|
{
|
||||||
_quotesWaiter.WaitOne(10000); // wait 10 sec for loading all quotes from MetaTrader
|
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
return _quotes.Values.ToList();
|
return _quotes.Values.ToList();
|
||||||
@@ -504,6 +502,12 @@ namespace MtApi
|
|||||||
Dictionary<string, object> cmdParams = new() { { "Pool", (int)pool} };
|
Dictionary<string, object> cmdParams = new() { { "Pool", (int)pool} };
|
||||||
return SendCommand<List<MtOrder>>(ExecutorHandle, MtCommandType.GetOrders, cmdParams);
|
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
|
#endregion
|
||||||
|
|
||||||
#region Checkup
|
#region Checkup
|
||||||
@@ -1133,7 +1137,7 @@ namespace MtApi
|
|||||||
return SendCommand<double>(ExecutorHandle, MtCommandType.iBearsPower, cmdParams);
|
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 },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol },
|
||||||
{ "Timeframe", timeframe }, { "Period", period },
|
{ "Timeframe", timeframe }, { "Period", period },
|
||||||
@@ -1143,7 +1147,7 @@ namespace MtApi
|
|||||||
return SendCommand<double>(ExecutorHandle, MtCommandType.iBands, cmdParams);
|
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 },
|
Dictionary<string, object> cmdParams = new() { { "Total", total },
|
||||||
{ "Period", period }, { "Deviation", deviation },
|
{ "Period", period }, { "Deviation", deviation },
|
||||||
@@ -3041,7 +3045,6 @@ namespace MtApi
|
|||||||
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connecting, message));
|
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connecting, message));
|
||||||
|
|
||||||
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
|
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
|
||||||
client.ExpertList += Client_ExpertList;
|
|
||||||
client.ExpertAdded += Client_ExpertAdded;
|
client.ExpertAdded += Client_ExpertAdded;
|
||||||
client.ExpertRemoved += Client_ExpertRemoved;
|
client.ExpertRemoved += Client_ExpertRemoved;
|
||||||
client.MtEventReceived += Client_MtEventReceived;
|
client.MtEventReceived += Client_MtEventReceived;
|
||||||
@@ -3052,13 +3055,44 @@ namespace MtApi
|
|||||||
{
|
{
|
||||||
await client.Connect();
|
await client.Connect();
|
||||||
Log.Info($"Connected to {host}:{port}");
|
Log.Info($"Connected to {host}:{port}");
|
||||||
|
|
||||||
|
var experts = client.RequestExpertsList();
|
||||||
|
if (experts == null || experts.Count == 0)
|
||||||
|
{
|
||||||
|
var errorMessage = "Failed to load expert list";
|
||||||
|
Log.Error(errorMessage);
|
||||||
|
client.Disconnect();
|
||||||
|
|
||||||
|
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Failed, errorMessage));
|
||||||
|
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load quotes
|
||||||
|
Dictionary<int, MtQuote> quotes = [];
|
||||||
|
foreach (var handle in experts)
|
||||||
|
{
|
||||||
|
var quote = GetQuote(client, handle);
|
||||||
|
if (quote != null)
|
||||||
|
quotes[handle] = quote;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
|
_experts = experts;
|
||||||
|
_quotes = quotes;
|
||||||
|
if (_executorHandle == 0)
|
||||||
|
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
||||||
_connectionState = MtConnectionState.Connected;
|
_connectionState = MtConnectionState.Connected;
|
||||||
}
|
}
|
||||||
client.NotifyClientReady();
|
|
||||||
|
if (IsTesting())
|
||||||
|
{
|
||||||
|
BacktestingReady();
|
||||||
|
}
|
||||||
|
|
||||||
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connected, $"Connected to {host}:{port}"));
|
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connected, $"Connected to {host}:{port}"));
|
||||||
|
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -3102,7 +3136,11 @@ namespace MtApi
|
|||||||
|
|
||||||
private T? SendCommand<T>(int expertHandle, MtCommandType commandType, object? payload = null)
|
private T? SendCommand<T>(int expertHandle, MtCommandType commandType, object? payload = null)
|
||||||
{
|
{
|
||||||
var client = Client;
|
return SendCommand<T>(Client, expertHandle, commandType, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private T? SendCommand<T>(MtRpcClient? client, int expertHandle, MtCommandType commandType, object? payload = null)
|
||||||
|
{
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
Log.Warn("SendCommand: No connection");
|
Log.Warn("SendCommand: No connection");
|
||||||
@@ -3143,11 +3181,6 @@ namespace MtApi
|
|||||||
Task.Run(() => _mtEventHandlers[(MtEventTypes)e.EventType](e.ExpertHandle, e.Payload));
|
Task.Run(() => _mtEventHandlers[(MtEventTypes)e.EventType](e.ExpertHandle, e.Payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Client_ExpertList(object? sender, MtExpertListEventArgs e)
|
|
||||||
{
|
|
||||||
Task.Run(() => ProcessExpertList(e.Experts));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
|
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
|
||||||
{
|
{
|
||||||
Task.Run(() => ProcessExpertAdded(e.Expert));
|
Task.Run(() => ProcessExpertAdded(e.Expert));
|
||||||
@@ -3213,39 +3246,6 @@ namespace MtApi
|
|||||||
OnLockTicks?.Invoke(this, new MtLockTicksEventArgs(expertHandle, e.Instrument));
|
OnLockTicks?.Invoke(this, new MtLockTicksEventArgs(expertHandle, e.Instrument));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessExpertList(HashSet<int> experts)
|
|
||||||
{
|
|
||||||
if (experts == null || experts.Count == 0)
|
|
||||||
{
|
|
||||||
Log.Warn("ProcessExpertList: expert list invalid or empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<int, MtQuote> quotes = [];
|
|
||||||
foreach (var handle in experts)
|
|
||||||
{
|
|
||||||
var quote = GetQuote(handle);
|
|
||||||
if (quote != null)
|
|
||||||
quotes[handle] = quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
_experts = experts;
|
|
||||||
_quotes = quotes;
|
|
||||||
if (_executorHandle == 0)
|
|
||||||
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
|
||||||
}
|
|
||||||
_quotesWaiter.Set();
|
|
||||||
|
|
||||||
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
|
|
||||||
|
|
||||||
if (IsTesting())
|
|
||||||
{
|
|
||||||
BacktestingReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessExpertAdded(int handle)
|
private void ProcessExpertAdded(int handle)
|
||||||
{
|
{
|
||||||
Log.Debug($"ProcessExpertAdded: {handle}");
|
Log.Debug($"ProcessExpertAdded: {handle}");
|
||||||
@@ -3260,7 +3260,7 @@ namespace MtApi
|
|||||||
|
|
||||||
if (added)
|
if (added)
|
||||||
{
|
{
|
||||||
var quote = GetQuote(handle);
|
var quote = GetQuote(Client, handle);
|
||||||
if (quote != null)
|
if (quote != null)
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
@@ -3295,19 +3295,19 @@ namespace MtApi
|
|||||||
QuoteRemoved?.Invoke(this, new MtQuoteEventArgs(quote));
|
QuoteRemoved?.Invoke(this, new MtQuoteEventArgs(quote));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MtQuote? GetQuote(int expertHandle)
|
private MtQuote? GetQuote(MtRpcClient? client, int expertHandle)
|
||||||
{
|
{
|
||||||
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
|
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
|
||||||
|
|
||||||
var e = SendCommand<MtRpcQuote>(expertHandle, MtCommandType.GetQuote);
|
var q = SendCommand<MtRpcQuote>(client, expertHandle, MtCommandType.GetQuote);
|
||||||
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Tick == null)
|
if (q == null || string.IsNullOrEmpty(q.Instrument) || q.Tick == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
MtQuote quote = new()
|
MtQuote quote = new()
|
||||||
{
|
{
|
||||||
Instrument = e.Instrument,
|
Instrument = q.Instrument,
|
||||||
Bid = e.Tick.Bid,
|
Bid = q.Tick.Bid,
|
||||||
Ask = e.Tick.Ask,
|
Ask = q.Tick.Ask,
|
||||||
ExpertHandle = expertHandle,
|
ExpertHandle = expertHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -287,6 +287,7 @@
|
|||||||
SymbolInfoTick = 288,
|
SymbolInfoTick = 288,
|
||||||
SymbolInfoDouble = 289,
|
SymbolInfoDouble = 289,
|
||||||
|
|
||||||
GetQuote = 290
|
GetQuote = 290,
|
||||||
|
GetSymbols = 291
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -3,8 +3,8 @@
|
|||||||
public class MqlParam
|
public class MqlParam
|
||||||
{
|
{
|
||||||
public ENUM_DATATYPE DataType { get; set; }
|
public ENUM_DATATYPE DataType { get; set; }
|
||||||
public long? IntegerValue { get; set; }
|
public long IntegerValue { get; set; } = 0;
|
||||||
public double? DoubleValue { get; set; }
|
public double DoubleValue { get; set; } = 0.0;
|
||||||
public string? StringValue { get; set; }
|
public string StringValue { get; set; } = String.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,18 @@ namespace MtApi5
|
|||||||
public class MqlTick
|
public class MqlTick
|
||||||
{
|
{
|
||||||
public MqlTick(DateTime time, double bid, double ask, double last, ulong volume)
|
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);
|
MtTime = Mt5TimeConverter.ConvertToMtTime(time);
|
||||||
this.bid = bid;
|
this.bid = bid;
|
||||||
this.ask = ask;
|
this.ask = ask;
|
||||||
this.last = last;
|
this.last = last;
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
|
this.flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqlTick()
|
public MqlTick()
|
||||||
@@ -27,6 +33,7 @@ namespace MtApi5
|
|||||||
last = tick.Last;
|
last = tick.Last;
|
||||||
volume = tick.Volume;
|
volume = tick.Volume;
|
||||||
volume_real = tick.VolumeReal;
|
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 double last { get; set; } // Price of the last deal (Last)
|
||||||
public ulong volume { get; set; } // Volume for the current Last price
|
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 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);
|
public DateTime time => Mt5TimeConverter.ConvertFromMtTime(MtTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -862,6 +862,18 @@ namespace MtApi5
|
|||||||
STO_CLOSECLOSE = 1 //Calculation is based on Close/Close prices
|
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
|
#endregion //Price Constants
|
||||||
|
|
||||||
#region Smoothing Methods
|
#region Smoothing Methods
|
||||||
|
|||||||
@@ -4,15 +4,17 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
public class Mt5TimeBarArgs: EventArgs
|
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;
|
ExpertHandle = expertHandle;
|
||||||
Rates = rates;
|
Rates = rates;
|
||||||
Symbol = symbol;
|
Symbol = symbol;
|
||||||
|
Timeframe = timeframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExpertHandle { get; }
|
public int ExpertHandle { get; }
|
||||||
public string Symbol { get; }
|
public string Symbol { get; }
|
||||||
|
public ENUM_TIMEFRAMES Timeframe { get; }
|
||||||
public MqlRates Rates { get; }
|
public MqlRates Rates { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<VersionPrefix>2.0.0</VersionPrefix>
|
<VersionPrefix>2.0.1</VersionPrefix>
|
||||||
<BaseOutputPath>$(SolutionDir)build\products</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)build\products</BaseOutputPath>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
+106
-87
@@ -2,6 +2,7 @@
|
|||||||
using MtClient;
|
using MtClient;
|
||||||
using MtApi5.MtProtocol;
|
using MtApi5.MtProtocol;
|
||||||
using MtApi5.MtProtocol.ICustomRequest;
|
using MtApi5.MtProtocol.ICustomRequest;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
namespace MtApi5
|
namespace MtApi5
|
||||||
{
|
{
|
||||||
@@ -31,12 +32,24 @@ namespace MtApi5
|
|||||||
|
|
||||||
private HashSet<int> _experts = [];
|
private HashSet<int> _experts = [];
|
||||||
private Dictionary<int, Mt5Quote> _quotes = [];
|
private Dictionary<int, Mt5Quote> _quotes = [];
|
||||||
private readonly EventWaitHandle _quotesWaiter = new AutoResetEvent(false);
|
private volatile int _command_timeout = 30000; // 30 seconds
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
private IMtLogger Log { get; }
|
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)
|
public MtApi5Client(IMtLogger? log = null)
|
||||||
{
|
{
|
||||||
_mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent;
|
_mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent;
|
||||||
@@ -94,17 +107,13 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
if (_connectionState == Mt5ConnectionState.Connected
|
if (_connectionState == Mt5ConnectionState.Connected
|
||||||
|| _connectionState == Mt5ConnectionState.Connecting)
|
|| _connectionState == Mt5ConnectionState.Connecting)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
_connectionState = Mt5ConnectionState.Connecting;
|
_connectionState = Mt5ConnectionState.Connecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, $"Connecting to {host}:{port}"));
|
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, $"Connecting to {host}:{port}"));
|
||||||
|
|
||||||
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
|
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
|
||||||
client.ExpertList += Client_ExpertList;
|
|
||||||
client.ExpertAdded += Client_ExpertAdded;
|
client.ExpertAdded += Client_ExpertAdded;
|
||||||
client.ExpertRemoved += Client_ExpertRemoved;
|
client.ExpertRemoved += Client_ExpertRemoved;
|
||||||
client.MtEventReceived += Client_MtEventReceived;
|
client.MtEventReceived += Client_MtEventReceived;
|
||||||
@@ -115,13 +124,35 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
await client.Connect();
|
await client.Connect();
|
||||||
Log.Info($"Connected to {host}:{port}");
|
Log.Info($"Connected to {host}:{port}");
|
||||||
|
|
||||||
|
var experts = client.RequestExpertsList();
|
||||||
|
if (experts == null || experts.Count == 0)
|
||||||
|
{
|
||||||
|
var errorMessage = "Failed to load expert list";
|
||||||
|
Log.Error(errorMessage);
|
||||||
|
client.Disconnect();
|
||||||
|
|
||||||
|
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Failed, errorMessage));
|
||||||
|
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var quotes = LoadQuotes(client, experts);
|
||||||
|
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
|
_experts = experts;
|
||||||
|
_quotes = quotes;
|
||||||
|
if (_executorHandle == 0)
|
||||||
|
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
||||||
_connectionState = Mt5ConnectionState.Connected;
|
_connectionState = Mt5ConnectionState.Connected;
|
||||||
}
|
}
|
||||||
client.NotifyClientReady();
|
|
||||||
|
if (IsTesting())
|
||||||
|
BacktestingReady();
|
||||||
|
|
||||||
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connected, $"Connected to {host}:{port}"));
|
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connected, $"Connected to {host}:{port}"));
|
||||||
|
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -135,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>
|
///<summary>
|
||||||
///Disconnect from MetaTrader API. Async method.
|
///Disconnect from MetaTrader API. Async method.
|
||||||
///</summary>
|
///</summary>
|
||||||
@@ -154,18 +197,35 @@ namespace MtApi5
|
|||||||
}
|
}
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
///Load quotes connected into MetaTrader API (deprecated)
|
///Load quotes connected into MetaTrader API
|
||||||
///</summary>
|
///</summary>
|
||||||
public IEnumerable<Mt5Quote> GetQuotes()
|
public IEnumerable<Mt5Quote> GetQuotes()
|
||||||
{
|
{
|
||||||
// this function is deprecated.
|
MtRpcClient? client;
|
||||||
// should be used event OnQuoteList
|
HashSet<int> experts;
|
||||||
|
|
||||||
_quotesWaiter.WaitOne(10000); // wait 10 sec for loading all quotes from MetaTrader
|
|
||||||
lock (_locker)
|
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>
|
///<summary>
|
||||||
@@ -2644,7 +2704,7 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
|
||||||
{ "FastMaPeriod", fastMaPeriod }, { "SlowMaPeriod", slowMaPeriod},
|
{ "FastMaPeriod", fastMaPeriod }, { "SlowMaPeriod", slowMaPeriod},
|
||||||
{ "MaMethod", (int)maMethod }, { "appliedVolume", (int)appliedVolume } };
|
{ "MaMethod", (int)maMethod }, { "AppliedVolume", (int)appliedVolume } };
|
||||||
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iChaikin, cmdParams);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iChaikin, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2710,14 +2770,14 @@ namespace MtApi5
|
|||||||
}
|
}
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
///The function returns the handle of the Force Index indicator.
|
///The function returns the handle of the Fractals indicator.
|
||||||
///</summary>
|
///</summary>
|
||||||
///<param name="symbol">The symbol name of the security, the data of which should be used to calculate the indicator.</param>
|
///<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>
|
///<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 } };
|
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>
|
///<summary>
|
||||||
@@ -2949,7 +3009,7 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
|
||||||
{ "Kperiod", Kperiod }, { "Dperiod", Dperiod }, { "Slowing", slowing },
|
{ "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);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iStochastic, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3035,8 +3095,8 @@ namespace MtApi5
|
|||||||
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, double[] parameters)
|
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, double[] parameters)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
||||||
{ "Period", (int)period }, { "Name", name ?? string.Empty},
|
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty},
|
||||||
{ "Parameters", parameters }, { "ParamsType", ParametersType.Double} };
|
{ "Params", parameters }, { "ParamsType", ParametersType.Double} };
|
||||||
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3050,8 +3110,8 @@ namespace MtApi5
|
|||||||
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, int[] parameters)
|
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, int[] parameters)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
||||||
{ "Period", (int)period }, { "Name", name ?? string.Empty }, { "Parameters", parameters },
|
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty }, { "Parameters", parameters },
|
||||||
{ "ParamsType", ParametersType.Int } };
|
{ "Params", ParametersType.Int } };
|
||||||
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3065,8 +3125,8 @@ namespace MtApi5
|
|||||||
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, string[] parameters)
|
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, string[] parameters)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
||||||
{ "Period", (int)period }, { "Name", name ?? string.Empty },
|
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
|
||||||
{ "Parameters", parameters }, { "ParamsType", ParametersType.String } };
|
{ "Params", parameters }, { "ParamsType", ParametersType.String } };
|
||||||
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3080,8 +3140,8 @@ namespace MtApi5
|
|||||||
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, bool[] parameters)
|
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, bool[] parameters)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
|
||||||
{ "Period", (int)period }, { "Name", name ?? string.Empty },
|
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
|
||||||
{ "Parameters", parameters }, { "ParamsType", ParametersType.Boolean } };
|
{ "Params", parameters }, { "ParamsType", ParametersType.Boolean } };
|
||||||
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3345,11 +3405,6 @@ namespace MtApi5
|
|||||||
Task.Run(() => _mtEventHandlers[(Mt5EventTypes)e.EventType](e.ExpertHandle, e.Payload));
|
Task.Run(() => _mtEventHandlers[(Mt5EventTypes)e.EventType](e.ExpertHandle, e.Payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Client_ExpertList(object? sender, MtExpertListEventArgs e)
|
|
||||||
{
|
|
||||||
Task.Run(()=>ProcessExpertList(e.Experts));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
|
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
|
||||||
{
|
{
|
||||||
Task.Run(() => ProcessExpertAdded(e.Expert));
|
Task.Run(() => ProcessExpertAdded(e.Expert));
|
||||||
@@ -3360,39 +3415,6 @@ namespace MtApi5
|
|||||||
Task.Run(() => ProcessExpertRemoved(e.Expert));
|
Task.Run(() => ProcessExpertRemoved(e.Expert));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessExpertList(HashSet<int> experts)
|
|
||||||
{
|
|
||||||
if (experts == null || experts.Count == 0)
|
|
||||||
{
|
|
||||||
Log.Warn("ProcessExpertList: expert list invalid or empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<int, Mt5Quote> quotes = [];
|
|
||||||
foreach (var handle in experts)
|
|
||||||
{
|
|
||||||
var quote = GetQuote(handle);
|
|
||||||
if (quote != null)
|
|
||||||
quotes[handle] = quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
_experts = experts;
|
|
||||||
_quotes = quotes;
|
|
||||||
if (_executorHandle == 0)
|
|
||||||
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
|
||||||
}
|
|
||||||
_quotesWaiter.Set();
|
|
||||||
|
|
||||||
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
|
|
||||||
|
|
||||||
if (IsTesting())
|
|
||||||
{
|
|
||||||
BacktestingReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessExpertAdded(int handle)
|
private void ProcessExpertAdded(int handle)
|
||||||
{
|
{
|
||||||
Log.Debug($"ProcessExpertAdded: {handle}");
|
Log.Debug($"ProcessExpertAdded: {handle}");
|
||||||
@@ -3407,14 +3429,9 @@ namespace MtApi5
|
|||||||
|
|
||||||
if (added)
|
if (added)
|
||||||
{
|
{
|
||||||
var quote = GetQuote(handle);
|
var quote = GetQuote(Client, handle);
|
||||||
if (quote != null)
|
if (quote != null)
|
||||||
{
|
{
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
_quotes[handle] = quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
QuoteAdded?.Invoke(this, new Mt5QuoteEventArgs(quote));
|
QuoteAdded?.Invoke(this, new Mt5QuoteEventArgs(quote));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -3429,38 +3446,37 @@ namespace MtApi5
|
|||||||
{
|
{
|
||||||
Log.Debug($"ProcessExpertRemoved: {handle}");
|
Log.Debug($"ProcessExpertRemoved: {handle}");
|
||||||
|
|
||||||
Mt5Quote? quote = null;
|
Mt5Quote? quote;
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
|
_quotes.TryGetValue(handle, out quote);
|
||||||
|
_quotes.Remove(handle);
|
||||||
_experts.Remove(handle);
|
_experts.Remove(handle);
|
||||||
if (_quotes.TryGetValue(handle, out quote))
|
|
||||||
_quotes.Remove(handle);
|
|
||||||
if (_executorHandle == handle)
|
if (_executorHandle == handle)
|
||||||
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quote != null)
|
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(int expertHandle)
|
private Mt5Quote? GetQuote(MtRpcClient? client, int expertHandle)
|
||||||
{
|
{
|
||||||
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
|
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
|
||||||
|
|
||||||
var e = SendCommand<MtQuote>(expertHandle, Mt5CommandType.GetQuote);
|
var q = SendCommand<MtQuote>(client, expertHandle, Mt5CommandType.GetQuote);
|
||||||
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Tick == null)
|
if (q == null || string.IsNullOrEmpty(q.Instrument) || q.Tick == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Mt5Quote quote = new()
|
Mt5Quote quote = new()
|
||||||
{
|
{
|
||||||
Instrument = e.Instrument,
|
Instrument = q.Instrument,
|
||||||
Bid = e.Tick.Bid,
|
Bid = q.Tick.Bid,
|
||||||
Ask = e.Tick.Ask,
|
Ask = q.Tick.Ask,
|
||||||
ExpertHandle = expertHandle,
|
ExpertHandle = expertHandle,
|
||||||
Volume = e.Tick.Volume,
|
Volume = q.Tick.Volume,
|
||||||
Time = Mt5TimeConverter.ConvertFromMtTime(e.Tick.Time),
|
Time = Mt5TimeConverter.ConvertFromMtTime(q.Tick.Time),
|
||||||
Last = e.Tick.Last
|
Last = q.Tick.Last
|
||||||
};
|
};
|
||||||
|
|
||||||
return quote;
|
return quote;
|
||||||
@@ -3530,7 +3546,7 @@ namespace MtApi5
|
|||||||
var e = JsonConvert.DeserializeObject<OnLastTimeBarEvent>(payload);
|
var e = JsonConvert.DeserializeObject<OnLastTimeBarEvent>(payload);
|
||||||
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Rates == null)
|
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Rates == null)
|
||||||
return;
|
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)
|
private void ReceivedOnLockTicksEvent(int expertHandle, string payload)
|
||||||
@@ -3558,7 +3574,6 @@ namespace MtApi5
|
|||||||
client = _client;
|
client = _client;
|
||||||
_client = null;
|
_client = null;
|
||||||
|
|
||||||
_quotes.Clear();
|
|
||||||
_experts.Clear();
|
_experts.Clear();
|
||||||
_executorHandle = 0;
|
_executorHandle = 0;
|
||||||
}
|
}
|
||||||
@@ -3572,7 +3587,11 @@ namespace MtApi5
|
|||||||
|
|
||||||
private T? SendCommand<T>(int expertHandle, Mt5CommandType commandType, object? payload = null)
|
private T? SendCommand<T>(int expertHandle, Mt5CommandType commandType, object? payload = null)
|
||||||
{
|
{
|
||||||
var client = Client;
|
return SendCommand<T>(Client, expertHandle, commandType, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private T? SendCommand<T>(MtRpcClient? client, int expertHandle, Mt5CommandType commandType, object? payload = null)
|
||||||
|
{
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
Log.Warn("SendCommand: No connection");
|
Log.Warn("SendCommand: No connection");
|
||||||
@@ -3582,7 +3601,7 @@ namespace MtApi5
|
|||||||
var payloadJson = payload == null ? string.Empty : JsonConvert.SerializeObject(payload);
|
var payloadJson = payload == null ? string.Empty : JsonConvert.SerializeObject(payload);
|
||||||
Log.Debug($"SendCommand: sending '{payloadJson}' ...");
|
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}]");
|
Log.Debug($"SendCommand: received response JSON [{responseJson}]");
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,6 @@
|
|||||||
public double Last { get; set; } // Price of the last deal (Last)
|
public double Last { get; set; } // Price of the last deal (Last)
|
||||||
public ulong Volume { get; set; } // Volume for the current Last price
|
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 double VolumeReal { get; set; } // Volume for the current Last price with greater accuracy
|
||||||
|
public uint Flags { get; set; } // Tick flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,6 +259,7 @@ namespace MtApi5.MtProtocol
|
|||||||
OrderSendAsync = 302,
|
OrderSendAsync = 302,
|
||||||
OrderCheck = 303,
|
OrderCheck = 303,
|
||||||
Buy = 304,
|
Buy = 304,
|
||||||
Sell = 305
|
Sell = 305,
|
||||||
|
GetSymbols = 306
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
public MqlRates? Rates { get; set; }
|
public MqlRates? Rates { get; set; }
|
||||||
public string? Instrument { get; set; }
|
public string? Instrument { get; set; }
|
||||||
|
public ENUM_TIMEFRAMES Timeframe { get; set; }
|
||||||
public int ExpertHandle { get; set; }
|
public int ExpertHandle { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,12 @@
|
|||||||
ExpertList = 3,
|
ExpertList = 3,
|
||||||
ExpertAdded = 4,
|
ExpertAdded = 4,
|
||||||
ExpertRemoved = 5,
|
ExpertRemoved = 5,
|
||||||
Notification = 6
|
ServiceRequest = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum MtNotificationType
|
internal enum ServiceRequestType
|
||||||
{
|
{
|
||||||
ClientReady = 0
|
ExpertList = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class MtMessage
|
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()
|
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
|
internal class MtEvent(int expertHandle, int eventType, string payload) : MtMessage
|
||||||
|
|||||||
+42
-37
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Net.WebSockets;
|
||||||
using System.Net.WebSockets;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace MtClient
|
namespace MtClient
|
||||||
@@ -66,9 +65,9 @@ namespace MtClient
|
|||||||
logger_.Debug($"MtRpcClient.Disconnect: success");
|
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 commandTask = new();
|
CommandTask<string> commandTask = new();
|
||||||
int commandId;
|
int commandId;
|
||||||
lock (tasks_)
|
lock (tasks_)
|
||||||
{
|
{
|
||||||
@@ -79,7 +78,7 @@ namespace MtClient
|
|||||||
MtCommand command = new(expertHandle, commandType, commandId, payload);
|
MtCommand command = new(expertHandle, commandType, commandId, payload);
|
||||||
Send(command);
|
Send(command);
|
||||||
|
|
||||||
var response = commandTask.WaitResponse(10000); // 10 sec
|
var response = commandTask.WaitResponse(timeout);
|
||||||
lock (tasks_)
|
lock (tasks_)
|
||||||
{
|
{
|
||||||
tasks_.Remove(commandId);
|
tasks_.Remove(commandId);
|
||||||
@@ -88,10 +87,24 @@ namespace MtClient
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotifyClientReady()
|
public HashSet<int>? RequestExpertsList()
|
||||||
{
|
{
|
||||||
MtNotification notification = new(MtNotificationType.ClientReady);
|
CommandTask<object> requestTask = new();
|
||||||
Send(notification);
|
lock (service_requests_)
|
||||||
|
{
|
||||||
|
service_requests_[ServiceRequestType.ExpertList] = requestTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
MtServiceRequest request = new(ServiceRequestType.ExpertList);
|
||||||
|
Send(request);
|
||||||
|
|
||||||
|
var response = requestTask.WaitResponse(10000); // 10 sec
|
||||||
|
lock (service_requests_)
|
||||||
|
{
|
||||||
|
service_requests_.Remove(ServiceRequestType.ExpertList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response as HashSet<int>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Send(MtMessage message)
|
private void Send(MtMessage message)
|
||||||
@@ -118,7 +131,7 @@ namespace MtClient
|
|||||||
{
|
{
|
||||||
sendWaiter_.WaitOne();
|
sendWaiter_.WaitOne();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -166,30 +179,12 @@ namespace MtClient
|
|||||||
else if (result.MessageType == WebSocketMessageType.Text)
|
else if (result.MessageType == WebSocketMessageType.Text)
|
||||||
{
|
{
|
||||||
var msg = Encoding.UTF8.GetString(ms.ToArray(), 0, recvCount);
|
var msg = Encoding.UTF8.GetString(ms.ToArray(), 0, recvCount);
|
||||||
//var msg = Encoding.ASCII.GetString(recvBuffer, 0, result.Count);
|
|
||||||
OnReceive(msg);
|
OnReceive(msg);
|
||||||
}
|
}
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//byte[] recvBuffer = new byte[64 * 1024];
|
|
||||||
//while (ws_.State == WebSocketState.Open)
|
|
||||||
//{
|
|
||||||
// var result = await ws_.ReceiveAsync(new ArraySegment<byte>(recvBuffer), CancellationToken.None);
|
|
||||||
// if (result.MessageType == WebSocketMessageType.Close)
|
|
||||||
// {
|
|
||||||
// logger_.Info($"MtRpcClient.DoReceive: close signal {result.CloseStatusDescription}");
|
|
||||||
// Disconnected?.Invoke(this, EventArgs.Empty);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// var msg = Encoding.ASCII.GetString(recvBuffer, 0, result.Count);
|
|
||||||
// OnReceive(msg);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -216,7 +211,7 @@ namespace MtClient
|
|||||||
{
|
{
|
||||||
logger_.Warn("MtRpcClient.OnReceive: Invalid message format.");
|
logger_.Warn("MtRpcClient.OnReceive: Invalid message format.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageType msgType;
|
MessageType msgType;
|
||||||
try
|
try
|
||||||
@@ -250,7 +245,7 @@ namespace MtClient
|
|||||||
break;
|
break;
|
||||||
case MessageType.ExpertList:
|
case MessageType.ExpertList:
|
||||||
if (message is MtExpertListMsg expertListMsg)
|
if (message is MtExpertListMsg expertListMsg)
|
||||||
ExpertList?.Invoke(this, new(expertListMsg.Experts));
|
ProcessExpertList(expertListMsg.Experts);
|
||||||
break;
|
break;
|
||||||
case MessageType.ExpertAdded:
|
case MessageType.ExpertAdded:
|
||||||
if (message is MtExpertAddedMsg expertAddedMsg)
|
if (message is MtExpertAddedMsg expertAddedMsg)
|
||||||
@@ -273,14 +268,24 @@ namespace MtClient
|
|||||||
|
|
||||||
lock (tasks_)
|
lock (tasks_)
|
||||||
{
|
{
|
||||||
if (tasks_.TryGetValue(commandId, out CommandTask? value))
|
if (tasks_.TryGetValue(commandId, out CommandTask<string>? value))
|
||||||
value.SetResponse(payload);
|
value.SetResponse(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ProcessExpertList(HashSet<int> experts)
|
||||||
|
{
|
||||||
|
logger_.Debug($"MtRpcClient.ProcessExpertList: experts count - {experts.Count}");
|
||||||
|
|
||||||
|
lock (service_requests_)
|
||||||
|
{
|
||||||
|
if (service_requests_.TryGetValue(ServiceRequestType.ExpertList, out CommandTask<object>? value))
|
||||||
|
value.SetResponse(experts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public event EventHandler<EventArgs>? ConnectionFailed;
|
public event EventHandler<EventArgs>? ConnectionFailed;
|
||||||
public event EventHandler<EventArgs>? Disconnected;
|
public event EventHandler<EventArgs>? Disconnected;
|
||||||
public event EventHandler<MtExpertListEventArgs>? ExpertList;
|
|
||||||
public event EventHandler<MtExpertEventArgs>? ExpertAdded;
|
public event EventHandler<MtExpertEventArgs>? ExpertAdded;
|
||||||
public event EventHandler<MtExpertEventArgs>? ExpertRemoved;
|
public event EventHandler<MtExpertEventArgs>? ExpertRemoved;
|
||||||
public event EventHandler<MtEventArgs>? MtEventReceived;
|
public event EventHandler<MtEventArgs>? MtEventReceived;
|
||||||
@@ -288,7 +293,6 @@ namespace MtClient
|
|||||||
private readonly ClientWebSocket ws_ = new();
|
private readonly ClientWebSocket ws_ = new();
|
||||||
private readonly string host_;
|
private readonly string host_;
|
||||||
private readonly int port_;
|
private readonly int port_;
|
||||||
private readonly byte[] buf_ = new byte[10000];
|
|
||||||
private readonly Queue<MtMessage> pendingMessages_ = [];
|
private readonly Queue<MtMessage> pendingMessages_ = [];
|
||||||
|
|
||||||
private readonly Thread receiveThread_;
|
private readonly Thread receiveThread_;
|
||||||
@@ -296,18 +300,19 @@ namespace MtClient
|
|||||||
private readonly EventWaitHandle sendWaiter_ = new AutoResetEvent(false);
|
private readonly EventWaitHandle sendWaiter_ = new AutoResetEvent(false);
|
||||||
|
|
||||||
private int nextCommandId = 0;
|
private int nextCommandId = 0;
|
||||||
private readonly Dictionary<int, CommandTask> tasks_ = [];
|
private readonly Dictionary<int, CommandTask<string>> tasks_ = [];
|
||||||
|
private readonly Dictionary<ServiceRequestType, CommandTask<object>> service_requests_ = [];
|
||||||
|
|
||||||
private readonly IRpcLogger logger_;
|
private readonly IRpcLogger logger_;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CommandTask
|
internal class CommandTask<T>
|
||||||
{
|
{
|
||||||
private readonly EventWaitHandle responseWaiter_ = new AutoResetEvent(false);
|
private readonly EventWaitHandle responseWaiter_ = new AutoResetEvent(false);
|
||||||
private string? response_;
|
private T? response_;
|
||||||
private readonly object locker_ = new();
|
private readonly object locker_ = new();
|
||||||
|
|
||||||
public string? WaitResponse(int time)
|
public T? WaitResponse(int time)
|
||||||
{
|
{
|
||||||
responseWaiter_.WaitOne(time);
|
responseWaiter_.WaitOne(time);
|
||||||
lock (locker_)
|
lock (locker_)
|
||||||
@@ -316,7 +321,7 @@ namespace MtClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResponse(string result)
|
public void SetResponse(T result)
|
||||||
{
|
{
|
||||||
lock (locker_)
|
lock (locker_)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ void MtConnection::OnRead(
|
|||||||
return;
|
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)
|
if (ec)
|
||||||
{
|
{
|
||||||
log_.Error("%s: %s", __FUNCTION__, ec.message().c_str());
|
log_.Error("%s: %s", __FUNCTION__, ec.message().c_str());
|
||||||
|
|||||||
@@ -44,6 +44,5 @@ private:
|
|||||||
std::string host_;
|
std::string host_;
|
||||||
std::string read_text_;
|
std::string read_text_;
|
||||||
boost::beast::flat_buffer read_buffer_;
|
boost::beast::flat_buffer read_buffer_;
|
||||||
//std::string send_text_;
|
|
||||||
std::queue<std::string> send_queue_;
|
std::queue<std::string> send_queue_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ std::unique_ptr<MtCommand> MtCommand::Parse(const std::string& msg)
|
|||||||
return command;
|
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(';');
|
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>;
|
using rule = qi::rule<std::string::const_iterator>;
|
||||||
|
|
||||||
std::string message_type;
|
std::string message_type;
|
||||||
std::string notification_type;
|
std::string request_type;
|
||||||
|
|
||||||
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
|
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 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);
|
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -notification_type_p);
|
||||||
if (ok)
|
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
@@ -14,12 +14,12 @@ enum MessageType
|
|||||||
EXPERT_LIST = 3,
|
EXPERT_LIST = 3,
|
||||||
EXPERT_ADDED = 4,
|
EXPERT_ADDED = 4,
|
||||||
EXPERT_REMOVED = 5,
|
EXPERT_REMOVED = 5,
|
||||||
NOTIFICATION = 6
|
SERVICE_REQUEST = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NotificationType
|
enum ServiceRequestType
|
||||||
{
|
{
|
||||||
CLIENT_READY = 0
|
EXPERTS = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtMessage
|
class MtMessage
|
||||||
@@ -111,25 +111,25 @@ private:
|
|||||||
std::string payload_;
|
std::string payload_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtNotification : public MtMessage
|
class MtServiceRequest : public MtMessage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MtNotification(NotificationType type)
|
MtServiceRequest(ServiceRequestType type)
|
||||||
: notification_type_(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:
|
private:
|
||||||
MessageType GetType() const override
|
MessageType GetType() const override
|
||||||
{
|
{
|
||||||
return MessageType::NOTIFICATION;
|
return MessageType::SERVICE_REQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetBody() const override
|
std::string GetBody() const override
|
||||||
@@ -137,7 +137,7 @@ private:
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType notification_type_;
|
ServiceRequestType request_type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MtEvent : public MtMessage
|
class MtEvent : public MtMessage
|
||||||
|
|||||||
@@ -288,12 +288,12 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
|
|||||||
else
|
else
|
||||||
log_.Warning("%s: Failed to parse command from message: %s", __FUNCTION__, msg.c_str());
|
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);
|
auto request = MtServiceRequest::Parse(msg);
|
||||||
if (notification)
|
if (request)
|
||||||
{
|
{
|
||||||
if (notification->GetNotificationType() == NotificationType::CLIENT_READY)
|
if (request->GetServiceRequestType() == ServiceRequestType::EXPERTS)
|
||||||
{
|
{
|
||||||
std::vector<int> expert_list;
|
std::vector<int> expert_list;
|
||||||
for (const auto& e : experts_)
|
for (const auto& e : experts_)
|
||||||
@@ -306,7 +306,7 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|||||||
@@ -166,6 +166,8 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Label Grid.Row="0" Content="Quotes" Background="LightYellow" />
|
<Label Grid.Row="0" Content="Quotes" Background="LightYellow" />
|
||||||
<ListView Grid.Row="1" Margin="2"
|
<ListView Grid.Row="1" Margin="2"
|
||||||
@@ -181,6 +183,12 @@
|
|||||||
</GridView>
|
</GridView>
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
</ListView>
|
</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>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -473,22 +481,34 @@
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem Header="Market Info">
|
<TabItem Header="Market Info">
|
||||||
<WrapPanel VerticalAlignment="Top" Margin="5">
|
<Grid>
|
||||||
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
|
<Grid.RowDefinitions>
|
||||||
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<Button Command="{Binding SymbolSelectCommand}" Content="SymbolSelect" Margin="2"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
|
<RowDefinition Height="*"/>
|
||||||
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
|
</Grid.RowDefinitions>
|
||||||
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
|
<WrapPanel Grid.Row="0" VerticalAlignment="Top" Margin="5">
|
||||||
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
|
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
|
||||||
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
|
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
|
||||||
<Button Command="{Binding SymbolInfoTickCommand}" Content="SymbolInfoTick" Margin="2"/>
|
<Button Command="{Binding SymbolSelectCommand}" Content="SymbolSelect" Margin="2"/>
|
||||||
<Button Command="{Binding SymbolInfoSessionQuoteCommand}" Content="SymbolInfoSessionQuote" Margin="2"/>
|
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
|
||||||
<Button Command="{Binding SymbolInfoSessionTradeCommand}" Content="SymbolInfoSessionTrade" Margin="2"/>
|
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
|
||||||
<Button Command="{Binding MarketBookAddCommand}" Content="MarketBookAdd" Margin="2"/>
|
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
|
||||||
<Button Command="{Binding MarketBookReleaseCommand}" Content="MarketBookRelease" Margin="2"/>
|
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
|
||||||
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
|
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
|
||||||
</WrapPanel>
|
<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>
|
||||||
|
|
||||||
<TabItem Header="CTrade (Positions)">
|
<TabItem Header="CTrade (Positions)">
|
||||||
|
|||||||
@@ -160,6 +160,11 @@ namespace MtApi5TestClient
|
|||||||
public DelegateCommand GlobalVariablesTotalCommand { get; private set; }
|
public DelegateCommand GlobalVariablesTotalCommand { get; private set; }
|
||||||
|
|
||||||
public DelegateCommand UnlockTicksCommand { 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
|
#endregion
|
||||||
|
|
||||||
#region Properties
|
#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>();
|
public ObservableCollection<QuoteViewModel> Quotes { get; } = new ObservableCollection<QuoteViewModel>();
|
||||||
|
|
||||||
private QuoteViewModel _selectedQuote;
|
private QuoteViewModel _selectedQuote;
|
||||||
@@ -314,6 +330,19 @@ namespace MtApi5TestClient
|
|||||||
OnPropertyChanged("PositionTicketValue");
|
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
|
#endregion
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
@@ -334,6 +363,7 @@ namespace MtApi5TestClient
|
|||||||
ConnectionState = _mtApiClient.ConnectionState;
|
ConnectionState = _mtApiClient.ConnectionState;
|
||||||
ConnectionMessage = "Disconnected";
|
ConnectionMessage = "Disconnected";
|
||||||
Port = 8228; //default local port
|
Port = 8228; //default local port
|
||||||
|
CommandTimeout = _mtApiClient.CommandTimeout;
|
||||||
|
|
||||||
InitCommands();
|
InitCommands();
|
||||||
|
|
||||||
@@ -475,6 +505,11 @@ namespace MtApi5TestClient
|
|||||||
GlobalVariablesTotalCommand = new DelegateCommand(ExecuteGlobalVariablesTotal);
|
GlobalVariablesTotalCommand = new DelegateCommand(ExecuteGlobalVariablesTotal);
|
||||||
|
|
||||||
UnlockTicksCommand = new DelegateCommand(ExecuteUnlockTicks);
|
UnlockTicksCommand = new DelegateCommand(ExecuteUnlockTicks);
|
||||||
|
|
||||||
|
GetSymbolsCommand = new DelegateCommand(ExecuteGetSymbols);
|
||||||
|
RefreshQuotesCommand = new DelegateCommand(ExecuteRefreshQuotes);
|
||||||
|
|
||||||
|
TimeoutApplyCommand = new DelegateCommand(ExecuteTimeoutApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanExecuteConnect(object o)
|
private bool CanExecuteConnect(object o)
|
||||||
@@ -1054,7 +1089,7 @@ namespace MtApi5TestClient
|
|||||||
{
|
{
|
||||||
foreach (var v in result)
|
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);
|
TimeSeriesResults.Add(tickStr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1142,6 +1177,7 @@ namespace MtApi5TestClient
|
|||||||
AddLog($"SymbolInfoTick(EURUSD) tick.last = {result.last}");
|
AddLog($"SymbolInfoTick(EURUSD) tick.last = {result.last}");
|
||||||
AddLog($"SymbolInfoTick(EURUSD) tick.volume = {result.volume}");
|
AddLog($"SymbolInfoTick(EURUSD) tick.volume = {result.volume}");
|
||||||
AddLog($"SymbolInfoTick(EURUSD) tick.volume_real = {result.volume_real}");
|
AddLog($"SymbolInfoTick(EURUSD) tick.volume_real = {result.volume_real}");
|
||||||
|
AddLog($"SymbolInfoTick(EURUSD) tick.flags = {result.flags}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ExecuteSymbolInfoSessionQuote(object o)
|
private async void ExecuteSymbolInfoSessionQuote(object o)
|
||||||
@@ -1726,6 +1762,39 @@ namespace MtApi5TestClient
|
|||||||
_mtApiClient.UnlockTicks();
|
_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)
|
private static void RunOnUiThread(Action action)
|
||||||
{
|
{
|
||||||
Application.Current?.Dispatcher.Invoke(action);
|
Application.Current?.Dispatcher.Invoke(action);
|
||||||
@@ -1804,7 +1873,7 @@ namespace MtApi5TestClient
|
|||||||
|
|
||||||
private void _mtApiClient_OnLastTimeBar(object sender, Mt5TimeBarArgs e)
|
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)
|
private void _mtApiClient_OnLockTicks(object sender, Mt5LockTicksEventArgs e)
|
||||||
|
|||||||
+1860
-1724
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,16 @@
|
|||||||
using System;
|
using MtApi;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Globalization;
|
|
||||||
using MtApi;
|
|
||||||
using MtApi.Monitors;
|
using MtApi.Monitors;
|
||||||
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace TestApiClientUI
|
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
|
public partial class Form1 : Form
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
private readonly List<Action> _groupOrderCommands = [];
|
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 TimerTradeMonitor _timerTradeMonitor;
|
||||||
private readonly TimeframeTradeMonitor _timeframeTradeMonitor;
|
private readonly TimeframeTradeMonitor _timeframeTradeMonitor;
|
||||||
|
|
||||||
@@ -742,7 +707,7 @@ namespace TestApiClientUI
|
|||||||
|
|
||||||
var symbol = textBoxOrderSymbol.Text;
|
var symbol = textBoxOrderSymbol.Text;
|
||||||
|
|
||||||
var cmd = (TradeOperation) comboBoxOrderCommand.SelectedIndex;
|
var cmd = (TradeOperation)comboBoxOrderCommand.SelectedIndex;
|
||||||
|
|
||||||
double volume;
|
double volume;
|
||||||
double.TryParse(textBoxOrderVolume.Text, out volume);
|
double.TryParse(textBoxOrderVolume.Text, out volume);
|
||||||
@@ -750,7 +715,7 @@ namespace TestApiClientUI
|
|||||||
double price;
|
double price;
|
||||||
double.TryParse(textBoxOrderPrice.Text, out price);
|
double.TryParse(textBoxOrderPrice.Text, out price);
|
||||||
|
|
||||||
var slippage = (int) numericOrderSlippage.Value;
|
var slippage = (int)numericOrderSlippage.Value;
|
||||||
|
|
||||||
double stoploss;
|
double stoploss;
|
||||||
double.TryParse(textBoxOrderStoploss.Text, out stoploss);
|
double.TryParse(textBoxOrderStoploss.Text, out stoploss);
|
||||||
@@ -805,8 +770,8 @@ namespace TestApiClientUI
|
|||||||
private async void button16_Click(object sender, EventArgs e)
|
private async void button16_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var ticket = int.Parse(textBoxIndexTicket.Text);
|
var ticket = int.Parse(textBoxIndexTicket.Text);
|
||||||
var selectMode = (OrderSelectMode) comboBox1.SelectedIndex;
|
var selectMode = (OrderSelectMode)comboBox1.SelectedIndex;
|
||||||
var selectSource = (OrderSelectSource) comboBox2.SelectedIndex;
|
var selectSource = (OrderSelectSource)comboBox2.SelectedIndex;
|
||||||
|
|
||||||
var order = await Execute(() => _apiClient.GetOrder(ticket, selectMode, selectSource));
|
var order = await Execute(() => _apiClient.GetOrder(ticket, selectMode, selectSource));
|
||||||
|
|
||||||
@@ -1120,12 +1085,12 @@ namespace TestApiClientUI
|
|||||||
{
|
{
|
||||||
if (e.Opened != null)
|
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)
|
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 result1 = {result1}, time = {time1}");
|
||||||
PrintLog($"iBarShift result2 = {result2}, time = {time2}");
|
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}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</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>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
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
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
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
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
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
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
||||||
|
|||||||
Executable
+36
@@ -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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
+47
-9
@@ -1330,6 +1330,9 @@ int ExecuteCommand()
|
|||||||
case 290: //GetQuote
|
case 290: //GetQuote
|
||||||
response = Execute_GetQuote();
|
response = Execute_GetQuote();
|
||||||
break;
|
break;
|
||||||
|
case 291: //GetSymbols
|
||||||
|
response = Execute_GetSymbols();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Print("WARNING: Unknown command type = ", command_type);
|
Print("WARNING: Unknown command type = ", command_type);
|
||||||
@@ -2269,7 +2272,7 @@ string Execute_iBands()
|
|||||||
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
|
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
|
||||||
GET_INT_JSON_VALUE(jo, "Timeframe", timeframe);
|
GET_INT_JSON_VALUE(jo, "Timeframe", timeframe);
|
||||||
GET_INT_JSON_VALUE(jo, "Period", period);
|
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, "BandsShift", bands_shift);
|
||||||
GET_INT_JSON_VALUE(jo, "AppliedPrice", applied_price);
|
GET_INT_JSON_VALUE(jo, "AppliedPrice", applied_price);
|
||||||
GET_INT_JSON_VALUE(jo, "Mode", mode);
|
GET_INT_JSON_VALUE(jo, "Mode", mode);
|
||||||
@@ -2284,7 +2287,7 @@ string Execute_iBandsOnArray()
|
|||||||
GET_JSON_PAYLOAD(jo);
|
GET_JSON_PAYLOAD(jo);
|
||||||
GET_INT_JSON_VALUE(jo, "Total", total);
|
GET_INT_JSON_VALUE(jo, "Total", total);
|
||||||
GET_INT_JSON_VALUE(jo, "Period", period);
|
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, "BandsShift", bands_shift);
|
||||||
GET_INT_JSON_VALUE(jo, "Mode", mode);
|
GET_INT_JSON_VALUE(jo, "Mode", mode);
|
||||||
GET_INT_JSON_VALUE(jo, "Shift", shift);
|
GET_INT_JSON_VALUE(jo, "Shift", shift);
|
||||||
@@ -3792,16 +3795,25 @@ bool OrderCloseAll()
|
|||||||
{
|
{
|
||||||
if (OrderSelect(i, SELECT_BY_POS))
|
if (OrderSelect(i, SELECT_BY_POS))
|
||||||
{
|
{
|
||||||
int type = OrderType();
|
int type = OrderType();
|
||||||
|
bool order_closed = true;
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
//Close opened long positions
|
//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;
|
break;
|
||||||
|
}
|
||||||
//Close opened short positions
|
//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;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (order_closed == false)
|
||||||
|
Print("Failed to close order ", OrderTicket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3961,10 +3973,8 @@ string Execute_iCustom()
|
|||||||
{
|
{
|
||||||
int intParams[];
|
int intParams[];
|
||||||
ArrayResize(intParams, size);
|
ArrayResize(intParams, size);
|
||||||
for (int i = 0; i < size; i++)
|
for (int it_i = 0; it_i < size; it_i++)
|
||||||
{
|
intParams[it_i] = jaParams.getInt(it_i);
|
||||||
intParams[i] = jaParams.getInt(i);
|
|
||||||
}
|
|
||||||
result = iCustomT(symbol, timeframe, name, intParams, size, mode, shift);
|
result = iCustomT(symbol, timeframe, name, intParams, size, mode, shift);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3972,6 +3982,8 @@ string Execute_iCustom()
|
|||||||
{
|
{
|
||||||
double doubleParams[];
|
double doubleParams[];
|
||||||
ArrayResize(doubleParams, size);
|
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);
|
result = iCustomT(symbol, timeframe, name, doubleParams, size, mode, shift);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3979,6 +3991,8 @@ string Execute_iCustom()
|
|||||||
{
|
{
|
||||||
string stringParams[];
|
string stringParams[];
|
||||||
ArrayResize(stringParams, size);
|
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);
|
result = iCustomT(symbol, timeframe, name, stringParams, size, mode, shift);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3986,6 +4000,8 @@ string Execute_iCustom()
|
|||||||
{
|
{
|
||||||
bool boolParams[];
|
bool boolParams[];
|
||||||
ArrayResize(boolParams, size);
|
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);
|
result = iCustomT(symbol, timeframe, name, boolParams, size, mode, shift);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -4183,3 +4199,25 @@ string Execute_GetQuote()
|
|||||||
MtQuote quote(Symbol(), tick);
|
MtQuote quote(Symbol(), tick);
|
||||||
return CreateSuccessResponse(quote.CreateJson());
|
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
Binary file not shown.
+60
-13
@@ -1,7 +1,7 @@
|
|||||||
#property copyright "Vyacheslav Demidyuk"
|
#property copyright "Vyacheslav Demidyuk"
|
||||||
#property link ""
|
#property link ""
|
||||||
|
|
||||||
#property version "2.0"
|
#property version "2.1"
|
||||||
#property description "MtApi (MT5) connection expert"
|
#property description "MtApi (MT5) connection expert"
|
||||||
|
|
||||||
#include <json.mqh>
|
#include <json.mqh>
|
||||||
@@ -82,7 +82,7 @@ void OnTick()
|
|||||||
MqlRates rates_array[];
|
MqlRates rates_array[];
|
||||||
CopyRates(symbol, Period(), 1, 1, 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);
|
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
|
||||||
}
|
}
|
||||||
lastbar_time_changed = true;
|
lastbar_time_changed = true;
|
||||||
@@ -380,6 +380,7 @@ int preinit()
|
|||||||
ADD_EXECUTOR(303, OrderCheck);
|
ADD_EXECUTOR(303, OrderCheck);
|
||||||
ADD_EXECUTOR(304, Buy);
|
ADD_EXECUTOR(304, Buy);
|
||||||
ADD_EXECUTOR(305, Sell);
|
ADD_EXECUTOR(305, Sell);
|
||||||
|
ADD_EXECUTOR(306, GetSymbols);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -408,14 +409,14 @@ int init()
|
|||||||
isCrashed = true;
|
isCrashed = true;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
if (MQL5InfoInteger(MQL5_DLLS_ALLOWED) == false)
|
if (MQLInfoInteger(MQL_DLLS_ALLOWED) == false)
|
||||||
{
|
{
|
||||||
MessageBox("Libraries not allowed.", "MtApi", 0);
|
MessageBox("Libraries not allowed.", "MtApi", 0);
|
||||||
isCrashed = true;
|
isCrashed = true;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MQL5InfoInteger(MQL5_TRADE_ALLOWED) == false)
|
if (MQLInfoInteger(MQL_TRADE_ALLOWED) == false)
|
||||||
{
|
{
|
||||||
MessageBox("Trade not allowed.", "MtApi", 0);
|
MessageBox("Trade not allowed.", "MtApi", 0);
|
||||||
isCrashed = true;
|
isCrashed = true;
|
||||||
@@ -1829,7 +1830,7 @@ string Execute_ObjectCreate()
|
|||||||
|
|
||||||
datetime times[30];
|
datetime times[30];
|
||||||
double prices[30];
|
double prices[30];
|
||||||
ArrayInitialize(times, EMPTY_VALUE);
|
ArrayInitialize(times, 0);
|
||||||
ArrayInitialize(prices, EMPTY_VALUE);
|
ArrayInitialize(prices, EMPTY_VALUE);
|
||||||
|
|
||||||
JSONArray* times_jo = jo.p.getArray("Times");
|
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, "Period", period);
|
||||||
GET_INT_JSON_VALUE(jo, "FastMaPeriod", fast_ma_period);
|
GET_INT_JSON_VALUE(jo, "FastMaPeriod", fast_ma_period);
|
||||||
GET_INT_JSON_VALUE(jo, "SlowMaPeriod", slow_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);
|
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));
|
return CreateSuccessResponse(new JSONNumber(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2377,7 +2378,7 @@ string Execute_iSAR()
|
|||||||
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
|
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
|
||||||
GET_INT_JSON_VALUE(jo, "Period", period);
|
GET_INT_JSON_VALUE(jo, "Period", period);
|
||||||
GET_DOUBLE_JSON_VALUE(jo, "Step", step);
|
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);
|
int result = iSAR(symbol, (ENUM_TIMEFRAMES)period, step, maximum);
|
||||||
return CreateSuccessResponse(new JSONNumber(result));
|
return CreateSuccessResponse(new JSONNumber(result));
|
||||||
@@ -2959,6 +2960,7 @@ string Execute_UnlockTicks()
|
|||||||
return CreateErrorResponse(-1, "UnlockTicks can be used only for backtesting");
|
return CreateErrorResponse(-1, "UnlockTicks can be used only for backtesting");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_is_ticks_locked = false;
|
||||||
return CreateSuccessResponse();
|
return CreateSuccessResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3065,15 +3067,15 @@ string Execute_iCustom()
|
|||||||
int intParams[];
|
int intParams[];
|
||||||
ArrayResize(intParams, size);
|
ArrayResize(intParams, size);
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
|
||||||
intParams[i] = jaParams.getInt(i);
|
intParams[i] = jaParams.getInt(i);
|
||||||
}
|
|
||||||
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, intParams, size);
|
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, intParams, size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: //Double
|
case 1: //Double
|
||||||
{
|
{
|
||||||
int doubleParams[];
|
double doubleParams[];
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
doubleParams[i] = jaParams.getDouble(i);
|
||||||
ArrayResize(doubleParams, size);
|
ArrayResize(doubleParams, size);
|
||||||
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, doubleParams, size);
|
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, doubleParams, size);
|
||||||
}
|
}
|
||||||
@@ -3082,13 +3084,17 @@ string Execute_iCustom()
|
|||||||
{
|
{
|
||||||
string stringParams[];
|
string stringParams[];
|
||||||
ArrayResize(stringParams, size);
|
ArrayResize(stringParams, size);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
stringParams[i] = jaParams.getString(i);
|
||||||
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, stringParams, size);
|
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, stringParams, size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: //Boolean
|
case 3: //Boolean
|
||||||
{
|
{
|
||||||
string boolParams[];
|
bool boolParams[];
|
||||||
ArrayResize(boolParams, size);
|
ArrayResize(boolParams, size);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
boolParams[i] = jaParams.getBool(i);
|
||||||
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, boolParams, size);
|
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, boolParams, size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3446,6 +3452,28 @@ string Execute_Sell()
|
|||||||
return CreateSuccessResponse(result_value_jo);
|
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()
|
int PositionCloseAll()
|
||||||
{
|
{
|
||||||
CTrade trade;
|
CTrade trade;
|
||||||
@@ -3635,9 +3663,10 @@ private:
|
|||||||
class MtTimeBarEvent: public MtObject
|
class MtTimeBarEvent: public MtObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MtTimeBarEvent(string symbol, const MqlRates& rates)
|
MtTimeBarEvent(string symbol, int timeframe, const MqlRates& rates)
|
||||||
{
|
{
|
||||||
_symbol = symbol;
|
_symbol = symbol;
|
||||||
|
_timeframe = timeframe;
|
||||||
_rates = rates;
|
_rates = rates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3646,12 +3675,14 @@ public:
|
|||||||
JSONObject *jo = new JSONObject();
|
JSONObject *jo = new JSONObject();
|
||||||
jo.put("Rates", MqlRatesToJson(_rates));
|
jo.put("Rates", MqlRatesToJson(_rates));
|
||||||
jo.put("Instrument", new JSONString(_symbol));
|
jo.put("Instrument", new JSONString(_symbol));
|
||||||
|
jo.put("Timeframe", new JSONNumber(_timeframe));
|
||||||
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
|
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
|
||||||
return jo;
|
return jo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string _symbol;
|
string _symbol;
|
||||||
|
int _timeframe;
|
||||||
MqlRates _rates;
|
MqlRates _rates;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3774,6 +3805,21 @@ bool JsonToMqlTradeRequest(JSONObject *jo, MqlTradeRequest& request)
|
|||||||
|
|
||||||
JSONObject* MqlTickToJson(const MqlTick& tick)
|
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();
|
JSONObject *jo = new JSONObject();
|
||||||
jo.put("Time", new JSONNumber((long)tick.time));
|
jo.put("Time", new JSONNumber((long)tick.time));
|
||||||
jo.put("Bid", new JSONNumber(tick.bid));
|
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("Last", new JSONNumber(tick.last));
|
||||||
jo.put("Volume", new JSONNumber(tick.volume));
|
jo.put("Volume", new JSONNumber(tick.volume));
|
||||||
jo.put("VolumeReal", new JSONNumber(tick.volume_real));
|
jo.put("VolumeReal", new JSONNumber(tick.volume_real));
|
||||||
|
jo.put("Flags", new JSONNumber(summ));
|
||||||
return jo;
|
return jo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -324,27 +324,27 @@ public:
|
|||||||
/// Lookup key and get associated string value, return false if failure.
|
/// Lookup key and get associated string value, return false if failure.
|
||||||
bool getString(string key,string &out)
|
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.
|
/// Lookup key and get associated bool value, return false if failure.
|
||||||
bool getBool(string key,bool &out)
|
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.
|
/// Lookup key and get associated double value, return false if failure.
|
||||||
bool getDouble(string key,double &out)
|
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.
|
/// Lookup key and get associated long value, return false if failure.
|
||||||
bool getLong(string key,long &out)
|
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.
|
/// Lookup key and get associated int value, return false if failure.
|
||||||
bool getInt(string key,int &out)
|
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.
|
/// 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.
|
/// Lookup JSONString by array index. NULL if not present. Cast failure if not an Object.
|
||||||
bool getString(int index,string &out)
|
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.
|
/// Lookup JSONBool by array index. NULL if not present. Cast failure if not an Object.
|
||||||
bool getBool(int index,bool &out)
|
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.
|
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
|
||||||
bool getDouble(int index,double &out)
|
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.
|
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
|
||||||
bool getLong(int index,long &out)
|
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.
|
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
|
||||||
bool getInt(int index,int &out)
|
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.
|
/// Lookup array child by index, NULL if not present. Cast failure if not an Array.
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// Boost.Bimap
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2007 Matias Capeletto
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
/// \file detail/debug/static_error.hpp
|
||||||
|
/// \brief Formatted compile time error
|
||||||
|
|
||||||
|
#ifndef BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
|
||||||
|
#define BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/mpl/assert.hpp>
|
||||||
|
#include <boost/preprocessor/cat.hpp>
|
||||||
|
|
||||||
|
// Easier way to call BOOST_MPL_ASSERT_MSG in class scope to generate
|
||||||
|
// a static error.
|
||||||
|
/*===========================================================================*/
|
||||||
|
#define BOOST_BIMAP_STATIC_ERROR(MESSAGE,VARIABLES) \
|
||||||
|
BOOST_MPL_ASSERT_MSG(false, \
|
||||||
|
BOOST_PP_CAT(BIMAP_STATIC_ERROR__,MESSAGE), \
|
||||||
|
VARIABLES)
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Copyright Rene Rivera 2008-2015
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_PREDEF_ARCHITECTURE_X86_32_H
|
||||||
|
#define BOOST_PREDEF_ARCHITECTURE_X86_32_H
|
||||||
|
|
||||||
|
#include <boost/predef/version_number.h>
|
||||||
|
#include <boost/predef/make.h>
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_ARCH_X86_32`
|
||||||
|
|
||||||
|
http://en.wikipedia.org/wiki/X86[Intel x86] architecture:
|
||||||
|
If available versions [3-6] are specifically detected.
|
||||||
|
|
||||||
|
[options="header"]
|
||||||
|
|===
|
||||||
|
| {predef_symbol} | {predef_version}
|
||||||
|
|
||||||
|
| `i386` | {predef_detection}
|
||||||
|
| `+__i386__+` | {predef_detection}
|
||||||
|
| `+__i486__+` | {predef_detection}
|
||||||
|
| `+__i586__+` | {predef_detection}
|
||||||
|
| `+__i686__+` | {predef_detection}
|
||||||
|
| `+__i386+` | {predef_detection}
|
||||||
|
| `+_M_IX86+` | {predef_detection}
|
||||||
|
| `+_X86_+` | {predef_detection}
|
||||||
|
| `+__THW_INTEL__+` | {predef_detection}
|
||||||
|
| `+__I86__+` | {predef_detection}
|
||||||
|
| `+__INTEL__+` | {predef_detection}
|
||||||
|
|
||||||
|
| `+__I86__+` | V.0.0
|
||||||
|
| `+_M_IX86+` | V.0.0
|
||||||
|
| `+__i686__+` | 6.0.0
|
||||||
|
| `+__i586__+` | 5.0.0
|
||||||
|
| `+__i486__+` | 4.0.0
|
||||||
|
| `+__i386__+` | 3.0.0
|
||||||
|
|===
|
||||||
|
*/ // end::reference[]
|
||||||
|
|
||||||
|
#define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER_NOT_AVAILABLE
|
||||||
|
|
||||||
|
#if defined(i386) || defined(__i386__) || \
|
||||||
|
defined(__i486__) || defined(__i586__) || \
|
||||||
|
defined(__i686__) || defined(__i386) || \
|
||||||
|
defined(_M_IX86) || defined(_X86_) || \
|
||||||
|
defined(__THW_INTEL__) || defined(__I86__) || \
|
||||||
|
defined(__INTEL__)
|
||||||
|
# undef BOOST_ARCH_X86_32
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(__I86__)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(__I86__,0,0)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(_M_IX86)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_PREDEF_MAKE_10_VV00(_M_IX86)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(__i686__)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(6,0,0)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(__i586__)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(5,0,0)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(__i486__)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(4,0,0)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32) && defined(__i386__)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(3,0,0)
|
||||||
|
# endif
|
||||||
|
# if !defined(BOOST_ARCH_X86_32)
|
||||||
|
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER_AVAILABLE
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOST_ARCH_X86_32
|
||||||
|
# define BOOST_ARCH_X86_32_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOST_ARCH_X86_32
|
||||||
|
# undef BOOST_ARCH_WORD_BITS_32
|
||||||
|
# define BOOST_ARCH_WORD_BITS_32 BOOST_VERSION_NUMBER_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOST_ARCH_X86_32_NAME "Intel x86-32"
|
||||||
|
|
||||||
|
#include <boost/predef/architecture/x86.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/predef/detail/test.h>
|
||||||
|
BOOST_PREDEF_DECLARE_TEST(BOOST_ARCH_X86_32,BOOST_ARCH_X86_32_NAME)
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright Rene Rivera 2008-2021
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_PREDEF_ARCHITECTURE_X86_64_H
|
||||||
|
#define BOOST_PREDEF_ARCHITECTURE_X86_64_H
|
||||||
|
|
||||||
|
#include <boost/predef/version_number.h>
|
||||||
|
#include <boost/predef/make.h>
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_ARCH_X86_64`
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/X86-64[X86-64] architecture.
|
||||||
|
|
||||||
|
[options="header"]
|
||||||
|
|===
|
||||||
|
| {predef_symbol} | {predef_version}
|
||||||
|
|
||||||
|
| `+__x86_64+` | {predef_detection}
|
||||||
|
| `+__x86_64__+` | {predef_detection}
|
||||||
|
| `+__amd64__+` | {predef_detection}
|
||||||
|
| `+__amd64+` | {predef_detection}
|
||||||
|
| `+_M_X64+` | {predef_detection}
|
||||||
|
|===
|
||||||
|
*/ // end::reference[]
|
||||||
|
|
||||||
|
#define BOOST_ARCH_X86_64 BOOST_VERSION_NUMBER_NOT_AVAILABLE
|
||||||
|
|
||||||
|
#if defined(__x86_64) || defined(__x86_64__) || \
|
||||||
|
defined(__amd64__) || defined(__amd64) || \
|
||||||
|
defined(_M_X64)
|
||||||
|
# undef BOOST_ARCH_X86_64
|
||||||
|
# define BOOST_ARCH_X86_64 BOOST_VERSION_NUMBER_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOST_ARCH_X86_64
|
||||||
|
# define BOOST_ARCH_X86_64_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOST_ARCH_X86_64
|
||||||
|
# undef BOOST_ARCH_WORD_BITS_64
|
||||||
|
# define BOOST_ARCH_WORD_BITS_64 BOOST_VERSION_NUMBER_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOST_ARCH_X86_64_NAME "Intel x86-64"
|
||||||
|
|
||||||
|
#include <boost/predef/architecture/x86.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/predef/detail/test.h>
|
||||||
|
BOOST_PREDEF_DECLARE_TEST(BOOST_ARCH_X86_64,BOOST_ARCH_X86_64_NAME)
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
Copyright Charly Chevalier 2015
|
||||||
|
Copyright Joel Falcou 2015
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_PREDEF_HARDWARE_SIMD_X86_VERSIONS_H
|
||||||
|
#define BOOST_PREDEF_HARDWARE_SIMD_X86_VERSIONS_H
|
||||||
|
|
||||||
|
#include <boost/predef/version_number.h>
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_*_VERSION`
|
||||||
|
|
||||||
|
Those defines represent x86 SIMD extensions versions.
|
||||||
|
|
||||||
|
NOTE: You *MUST* compare them with the predef `BOOST_HW_SIMD_X86`.
|
||||||
|
*/ // end::reference[]
|
||||||
|
|
||||||
|
// ---------------------------------
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_MMX_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/MMX_(instruction_set)[MMX] x86 extension
|
||||||
|
version number.
|
||||||
|
|
||||||
|
Version number is: *0.99.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_MMX_VERSION BOOST_VERSION_NUMBER(0, 99, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSE_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions[SSE] x86 extension
|
||||||
|
version number.
|
||||||
|
|
||||||
|
Version number is: *1.0.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSE_VERSION BOOST_VERSION_NUMBER(1, 0, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSE2_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/SSE2[SSE2] x86 extension version number.
|
||||||
|
|
||||||
|
Version number is: *2.0.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSE2_VERSION BOOST_VERSION_NUMBER(2, 0, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSE3_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/SSE3[SSE3] x86 extension version number.
|
||||||
|
|
||||||
|
Version number is: *3.0.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSE3_VERSION BOOST_VERSION_NUMBER(3, 0, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSSE3_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/SSSE3[SSSE3] x86 extension version number.
|
||||||
|
|
||||||
|
Version number is: *3.1.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSSE3_VERSION BOOST_VERSION_NUMBER(3, 1, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSE4_1_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/SSE4#SSE4.1[SSE4_1] x86 extension version
|
||||||
|
number.
|
||||||
|
|
||||||
|
Version number is: *4.1.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSE4_1_VERSION BOOST_VERSION_NUMBER(4, 1, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_SSE4_2_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/SSE4##SSE4.2[SSE4_2] x86 extension version
|
||||||
|
number.
|
||||||
|
|
||||||
|
Version number is: *4.2.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_SSE4_2_VERSION BOOST_VERSION_NUMBER(4, 2, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_AVX_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/Advanced_Vector_Extensions[AVX] x86
|
||||||
|
extension version number.
|
||||||
|
|
||||||
|
Version number is: *5.0.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_AVX_VERSION BOOST_VERSION_NUMBER(5, 0, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_FMA3_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/FMA_instruction_set[FMA3] x86 extension
|
||||||
|
version number.
|
||||||
|
|
||||||
|
Version number is: *5.2.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_FMA3_VERSION BOOST_VERSION_NUMBER(5, 2, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_AVX2_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2[AVX2]
|
||||||
|
x86 extension version number.
|
||||||
|
|
||||||
|
Version number is: *5.3.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_AVX2_VERSION BOOST_VERSION_NUMBER(5, 3, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
= `BOOST_HW_SIMD_X86_MIC_VERSION`
|
||||||
|
|
||||||
|
The https://en.wikipedia.org/wiki/Xeon_Phi[MIC] (Xeon Phi) x86 extension
|
||||||
|
version number.
|
||||||
|
|
||||||
|
Version number is: *9.0.0*.
|
||||||
|
*/ // end::reference[]
|
||||||
|
#define BOOST_HW_SIMD_X86_MIC_VERSION BOOST_VERSION_NUMBER(9, 0, 0)
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
|
||||||
|
#endif
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
# /* Copyright (C) 2001
|
||||||
|
# * Housemarque Oy
|
||||||
|
# * http://www.housemarque.com
|
||||||
|
# *
|
||||||
|
# * Distributed under the Boost Software License, Version 1.0. (See
|
||||||
|
# * accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# * http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# */
|
||||||
|
#
|
||||||
|
# /* Revised by Paul Mensonides (2002) */
|
||||||
|
#
|
||||||
|
# /* See http://www.boost.org for most recent version. */
|
||||||
|
#
|
||||||
|
# ifndef BOOST_PREPROCESSOR_DEBUG_ASSERT_HPP
|
||||||
|
# define BOOST_PREPROCESSOR_DEBUG_ASSERT_HPP
|
||||||
|
#
|
||||||
|
# include <boost/preprocessor/config/config.hpp>
|
||||||
|
# include <boost/preprocessor/control/expr_iif.hpp>
|
||||||
|
# include <boost/preprocessor/control/iif.hpp>
|
||||||
|
# include <boost/preprocessor/logical/not.hpp>
|
||||||
|
# include <boost/preprocessor/tuple/eat.hpp>
|
||||||
|
#
|
||||||
|
# /* BOOST_PP_ASSERT */
|
||||||
|
#
|
||||||
|
# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG()
|
||||||
|
# define BOOST_PP_ASSERT BOOST_PP_ASSERT_D
|
||||||
|
# else
|
||||||
|
# define BOOST_PP_ASSERT(cond) BOOST_PP_ASSERT_D(cond)
|
||||||
|
# endif
|
||||||
|
#
|
||||||
|
# define BOOST_PP_ASSERT_D(cond) BOOST_PP_IIF(BOOST_PP_NOT(cond), BOOST_PP_ASSERT_ERROR, BOOST_PP_TUPLE_EAT_1)(...)
|
||||||
|
# define BOOST_PP_ASSERT_ERROR(x, y, z)
|
||||||
|
#
|
||||||
|
# /* BOOST_PP_ASSERT_MSG */
|
||||||
|
#
|
||||||
|
# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG()
|
||||||
|
# define BOOST_PP_ASSERT_MSG BOOST_PP_ASSERT_MSG_D
|
||||||
|
# else
|
||||||
|
# define BOOST_PP_ASSERT_MSG(cond, msg) BOOST_PP_ASSERT_MSG_D(cond, msg)
|
||||||
|
# endif
|
||||||
|
#
|
||||||
|
# define BOOST_PP_ASSERT_MSG_D(cond, msg) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(cond), msg)
|
||||||
|
#
|
||||||
|
# endif
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# /* **************************************************************************
|
||||||
|
# * *
|
||||||
|
# * (C) Copyright Paul Mensonides 2002.
|
||||||
|
# * Distributed under the Boost Software License, Version 1.0. (See
|
||||||
|
# * accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# * http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# * *
|
||||||
|
# ************************************************************************** */
|
||||||
|
#
|
||||||
|
# /* See http://www.boost.org for most recent version. */
|
||||||
|
#
|
||||||
|
# ifndef BOOST_PREPROCESSOR_DEBUG_ERROR_HPP
|
||||||
|
# define BOOST_PREPROCESSOR_DEBUG_ERROR_HPP
|
||||||
|
#
|
||||||
|
# include <boost/preprocessor/cat.hpp>
|
||||||
|
# include <boost/preprocessor/config/config.hpp>
|
||||||
|
#
|
||||||
|
# /* BOOST_PP_ERROR */
|
||||||
|
#
|
||||||
|
# if BOOST_PP_CONFIG_ERRORS
|
||||||
|
# define BOOST_PP_ERROR(code) BOOST_PP_CAT(BOOST_PP_ERROR_, code)
|
||||||
|
# endif
|
||||||
|
#
|
||||||
|
# define BOOST_PP_ERROR_0x0000 BOOST_PP_ERROR(0x0000, BOOST_PP_INDEX_OUT_OF_BOUNDS)
|
||||||
|
# define BOOST_PP_ERROR_0x0001 BOOST_PP_ERROR(0x0001, BOOST_PP_WHILE_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0002 BOOST_PP_ERROR(0x0002, BOOST_PP_FOR_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0003 BOOST_PP_ERROR(0x0003, BOOST_PP_REPEAT_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0004 BOOST_PP_ERROR(0x0004, BOOST_PP_LIST_FOLD_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0005 BOOST_PP_ERROR(0x0005, BOOST_PP_SEQ_FOLD_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0006 BOOST_PP_ERROR(0x0006, BOOST_PP_ARITHMETIC_OVERFLOW)
|
||||||
|
# define BOOST_PP_ERROR_0x0007 BOOST_PP_ERROR(0x0007, BOOST_PP_DIVISION_BY_ZERO)
|
||||||
|
#
|
||||||
|
# endif
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
# /* **************************************************************************
|
||||||
|
# * *
|
||||||
|
# * (C) Copyright Paul Mensonides 2002.
|
||||||
|
# * Distributed under the Boost Software License, Version 1.0. (See
|
||||||
|
# * accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# * http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# * *
|
||||||
|
# ************************************************************************** */
|
||||||
|
#
|
||||||
|
# /* See http://www.boost.org for most recent version. */
|
||||||
|
#
|
||||||
|
# ifndef BOOST_PREPROCESSOR_DEBUG_LINE_HPP
|
||||||
|
# define BOOST_PREPROCESSOR_DEBUG_LINE_HPP
|
||||||
|
#
|
||||||
|
# include <boost/preprocessor/cat.hpp>
|
||||||
|
# include <boost/preprocessor/config/config.hpp>
|
||||||
|
# include <boost/preprocessor/iteration/iterate.hpp>
|
||||||
|
# include <boost/preprocessor/stringize.hpp>
|
||||||
|
#
|
||||||
|
# /* BOOST_PP_LINE */
|
||||||
|
#
|
||||||
|
# if BOOST_PP_CONFIG_EXTENDED_LINE_INFO
|
||||||
|
# define BOOST_PP_LINE(line, file) line BOOST_PP_CAT(BOOST_PP_LINE_, BOOST_PP_IS_ITERATING)(file)
|
||||||
|
# define BOOST_PP_LINE_BOOST_PP_IS_ITERATING(file) #file
|
||||||
|
# define BOOST_PP_LINE_1(file) BOOST_PP_STRINGIZE(file BOOST_PP_CAT(BOOST_PP_LINE_I_, BOOST_PP_ITERATION_DEPTH())())
|
||||||
|
# define BOOST_PP_LINE_I_1() [BOOST_PP_FRAME_ITERATION(1)]
|
||||||
|
# define BOOST_PP_LINE_I_2() BOOST_PP_LINE_I_1()[BOOST_PP_FRAME_ITERATION(2)]
|
||||||
|
# define BOOST_PP_LINE_I_3() BOOST_PP_LINE_I_2()[BOOST_PP_FRAME_ITERATION(3)]
|
||||||
|
# define BOOST_PP_LINE_I_4() BOOST_PP_LINE_I_3()[BOOST_PP_FRAME_ITERATION(4)]
|
||||||
|
# define BOOST_PP_LINE_I_5() BOOST_PP_LINE_I_4()[BOOST_PP_FRAME_ITERATION(5)]
|
||||||
|
# else
|
||||||
|
# define BOOST_PP_LINE(line, file) line __FILE__
|
||||||
|
# endif
|
||||||
|
#
|
||||||
|
# endif
|
||||||
+319
@@ -0,0 +1,319 @@
|
|||||||
|
/*=============================================================================
|
||||||
|
Copyright (c) 2001-2003 Joel de Guzman
|
||||||
|
Copyright (c) 2002-2003 Hartmut Kaiser
|
||||||
|
Copyright (c) 2003 Gustavo Guerra
|
||||||
|
http://spirit.sourceforge.net/
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
=============================================================================*/
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_NODE_HPP)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_NODE_HPP
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP)
|
||||||
|
#error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/debug_node.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/type_traits/is_convertible.hpp>
|
||||||
|
#include <boost/mpl/if.hpp>
|
||||||
|
#include <boost/mpl/and.hpp>
|
||||||
|
#include <boost/spirit/home/classic/namespace.hpp>
|
||||||
|
#include <boost/spirit/home/classic/core/primitives/primitives.hpp> // for iscntrl_
|
||||||
|
|
||||||
|
namespace boost { namespace spirit {
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Debug helper classes for rules, which ensure maximum non-intrusiveness of
|
||||||
|
// the Spirit debug support
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
struct token_printer_aux_for_chars
|
||||||
|
{
|
||||||
|
template<typename CharT>
|
||||||
|
static void print(std::ostream& o, CharT c)
|
||||||
|
{
|
||||||
|
if (c == static_cast<CharT>('\a'))
|
||||||
|
o << "\\a";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\b'))
|
||||||
|
o << "\\b";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\f'))
|
||||||
|
o << "\\f";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\n'))
|
||||||
|
o << "\\n";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\r'))
|
||||||
|
o << "\\r";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\t'))
|
||||||
|
o << "\\t";
|
||||||
|
|
||||||
|
else if (c == static_cast<CharT>('\v'))
|
||||||
|
o << "\\v";
|
||||||
|
|
||||||
|
else if (iscntrl_(c))
|
||||||
|
o << "\\" << static_cast<int>(c);
|
||||||
|
|
||||||
|
else
|
||||||
|
o << static_cast<char>(c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// for token types where the comparison with char constants wouldn't work
|
||||||
|
struct token_printer_aux_for_other_types
|
||||||
|
{
|
||||||
|
template<typename CharT>
|
||||||
|
static void print(std::ostream& o, CharT c)
|
||||||
|
{
|
||||||
|
o << c;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
struct token_printer_aux
|
||||||
|
: mpl::if_<
|
||||||
|
mpl::and_<
|
||||||
|
is_convertible<CharT, char>,
|
||||||
|
is_convertible<char, CharT> >,
|
||||||
|
token_printer_aux_for_chars,
|
||||||
|
token_printer_aux_for_other_types
|
||||||
|
>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename CharT>
|
||||||
|
inline void token_printer(std::ostream& o, CharT c)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TOKEN_PRINTER)
|
||||||
|
|
||||||
|
token_printer_aux<CharT>::print(o, c);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
BOOST_SPIRIT_DEBUG_TOKEN_PRINTER(o, c);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Dump infos about the parsing state of a rule
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
template <typename IteratorT>
|
||||||
|
inline void
|
||||||
|
print_node_info(bool hit, int level, bool close, std::string const& name,
|
||||||
|
IteratorT first, IteratorT last)
|
||||||
|
{
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < level; ++i)
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << " ";
|
||||||
|
if (close)
|
||||||
|
{
|
||||||
|
if (hit)
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "/";
|
||||||
|
else
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "#";
|
||||||
|
}
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << name << ":\t\"";
|
||||||
|
IteratorT iter = first;
|
||||||
|
IteratorT ilast = last;
|
||||||
|
for (int j = 0; j < BOOST_SPIRIT_DEBUG_PRINT_SOME; ++j)
|
||||||
|
{
|
||||||
|
if (iter == ilast)
|
||||||
|
break;
|
||||||
|
|
||||||
|
token_printer(BOOST_SPIRIT_DEBUG_OUT, *iter);
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "\"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
|
||||||
|
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
|
||||||
|
template <typename ResultT>
|
||||||
|
inline ResultT &
|
||||||
|
print_closure_info(ResultT &hit, int level, std::string const& name)
|
||||||
|
{
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < level-1; ++i)
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << " ";
|
||||||
|
|
||||||
|
// for now, print out the return value only
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "^" << name << ":\t";
|
||||||
|
if (hit.has_valid_attribute())
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << hit.value();
|
||||||
|
else
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "undefined attribute";
|
||||||
|
BOOST_SPIRIT_DEBUG_OUT << "\n";
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Implementation note: The parser_context_linker, parser_scanner_linker and
|
||||||
|
// closure_context_linker classes are wrapped by a PP constant to allow
|
||||||
|
// redefinition of this classes outside of Spirit
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED)
|
||||||
|
#define BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// parser_context_linker is a debug wrapper for the ContextT template
|
||||||
|
// parameter of the rule<>, subrule<> and the grammar<> classes
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template<typename ContextT>
|
||||||
|
struct parser_context_linker : public ContextT
|
||||||
|
{
|
||||||
|
typedef ContextT base_t;
|
||||||
|
|
||||||
|
template <typename ParserT>
|
||||||
|
parser_context_linker(ParserT const& p)
|
||||||
|
: ContextT(p) {}
|
||||||
|
|
||||||
|
template <typename ParserT, typename ScannerT>
|
||||||
|
void pre_parse(ParserT const& p, ScannerT &scan)
|
||||||
|
{
|
||||||
|
this->base_t::pre_parse(p, scan);
|
||||||
|
|
||||||
|
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
if (trace_parser(p.derived())) {
|
||||||
|
impl::print_node_info(
|
||||||
|
false,
|
||||||
|
scan.get_level(),
|
||||||
|
false,
|
||||||
|
parser_name(p.derived()),
|
||||||
|
scan.first,
|
||||||
|
scan.last);
|
||||||
|
}
|
||||||
|
scan.get_level()++;
|
||||||
|
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ResultT, typename ParserT, typename ScannerT>
|
||||||
|
ResultT& post_parse(ResultT& hit, ParserT const& p, ScannerT &scan)
|
||||||
|
{
|
||||||
|
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
--scan.get_level();
|
||||||
|
if (trace_parser(p.derived())) {
|
||||||
|
impl::print_node_info(
|
||||||
|
hit,
|
||||||
|
scan.get_level(),
|
||||||
|
true,
|
||||||
|
parser_name(p.derived()),
|
||||||
|
scan.first,
|
||||||
|
scan.last);
|
||||||
|
}
|
||||||
|
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
|
||||||
|
|
||||||
|
return this->base_t::post_parse(hit, p, scan);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED)
|
||||||
|
#define BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This class is to avoid linker problems and to ensure a real singleton
|
||||||
|
// 'level' variable
|
||||||
|
struct debug_support
|
||||||
|
{
|
||||||
|
int& get_level()
|
||||||
|
{
|
||||||
|
static int level = 0;
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename ScannerT>
|
||||||
|
struct parser_scanner_linker : public ScannerT
|
||||||
|
{
|
||||||
|
parser_scanner_linker(ScannerT const &scan_) : ScannerT(scan_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int &get_level()
|
||||||
|
{ return debug.get_level(); }
|
||||||
|
|
||||||
|
private: debug_support debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED)
|
||||||
|
#define BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// closure_context_linker is a debug wrapper for the closure template
|
||||||
|
// parameter of the rule<>, subrule<> and grammar classes
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<typename ContextT>
|
||||||
|
struct closure_context_linker : public parser_context_linker<ContextT>
|
||||||
|
{
|
||||||
|
typedef parser_context_linker<ContextT> base_t;
|
||||||
|
|
||||||
|
template <typename ParserT>
|
||||||
|
closure_context_linker(ParserT const& p)
|
||||||
|
: parser_context_linker<ContextT>(p) {}
|
||||||
|
|
||||||
|
template <typename ParserT, typename ScannerT>
|
||||||
|
void pre_parse(ParserT const& p, ScannerT &scan)
|
||||||
|
{ this->base_t::pre_parse(p, scan); }
|
||||||
|
|
||||||
|
template <typename ResultT, typename ParserT, typename ScannerT>
|
||||||
|
ResultT&
|
||||||
|
post_parse(ResultT& hit, ParserT const& p, ScannerT &scan)
|
||||||
|
{
|
||||||
|
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
|
||||||
|
if (hit && trace_parser(p.derived())) {
|
||||||
|
// for now, print out the return value only
|
||||||
|
return impl::print_closure_info(
|
||||||
|
this->base_t::post_parse(hit, p, scan),
|
||||||
|
scan.get_level(),
|
||||||
|
parser_name(p.derived())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
|
||||||
|
|
||||||
|
return this->base_t::post_parse(hit, p, scan);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED)
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||||
|
|
||||||
|
}} // namespace BOOST_SPIRIT_CLASSIC_NS
|
||||||
|
|
||||||
|
#endif // defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_NODE_HPP)
|
||||||
|
|
||||||
+555
@@ -0,0 +1,555 @@
|
|||||||
|
/*=============================================================================
|
||||||
|
Copyright (c) 2001-2003 Joel de Guzman
|
||||||
|
Copyright (c) 2002-2003 Hartmut Kaiser
|
||||||
|
http://spirit.sourceforge.net/
|
||||||
|
|
||||||
|
Use, modification and distribution is subject to the Boost Software
|
||||||
|
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
=============================================================================*/
|
||||||
|
#if !defined(BOOST_SPIRIT_PARSER_NAMES_IPP)
|
||||||
|
#define BOOST_SPIRIT_PARSER_NAMES_IPP
|
||||||
|
|
||||||
|
#if defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#ifdef BOOST_NO_STRINGSTREAM
|
||||||
|
#include <strstream>
|
||||||
|
#define BOOST_SPIRIT_SSTREAM std::strstream
|
||||||
|
std::string BOOST_SPIRIT_GETSTRING(std::strstream& ss)
|
||||||
|
{
|
||||||
|
ss << ends;
|
||||||
|
std::string rval = ss.str();
|
||||||
|
ss.freeze(false);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <sstream>
|
||||||
|
#define BOOST_SPIRIT_GETSTRING(ss) ss.str()
|
||||||
|
#define BOOST_SPIRIT_SSTREAM std::stringstream
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost { namespace spirit {
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from actions.hpp
|
||||||
|
template <typename ParserT, typename ActionT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(action<ParserT, ActionT> const& p)
|
||||||
|
{
|
||||||
|
return std::string("action")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from directives.hpp
|
||||||
|
template <typename ParserT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(contiguous<ParserT> const& p)
|
||||||
|
{
|
||||||
|
return std::string("contiguous")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParserT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(inhibit_case<ParserT> const& p)
|
||||||
|
{
|
||||||
|
return std::string("inhibit_case")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(longest_alternative<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("longest_alternative")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(shortest_alternative<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("shortest_alternative")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from numerics.hpp
|
||||||
|
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
|
||||||
|
inline std::string
|
||||||
|
parser_name(uint_parser<T, Radix, MinDigits, MaxDigits> const& /*p*/)
|
||||||
|
{
|
||||||
|
BOOST_SPIRIT_SSTREAM stream;
|
||||||
|
stream << Radix << ", " << MinDigits << ", " << MaxDigits;
|
||||||
|
return std::string("uint_parser<")
|
||||||
|
+ BOOST_SPIRIT_GETSTRING(stream)
|
||||||
|
+ std::string(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
|
||||||
|
inline std::string
|
||||||
|
parser_name(int_parser<T, Radix, MinDigits, MaxDigits> const& /*p*/)
|
||||||
|
{
|
||||||
|
BOOST_SPIRIT_SSTREAM stream;
|
||||||
|
stream << Radix << ", " << MinDigits << ", " << MaxDigits;
|
||||||
|
return std::string("int_parser<")
|
||||||
|
+ BOOST_SPIRIT_GETSTRING(stream)
|
||||||
|
+ std::string(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename RealPoliciesT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(real_parser<T, RealPoliciesT> const& /*p*/)
|
||||||
|
{
|
||||||
|
return std::string("real_parser");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from operators.hpp
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(sequence<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("sequence")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(sequential_or<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("sequential_or")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(alternative<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("alternative")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(intersection<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("intersection")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(difference<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("difference")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
inline std::string
|
||||||
|
parser_name(exclusive_or<A, B> const& p)
|
||||||
|
{
|
||||||
|
return std::string("exclusive_or")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
inline std::string
|
||||||
|
parser_name(optional<S> const& p)
|
||||||
|
{
|
||||||
|
return std::string("optional")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
inline std::string
|
||||||
|
parser_name(kleene_star<S> const& p)
|
||||||
|
{
|
||||||
|
return std::string("kleene_star")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
inline std::string
|
||||||
|
parser_name(positive<S> const& p)
|
||||||
|
{
|
||||||
|
return std::string("positive")
|
||||||
|
+ std::string("[")
|
||||||
|
+ parser_name(p.subject())
|
||||||
|
+ std::string("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from parser.hpp
|
||||||
|
template <typename DerivedT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(parser<DerivedT> const& /*p*/)
|
||||||
|
{
|
||||||
|
return std::string("parser");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from primitives.hpp
|
||||||
|
template <typename DerivedT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(char_parser<DerivedT> const &/*p*/)
|
||||||
|
{
|
||||||
|
return std::string("char_parser");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(chlit<CharT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("chlit(\'")
|
||||||
|
+ std::string(1, p.ch)
|
||||||
|
+ std::string("\')");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(range<CharT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("range(")
|
||||||
|
+ std::string(1, p.first) + std::string(", ") + std::string(1, p.last)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IteratorT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(chseq<IteratorT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("chseq(\"")
|
||||||
|
+ std::string(p.first, p.last)
|
||||||
|
+ std::string("\")");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IteratorT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(strlit<IteratorT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("strlit(\"")
|
||||||
|
+ std::string(p.seq.first, p.seq.last)
|
||||||
|
+ std::string("\")");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(nothing_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("nothing");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(epsilon_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("epsilon");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(anychar_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("anychar");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(alnum_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("alnum");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(alpha_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("alpha");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(cntrl_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("cntrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(digit_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("digit");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(graph_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("graph");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(lower_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("lower");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(print_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("print");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(punct_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("punct");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(blank_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(space_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("space");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(upper_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("upper");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(xdigit_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("xdigit");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(eol_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("eol");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
parser_name(end_parser const&)
|
||||||
|
{
|
||||||
|
return std::string("end");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from rule.hpp
|
||||||
|
namespace impl {
|
||||||
|
struct node_registry
|
||||||
|
{
|
||||||
|
typedef std::pair<std::string, bool> rule_info;
|
||||||
|
typedef std::map<void const *, rule_info> rule_infos;
|
||||||
|
|
||||||
|
std::string find_node(void const *r)
|
||||||
|
{
|
||||||
|
rule_infos::const_iterator cit = infos.find(r);
|
||||||
|
if (cit != infos.end())
|
||||||
|
return (*cit).second.first;
|
||||||
|
return std::string("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trace_node(void const *r)
|
||||||
|
{
|
||||||
|
rule_infos::const_iterator cit = infos.find(r);
|
||||||
|
if (cit != infos.end())
|
||||||
|
return (*cit).second.second;
|
||||||
|
return BOOST_SPIRIT_DEBUG_TRACENODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool register_node(void const *r, char const *name_to_register,
|
||||||
|
bool trace_node)
|
||||||
|
{
|
||||||
|
if (infos.find(r) != infos.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return infos.insert(rule_infos::value_type(r,
|
||||||
|
rule_info(std::string(name_to_register), trace_node))
|
||||||
|
).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unregister_node(void const *r)
|
||||||
|
{
|
||||||
|
if (infos.find(r) == infos.end())
|
||||||
|
return false;
|
||||||
|
return (1 == infos.erase(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
rule_infos infos;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline node_registry &
|
||||||
|
get_node_registry()
|
||||||
|
{
|
||||||
|
static node_registry node_infos;
|
||||||
|
return node_infos;
|
||||||
|
}
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename DerivedT, typename EmbedT,
|
||||||
|
typename T0, typename T1, typename T2
|
||||||
|
>
|
||||||
|
inline std::string
|
||||||
|
parser_name(impl::rule_base<DerivedT, EmbedT, T0, T1, T2> const& p)
|
||||||
|
{
|
||||||
|
return std::string("rule_base")
|
||||||
|
+ std::string("(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T0, typename T1, typename T2>
|
||||||
|
inline std::string
|
||||||
|
parser_name(rule<T0, T1, T2> const& p)
|
||||||
|
{
|
||||||
|
return std::string("rule")
|
||||||
|
+ std::string("(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from subrule.hpp
|
||||||
|
template <typename FirstT, typename RestT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(subrule_list<FirstT, RestT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("subrule_list")
|
||||||
|
+ std::string("(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int ID, typename DefT, typename ContextT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(subrule_parser<ID, DefT, ContextT> const &p)
|
||||||
|
{
|
||||||
|
return std::string("subrule_parser")
|
||||||
|
+ std::string("(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int ID, typename ContextT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(subrule<ID, ContextT> const &p)
|
||||||
|
{
|
||||||
|
BOOST_SPIRIT_SSTREAM stream;
|
||||||
|
stream << ID;
|
||||||
|
return std::string("subrule<")
|
||||||
|
+ BOOST_SPIRIT_GETSTRING(stream)
|
||||||
|
+ std::string(">(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from grammar.hpp
|
||||||
|
template <typename DerivedT, typename ContextT>
|
||||||
|
inline std::string
|
||||||
|
parser_name(grammar<DerivedT, ContextT> const& p)
|
||||||
|
{
|
||||||
|
return std::string("grammar")
|
||||||
|
+ std::string("(")
|
||||||
|
+ impl::get_node_registry().find_node(&p)
|
||||||
|
+ std::string(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// decide, if a node is to be traced or not
|
||||||
|
template<
|
||||||
|
typename DerivedT, typename EmbedT,
|
||||||
|
typename T0, typename T1, typename T2
|
||||||
|
>
|
||||||
|
inline bool
|
||||||
|
trace_parser(impl::rule_base<DerivedT, EmbedT, T0, T1, T2>
|
||||||
|
const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T0, typename T1, typename T2>
|
||||||
|
inline bool
|
||||||
|
trace_parser(rule<T0, T1, T2> const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DerivedT, typename ContextT>
|
||||||
|
inline bool
|
||||||
|
trace_parser(grammar<DerivedT, ContextT> const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DerivedT, int N, typename ContextT>
|
||||||
|
inline bool
|
||||||
|
trace_parser(impl::entry_grammar<DerivedT, N, ContextT> const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int ID, typename ContextT>
|
||||||
|
bool
|
||||||
|
trace_parser(subrule<ID, ContextT> const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParserT, typename ActorTupleT>
|
||||||
|
bool
|
||||||
|
trace_parser(init_closure_parser<ParserT, ActorTupleT> const& p)
|
||||||
|
{
|
||||||
|
return impl::get_node_registry().trace_node(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||||
|
|
||||||
|
}} // namespace boost::spirit
|
||||||
|
|
||||||
|
#undef BOOST_SPIRIT_SSTREAM
|
||||||
|
#undef BOOST_SPIRIT_GETSTRING
|
||||||
|
|
||||||
|
#endif // defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_PARSER_NAMES_IPP)
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
/*=============================================================================
|
||||||
|
Copyright (c) 2001-2003 Joel de Guzman
|
||||||
|
Copyright (c) 2002-2003 Hartmut Kaiser
|
||||||
|
http://spirit.sourceforge.net/
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
=============================================================================*/
|
||||||
|
#if !defined(BOOST_SPIRIT_MINIMAL_DEBUG_HPP)
|
||||||
|
#define BOOST_SPIRIT_MINIMAL_DEBUG_HPP
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP)
|
||||||
|
#error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/minimal.hpp"
|
||||||
|
#endif
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Minimum debugging tools support
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_OUT)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_OUT std::cout
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// BOOST_SPIRIT_DEBUG_FLAGS controls the level of diagnostics printed
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_NONE)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_FLAGS_NONE 0x0000 // no diagnostics at all
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_MAX)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_FLAGS_MAX 0xFFFF // print maximal diagnostics
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_FLAGS BOOST_SPIRIT_DEBUG_FLAGS_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_PRINT_SOME)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_PRINT_SOME 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_RULE)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_RULE(r)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_RULE)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_NODE)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_NODE(r)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_NODE)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_GRAMMAR)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_GRAMMAR(r)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_GRAMMAR)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_RULE(r, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_NODE(r, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR(r, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME(r, n, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME(r, n, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME)
|
||||||
|
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(r, n, t)
|
||||||
|
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME)
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_MINIMAL_DEBUG_HPP)
|
||||||
+254
@@ -0,0 +1,254 @@
|
|||||||
|
/*=============================================================================
|
||||||
|
Copyright (c) 2001-2003 Joel de Guzman
|
||||||
|
Copyright (c) 2002-2003 Hartmut Kaiser
|
||||||
|
http://spirit.sourceforge.net/
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
=============================================================================*/
|
||||||
|
#if !defined(BOOST_SPIRIT_PARSER_NAMES_HPP)
|
||||||
|
#define BOOST_SPIRIT_PARSER_NAMES_HPP
|
||||||
|
|
||||||
|
#if defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
#include <boost/spirit/home/classic/namespace.hpp>
|
||||||
|
#include <boost/spirit/home/classic/core.hpp>
|
||||||
|
|
||||||
|
namespace boost { namespace spirit {
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Declaration of helper functions, which return the name of a concrete
|
||||||
|
// parser instance. The functions are specialized on the parser types. The
|
||||||
|
// functions declared in this file are for the predefined parser types from
|
||||||
|
// the Spirit core library only, so additional functions might be provided as
|
||||||
|
// needed.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from actions.hpp
|
||||||
|
template <typename ParserT, typename ActionT>
|
||||||
|
std::string
|
||||||
|
parser_name(action<ParserT, ActionT> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from directives.hpp
|
||||||
|
template <typename ParserT>
|
||||||
|
std::string
|
||||||
|
parser_name(contiguous<ParserT> const& p);
|
||||||
|
|
||||||
|
template <typename ParserT>
|
||||||
|
std::string
|
||||||
|
parser_name(inhibit_case<ParserT> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(longest_alternative<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(shortest_alternative<A, B> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from grammar.hpp
|
||||||
|
template <typename DerivedT, typename ContextT>
|
||||||
|
std::string
|
||||||
|
parser_name(grammar<DerivedT, ContextT> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from numerics.hpp
|
||||||
|
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
|
||||||
|
std::string
|
||||||
|
parser_name(uint_parser<T, Radix, MinDigits, MaxDigits> const& p);
|
||||||
|
|
||||||
|
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
|
||||||
|
std::string
|
||||||
|
parser_name(int_parser<T, Radix, MinDigits, MaxDigits> const& p);
|
||||||
|
|
||||||
|
template <typename T, typename RealPoliciesT>
|
||||||
|
std::string
|
||||||
|
parser_name(real_parser<T, RealPoliciesT> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from operators.hpp
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(sequence<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(sequential_or<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(alternative<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(intersection<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(difference<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
std::string
|
||||||
|
parser_name(exclusive_or<A, B> const& p);
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
std::string
|
||||||
|
parser_name(optional<S> const& p);
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
std::string
|
||||||
|
parser_name(kleene_star<S> const& p);
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
std::string
|
||||||
|
parser_name(positive<S> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from parser.hpp
|
||||||
|
template <typename DerivedT>
|
||||||
|
std::string
|
||||||
|
parser_name(parser<DerivedT> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from primitives.hpp
|
||||||
|
template <typename DerivedT>
|
||||||
|
std::string
|
||||||
|
parser_name(char_parser<DerivedT> const &p);
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::string
|
||||||
|
parser_name(chlit<CharT> const &p);
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::string
|
||||||
|
parser_name(range<CharT> const &p);
|
||||||
|
|
||||||
|
template <typename IteratorT>
|
||||||
|
std::string
|
||||||
|
parser_name(chseq<IteratorT> const &p);
|
||||||
|
|
||||||
|
template <typename IteratorT>
|
||||||
|
std::string
|
||||||
|
parser_name(strlit<IteratorT> const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(nothing_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(epsilon_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(anychar_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(alnum_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(alpha_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(cntrl_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(digit_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(graph_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(lower_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(print_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(punct_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(blank_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(space_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(upper_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(xdigit_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(eol_parser const &p);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
parser_name(end_parser const &p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from rule.hpp
|
||||||
|
template<typename T0, typename T1, typename T2>
|
||||||
|
std::string
|
||||||
|
parser_name(rule<T0, T1, T2> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from subrule.hpp
|
||||||
|
template <typename FirstT, typename RestT>
|
||||||
|
std::string
|
||||||
|
parser_name(subrule_list<FirstT, RestT> const &p);
|
||||||
|
|
||||||
|
template <int ID, typename DefT, typename ContextT>
|
||||||
|
std::string
|
||||||
|
parser_name(subrule_parser<ID, DefT, ContextT> const &p);
|
||||||
|
|
||||||
|
template <int ID, typename ContextT>
|
||||||
|
std::string
|
||||||
|
parser_name(subrule<ID, ContextT> const &p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// from chset.hpp
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Decide, if a node is to be traced or not
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<
|
||||||
|
typename DerivedT, typename EmbedT,
|
||||||
|
typename T0, typename T1, typename T2
|
||||||
|
>
|
||||||
|
bool
|
||||||
|
trace_parser(impl::rule_base<DerivedT, EmbedT, T0, T1, T2>
|
||||||
|
const& p);
|
||||||
|
|
||||||
|
template <typename DerivedT, typename ContextT>
|
||||||
|
bool
|
||||||
|
trace_parser(grammar<DerivedT, ContextT> const& p);
|
||||||
|
|
||||||
|
template <int ID, typename ContextT>
|
||||||
|
bool
|
||||||
|
trace_parser(subrule<ID, ContextT> const& p);
|
||||||
|
|
||||||
|
template <typename ParserT, typename ActorTupleT>
|
||||||
|
struct init_closure_parser;
|
||||||
|
|
||||||
|
template <typename ParserT, typename ActorTupleT>
|
||||||
|
bool
|
||||||
|
trace_parser(init_closure_parser<ParserT, ActorTupleT> const& p);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||||
|
|
||||||
|
}} // namespace BOOST_SPIRIT_CLASSIC_NS
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
#include <boost/spirit/home/classic/debug/impl/parser_names.ipp>
|
||||||
|
|
||||||
|
#endif // defined(BOOST_SPIRIT_DEBUG)
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_SPIRIT_PARSER_NAMES_HPP)
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*=============================================================================
|
||||||
|
Copyright (c) 2006 Tobias Schwinger
|
||||||
|
http://spirit.sourceforge.net/
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
=============================================================================*/
|
||||||
|
#if !defined(BOOST_SPIRIT_DEBUG_TYPEOF_HPP)
|
||||||
|
#define BOOST_SPIRIT_DEBUG_TYPEOF_HPP
|
||||||
|
|
||||||
|
#include <boost/typeof/typeof.hpp>
|
||||||
|
|
||||||
|
#include <boost/spirit/home/classic/namespace.hpp>
|
||||||
|
#include <boost/spirit/home/classic/core/typeof.hpp>
|
||||||
|
|
||||||
|
namespace boost { namespace spirit {
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// debug_node.hpp
|
||||||
|
template<typename ContextT> struct parser_context_linker;
|
||||||
|
template<typename ScannerT> struct scanner_context_linker;
|
||||||
|
template<typename ContextT> struct closure_context_linker;
|
||||||
|
|
||||||
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||||
|
|
||||||
|
}} // namespace BOOST_SPIRIT_CLASSIC_NS
|
||||||
|
|
||||||
|
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
|
||||||
|
|
||||||
|
// debug_node.hpp
|
||||||
|
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::parser_context_linker,1)
|
||||||
|
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::scanner_context_linker,1)
|
||||||
|
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::closure_context_linker,1)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Reference in New Issue
Block a user