mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-30 12:07:51 +00:00
Compare commits
36 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 |
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -502,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
|
||||||
@@ -1131,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 },
|
||||||
@@ -1141,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 },
|
||||||
|
|||||||
@@ -287,6 +287,7 @@
|
|||||||
SymbolInfoTick = 288,
|
SymbolInfoTick = 288,
|
||||||
SymbolInfoDouble = 289,
|
SymbolInfoDouble = 289,
|
||||||
|
|
||||||
GetQuote = 290
|
GetQuote = 290,
|
||||||
|
GetSymbols = 291
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+68
-35
@@ -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,11 +32,24 @@ namespace MtApi5
|
|||||||
|
|
||||||
private HashSet<int> _experts = [];
|
private HashSet<int> _experts = [];
|
||||||
private Dictionary<int, Mt5Quote> _quotes = [];
|
private Dictionary<int, Mt5Quote> _quotes = [];
|
||||||
|
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;
|
||||||
@@ -122,14 +136,7 @@ namespace MtApi5
|
|||||||
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
|
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load quotes
|
var quotes = LoadQuotes(client, experts);
|
||||||
Dictionary<int, Mt5Quote> quotes = [];
|
|
||||||
foreach (var handle in experts)
|
|
||||||
{
|
|
||||||
var quote = GetQuote(client, handle);
|
|
||||||
if (quote != null)
|
|
||||||
quotes[handle] = quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
@@ -159,6 +166,18 @@ namespace MtApi5
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Dictionary<int, Mt5Quote> LoadQuotes(MtRpcClient client, HashSet<int> experts)
|
||||||
|
{
|
||||||
|
Dictionary<int, Mt5Quote> quotes = [];
|
||||||
|
foreach (var handle in experts)
|
||||||
|
{
|
||||||
|
var quote = GetQuote(client, handle);
|
||||||
|
if (quote != null)
|
||||||
|
quotes[handle] = quote;
|
||||||
|
}
|
||||||
|
return quotes;
|
||||||
|
}
|
||||||
|
|
||||||
///<summary>
|
///<summary>
|
||||||
///Disconnect from MetaTrader API. Async method.
|
///Disconnect from MetaTrader API. Async method.
|
||||||
///</summary>
|
///</summary>
|
||||||
@@ -182,10 +201,31 @@ namespace MtApi5
|
|||||||
///</summary>
|
///</summary>
|
||||||
public IEnumerable<Mt5Quote> GetQuotes()
|
public IEnumerable<Mt5Quote> GetQuotes()
|
||||||
{
|
{
|
||||||
|
MtRpcClient? client;
|
||||||
|
HashSet<int> experts;
|
||||||
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>
|
||||||
@@ -2664,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2730,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>
|
||||||
@@ -2969,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3055,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3070,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3085,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3100,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3392,11 +3432,6 @@ namespace MtApi5
|
|||||||
var quote = GetQuote(Client, 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
|
||||||
@@ -3411,19 +3446,18 @@ 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(MtRpcClient? client, int expertHandle)
|
private Mt5Quote? GetQuote(MtRpcClient? client, int expertHandle)
|
||||||
@@ -3512,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)
|
||||||
@@ -3540,7 +3574,6 @@ namespace MtApi5
|
|||||||
client = _client;
|
client = _client;
|
||||||
_client = null;
|
_client = null;
|
||||||
|
|
||||||
_quotes.Clear();
|
|
||||||
_experts.Clear();
|
_experts.Clear();
|
||||||
_executorHandle = 0;
|
_executorHandle = 0;
|
||||||
}
|
}
|
||||||
@@ -3568,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
|
||||||
|
|||||||
+13
-13
@@ -65,7 +65,7 @@ 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<string> commandTask = new();
|
CommandTask<string> commandTask = new();
|
||||||
int commandId;
|
int commandId;
|
||||||
@@ -78,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);
|
||||||
@@ -89,19 +89,19 @@ namespace MtClient
|
|||||||
|
|
||||||
public HashSet<int>? RequestExpertsList()
|
public HashSet<int>? RequestExpertsList()
|
||||||
{
|
{
|
||||||
CommandTask<object> notificationTask = new();
|
CommandTask<object> requestTask = new();
|
||||||
lock (notification_tasks_)
|
lock (service_requests_)
|
||||||
{
|
{
|
||||||
notification_tasks_[MtNotificationType.ClientReady] = notificationTask;
|
service_requests_[ServiceRequestType.ExpertList] = requestTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
MtNotification notification = new(MtNotificationType.ClientReady);
|
MtServiceRequest request = new(ServiceRequestType.ExpertList);
|
||||||
Send(notification);
|
Send(request);
|
||||||
|
|
||||||
var response = notificationTask.WaitResponse(10000); // 10 sec
|
var response = requestTask.WaitResponse(10000); // 10 sec
|
||||||
lock (notification_tasks_)
|
lock (service_requests_)
|
||||||
{
|
{
|
||||||
notification_tasks_.Remove(MtNotificationType.ClientReady);
|
service_requests_.Remove(ServiceRequestType.ExpertList);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response as HashSet<int>;
|
return response as HashSet<int>;
|
||||||
@@ -277,9 +277,9 @@ namespace MtClient
|
|||||||
{
|
{
|
||||||
logger_.Debug($"MtRpcClient.ProcessExpertList: experts count - {experts.Count}");
|
logger_.Debug($"MtRpcClient.ProcessExpertList: experts count - {experts.Count}");
|
||||||
|
|
||||||
lock (notification_tasks_)
|
lock (service_requests_)
|
||||||
{
|
{
|
||||||
if (notification_tasks_.TryGetValue(MtNotificationType.ClientReady, out CommandTask<object>? value))
|
if (service_requests_.TryGetValue(ServiceRequestType.ExpertList, out CommandTask<object>? value))
|
||||||
value.SetResponse(experts);
|
value.SetResponse(experts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,7 +301,7 @@ namespace MtClient
|
|||||||
|
|
||||||
private int nextCommandId = 0;
|
private int nextCommandId = 0;
|
||||||
private readonly Dictionary<int, CommandTask<string>> tasks_ = [];
|
private readonly Dictionary<int, CommandTask<string>> tasks_ = [];
|
||||||
private readonly Dictionary<MtNotificationType, CommandTask<object>> notification_tasks_ = [];
|
private readonly Dictionary<ServiceRequestType, CommandTask<object>> service_requests_ = [];
|
||||||
|
|
||||||
private readonly IRpcLogger logger_;
|
private readonly IRpcLogger logger_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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.
+46
-8
@@ -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);
|
||||||
@@ -3793,15 +3796,24 @@ 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.
|
||||||
|
|||||||
Reference in New Issue
Block a user