Compare commits

...

23 Commits

Author SHA1 Message Date
vdemydiuk 5f4ae3cd9e Issue #74: Updated package Newtonsoft.Json from 8.0.3 to 12.0.2 2019-04-30 11:09:12 +03:00
vdemydiuk 13b8aa9644 Disable debug loging in MtApi.ex5 2019-04-30 11:07:47 +03:00
vdemydiuk e364b313c3 MtApi5: Set version 1.0.20 2019-04-26 13:07:34 +03:00
vdemydiuk 68f2a7ae07 Issue #147: added non-documented types of trade operations: balance, credit, rebate 2019-04-24 17:47:06 +03:00
vdemydiuk 42a1da3356 Issue #136: Added new properties to the ENUM_SYMBOL_INFO_DOUBLE enumeration: SYMBOL_VOLUME_REAL, SYMBOL_VOLUMEHIGH_REAL, SYMBOL_VOLUMELOW_REAL 2019-03-18 18:26:17 +02:00
vdemydiuk 44fab4dae1 Issue #136: Updated structures MqlTick, MqlBook with new field volume_real. Remove redundant code from MtApiService. 2019-03-18 17:31:54 +02:00
Vyacheslav Demidyuk d1387148df Merge pull request #148 from flognity/master
ObjectCreate can now take up to 30 anchor points
2019-03-18 16:11:48 +02:00
Florian Wilhelm bb4ac426cd Modified the ObjectCreate such that it can take up to 30 anchor points (maximum amount of anchor points in mql5). The MtApi5.mq5 has been updated to cope with the added parameters. The MtApi5.ex5 has been rebuilt. 2019-03-07 20:35:23 +01:00
vdemydiuk 34b4e33cc9 Issue #138: removed rudiment value POSITION_COMMISION from enum ENUM_POSITION_PROPERTY_DOUBLE 2019-02-20 13:12:29 +02:00
vdemydiuk f01ec01a5f Disable debug loging in MtApi.ex5 2018-06-06 15:11:56 +03:00
vdemydiuk 0c38d37559 Issue #107: Added function PositionCloseAll 2018-06-06 14:24:39 +03:00
vdemydiuk 897892dc89 Issue #122: Added event OnLockTicksEvent (MT5) 2018-06-06 12:46:24 +03:00
vdemydiuk 1a5882b75a Issue #122: Implemented UnlockTicks function in MtApi (MT5) 2018-06-05 19:19:35 +03:00
vdemydiuk 0f717f1cb7 Issue #119: Added out parameter MqlTradeResult to function PositionClose 2018-06-04 17:48:14 +03:00
vdemydiuk 5d78ad5067 Issue #120: set field 'Symbol' as optional in MqlTradeRequest (MT5) 2018-06-04 15:36:35 +03:00
vdemydiuk 6c45f28a05 Issue #121: Added original MtTime field to MqlRates (MT5) 2018-06-04 15:04:12 +03:00
vdemydiuk ca3c0e735f Issue #110: Implemented function for working with global variables (MT5) 2018-06-04 13:53:55 +03:00
vdemydiuk f71151104b Issue #111: Added enum value SYMBOL_VISIBLE 2018-05-08 19:07:52 +03:00
vdemydiuk 28816a75ac Issue #113: Changed extension of logging files to *.log 2018-05-08 16:44:57 +03:00
vdemydiuk 6023bffed6 Issue #106: Extended structure Mt5Quote with fields from MqlTick (volume, last, time) 2018-05-08 14:53:31 +03:00
vdemydiuk fd34f009cd Started version 1.0.19 (MT5) 2018-05-08 14:50:25 +03:00
Vyacheslav Demidyuk 1bb2b65cdf Merge pull request #115 from CVasquezG/master
Updated README
2018-04-02 16:27:58 +03:00
CVasquezG 37e8275465 Updated README
Changes made to the README file to be more formal.
I am doing this as a university assignment where I am required to improve documentation in the open source community.  I hope changes suggested in this commit are useful for your project.
2018-03-31 14:08:20 -07:00
36 changed files with 1228 additions and 293 deletions
-47
View File
@@ -31,22 +31,6 @@ public struct CMqlRates
int spread; // Spread
__int64 real_volume; // Trade volume
};
public struct CMqlTick
{
__int64 time; // Time of the last prices update
double bid; // Current Bid price
double ask; // Current Ask price
double last; // Price of the last deal (Last)
unsigned __int64 volume; // Volume for the current Last price
};
public struct CMqlBookInfo
{
int type; // Order type from ENUM_BOOK_TYPE enumeration
double price; // Price
__int64 volume; // Volume
};
#pragma pack(pop)
void convertSystemString(wchar_t* dest, String^ src)
@@ -224,37 +208,6 @@ _DLLAPI int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates value
}, err, 0);
}
_DLLAPI int _stdcall sendMqlTickResponse(int expertHandle, CMqlTick* response, wchar_t* err)
{
return Execute<int>([&expertHandle, response]() {
MtMqlTick^ mtResponse = gcnew MtMqlTick();
mtResponse->time = response->time;
mtResponse->bid = response->bid;
mtResponse->ask = response->ask;
mtResponse->last = response->last;
mtResponse->volume = response->volume;
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlTick(mtResponse));
return 1;
}, err, 0);
}
_DLLAPI int _stdcall sendMqlBookInfoArrayResponse(int expertHandle, CMqlBookInfo values[], int size, wchar_t* err)
{
return Execute<int>([&expertHandle, values, &size]() {
array<MtMqlBookInfo^>^ list = gcnew array<MtMqlBookInfo^>(size);
for (int i = 0; i < size; i++)
{
MtMqlBookInfo^ info = gcnew MtMqlBookInfo();
info->type = values[i].type;
info->price = values[i].price;
info->volume = values[i].volume;
list[i] = info;
}
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlBookInfoArray(list));
return 1;
}, err, 0);
}
//----------- get values -------------------------------
_DLLAPI int _stdcall getCommandType(int expertHandle, int* res, wchar_t* err)
+1 -1
View File
@@ -54,7 +54,7 @@ namespace MTApiService
public class LogConfigurator
{
private const string LogFileNameExtension = "txt";
private const string LogFileNameExtension = "log";
public static void Setup(string profileName)
{
-2
View File
@@ -72,9 +72,7 @@
<Compile Include="MtClient.cs" />
<Compile Include="MtCommandTask.cs" />
<Compile Include="MtEvent.cs" />
<Compile Include="MtMqlBookInfo.cs" />
<Compile Include="MtMqlRates.cs" />
<Compile Include="MtMqlTick.cs" />
<Compile Include="MtMqlTradeRequest.cs" />
<Compile Include="MtRegistryManager.cs" />
<Compile Include="MtConnectionProfile.cs" />
+41 -12
View File
@@ -4,35 +4,51 @@ namespace MTApiService
{
public class Mt5Expert : MtExpert
{
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert));
private static readonly ILog Log = LogManager.GetLogger(typeof(Mt5Expert));
private const int StopExpertInterval = 2000; // 2 sec for testing mode
private readonly System.Timers.Timer _stopTimer = new System.Timers.Timer();
private System.Timers.Timer _stopTimer;
public Mt5Expert(int handle, string symbol, double bid, double ask, IMetaTraderHandler mtHandler, bool isTestMode) :
base(handle, symbol, bid, ask, mtHandler)
{
IsTestMode = isTestMode;
_stopTimer.Interval = StopExpertInterval;
_stopTimer.Elapsed += _stopTimer_Elapsed;
}
public bool IsTestMode { get; }
public override void UpdateQuote(MtQuote quote)
public override int GetCommandType()
{
Log.Debug("UpdateQuote: begin.");
base.UpdateQuote(quote);
Log.Debug("GetCommandType: called.");
if (IsTestMode)
{
//reset timer
_stopTimer.Stop();
_stopTimer.Start();
ResetTestModeTimer();
}
Log.Debug("UpdateQuote: end.");
return base.GetCommandType();
}
public override void SendEvent(MtEvent mtEvent)
{
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
if (IsTestMode)
{
if (_stopTimer == null)
{
_stopTimer = new System.Timers.Timer
{
Interval = StopExpertInterval,
AutoReset = false
};
_stopTimer.Elapsed += _stopTimer_Elapsed;
}
}
base.SendEvent(mtEvent);
Log.Debug("SendEvent: end.");
}
private void _stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
@@ -42,7 +58,20 @@ namespace MTApiService
Log.Warn("Mt5Expert has received new tick during 2 sec in testing mode. The possible cause: user has stopped the tester manually in MetaTrader 5.");
Deinit();
_stopTimer.Elapsed -= _stopTimer_Elapsed;
_stopTimer = null;
Log.Debug("_stopTimer_Elapsed: end.");
}
private void ResetTestModeTimer()
{
if (_stopTimer == null)
return;
//reset timer
_stopTimer.Stop();
_stopTimer.Start();
}
}
}
+26 -1
View File
@@ -66,6 +66,7 @@ namespace MTApiService
}
server.AddExpert(expert);
expert.Deinited += ExpertOnDeinited;
Log.Info("AddExpert: end");
}
@@ -81,7 +82,6 @@ namespace MTApiService
if (_experts.ContainsKey(expertHandle))
{
expert = _experts[expertHandle];
_experts.Remove(expertHandle);
}
}
@@ -270,6 +270,31 @@ namespace MTApiService
}
}
}
private void ExpertOnDeinited(object sender, EventArgs eventArgs)
{
Log.Debug("ExpertOnDeinited: begin.");
var expert = sender as MtExpert;
if (expert == null)
{
Log.Warn("expert_Deinited: end. Expert is not defined.");
return;
}
lock (_experts)
{
if (_experts.ContainsKey(expert.Handle))
{
_experts.Remove(expert.Handle);
}
}
Log.DebugFormat("ExpertOnDeinited: removed expert {0}", expert.Handle);
Log.Debug("ExpertOnDeinited: end.");
}
#endregion
}
}
+3 -3
View File
@@ -48,7 +48,7 @@ namespace MTApiService
Log.Debug("SendResponse: end.");
}
public int GetCommandType()
public virtual int GetCommandType()
{
Log.Debug("GetCommandType: called.");
@@ -110,7 +110,7 @@ namespace MTApiService
return command.NamedParams.ContainsKey(name);
}
public void SendEvent(MtEvent mtEvent)
public virtual void SendEvent(MtEvent mtEvent)
{
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
@@ -119,7 +119,7 @@ namespace MTApiService
Log.Debug("SendEvent: end.");
}
public virtual void UpdateQuote(MtQuote quote)
public void UpdateQuote(MtQuote quote)
{
Log.DebugFormat("UpdateQuote: begin. quote = {0}", quote);
-17
View File
@@ -1,17 +0,0 @@
using System.Runtime.Serialization;
namespace MTApiService
{
[DataContract]
public class MtMqlBookInfo
{
[DataMember]
public int type { get; set; }
[DataMember]
public double price { get; set; }
[DataMember]
public long volume { get; set; }
}
}
-23
View File
@@ -1,23 +0,0 @@
using System.Runtime.Serialization;
namespace MTApiService
{
[DataContract]
public class MtMqlTick
{
[DataMember]
public long time { get; set; } // Time of the last prices update
[DataMember]
public double bid { get; set; } // Current Bid price
[DataMember]
public double ask { get; set; } // Current Ask price
[DataMember]
public double last { get; set; } // Price of the last deal (Last)
[DataMember]
public ulong volume { get; set; } // Volume for the current Last price
}
}
+2 -42
View File
@@ -17,9 +17,8 @@ namespace MTApiService
typeof(MtResponseString), typeof(MtResponseBool),
typeof(MtResponseLong), typeof(MtResponseULong),
typeof(MtResponseDoubleArray), typeof(MtResponseIntArray),
typeof(MtResponseLongArray), typeof(MtResponseMqlTick),
typeof(MtResponseArrayList), typeof(MtResponseMqlRatesArray),
typeof(MtResponseMqlBookInfoArray)};
typeof(MtResponseLongArray),
typeof(MtResponseArrayList), typeof(MtResponseMqlRatesArray)};
}
public abstract object GetValue();
@@ -255,43 +254,4 @@ namespace MTApiService
return Value.ToString();
}
}
[DataContract]
public class MtResponseMqlTick : MtResponse
{
public MtResponseMqlTick(MtMqlTick value)
{
Value = value;
}
[DataMember]
public MtMqlTick Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
public class MtResponseMqlBookInfoArray : MtResponse
{
public MtResponseMqlBookInfoArray(MtMqlBookInfo[] value)
{
Value = value;
}
[DataMember]
public MtMqlBookInfo[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
}
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.29.0")]
[assembly: AssemblyFileVersion("1.0.29.0")]
[assembly: AssemblyVersion("1.0.31.0")]
[assembly: AssemblyFileVersion("1.0.31.0")]
+4 -1
View File
@@ -7,6 +7,9 @@
OP_BUYLIMIT = 2,
OP_SELLLIMIT = 3,
OP_BUYSTOP = 4,
OP_SELLSTOP = 5
OP_SELLSTOP = 5,
OP_BALANCE = 6,
OP_CREDIT = 7,
OP_REBATE = 8
}
}
+4 -1
View File
@@ -3,6 +3,9 @@
internal enum Mt5EventTypes
{
OnTradeTransaction = 1,
OnBookEvent = 2
OnBookEvent = 2,
OnTick = 3,
OnLastTimeBar = 4,
OnLockTicks = 5
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace MtApi5.Events
{
public class OnLastTimeBarEvent
{
public MqlRates Rates { get; set; }
public string Instrument { get; set; }
public int ExpertHandle { get; set; }
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace MtApi5.Events
{
internal class OnLockTicksEvent
{
public string Instrument { get; set; }
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace MtApi5.Events
{
internal class OnTickEvent
{
public MqlTick Tick { get; set; }
public string Instrument { get; set; }
public int ExpertHandle { get; set; }
}
}
+1
View File
@@ -16,6 +16,7 @@ namespace MtApi5
public ENUM_BOOK_TYPE type { get; set; } // Order type from ENUM_BOOK_TYPE enumeration
public double price { get; set; } // Price
public long volume { get; set; } // Volume
public double volume_real { get; set; } // Volume for the current Last price with greater accuracy
public override string ToString()
{
+15 -2
View File
@@ -7,7 +7,19 @@ namespace MtApi5
{
public MqlRates(DateTime time, double open, double high, double low, double close, long tick_volume, int spread, long real_volume)
{
this.time = time;
mt_time = Mt5TimeConverter.ConvertToMtTime(time);
this.open = open;
this.high = high;
this.low = low;
this.close = close;
this.tick_volume = tick_volume;
this.spread = spread;
this.real_volume = real_volume;
}
internal MqlRates(long time, double open, double high, double low, double close, long tick_volume, int spread, long real_volume)
{
mt_time = time;
this.open = open;
this.high = high;
this.low = low;
@@ -21,7 +33,8 @@ namespace MtApi5
{
}
public DateTime time { get; set; } // Period start time
public DateTime time => Mt5TimeConverter.ConvertFromMtTime(mt_time); // Period start time
public long mt_time { get; set; } // Period start time (original MT time)
public double open { get; set; } // Open price
public double high { get; set; } // The highest price of the period
public double low { get; set; } // The lowest price of the period
+2 -1
View File
@@ -23,7 +23,8 @@ namespace MtApi5
public double bid { get; set; } // Current Bid price
public double ask { get; set; } // Current Ask price
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 DateTime time => Mt5TimeConverter.ConvertFromMtTime(MtTime);
}
+17 -1
View File
@@ -235,6 +235,22 @@ namespace MtApi5
Print = 68,
ResetLastError = 143,
SendNotification = 144, //TODO
SendMail = 145 //TODO
SendMail = 145, //TODO
//Global Variables
GlobalVariableCheck = 146,
GlobalVariableTime = 147,
GlobalVariableDel = 148,
GlobalVariableGet = 149,
GlobalVariableName = 150,
GlobalVariableSet = 151,
GlobalVariablesFlush = 152,
GlobalVariableTemp = 154,
GlobalVariableSetOnCondition = 156,
GlobalVariablesDeleteAll = 157,
GlobalVariablesTotal = 158,
UnlockTicks = 159,
PositionCloseAll = 160
}
}
+4 -3
View File
@@ -181,8 +181,7 @@ namespace MtApi5
SYMBOL_BACKGROUND_COLOR = 79,
SYMBOL_CHART_MODE = 80,
SYMBOL_SELECT = 0,
//FIXME: SYMBOL_VISIBLE not found in MQL5 environment!
//SYMBOL_VISIBLE = ?
SYMBOL_VISIBLE = 76,
SYMBOL_SESSION_DEALS = 56,
SYMBOL_SESSION_BUY_ORDERS = 60,
SYMBOL_SESSION_SELL_ORDERS = 62,
@@ -224,6 +223,9 @@ namespace MtApi5
SYMBOL_LAST = 7,
SYMBOL_LASTHIGH = 8,
SYMBOL_LASTLOW = 9,
SYMBOL_VOLUME_REAL = 10,
SYMBOL_VOLUMEHIGH_REAL = 11,
SYMBOL_VOLUMELOW_REAL = 12,
SYMBOL_OPTION_STRIKE = 72,
SYMBOL_POINT = 16,
SYMBOL_TRADE_TICK_VALUE = 26,
@@ -549,7 +551,6 @@ namespace MtApi5
POSITION_SL = 6, //Stop Loss level of opened position
POSITION_TP = 7, //Take Profit level of opened position
POSITION_PRICE_CURRENT = 5, //Current price of the position symbol
POSITION_COMMISSION = 8, //FIXME: Undocumented!
POSITION_SWAP = 9, //Cumulative swap
POSITION_PROFIT = 10 //Current profit
}
+14
View File
@@ -0,0 +1,14 @@
using System;
namespace MtApi5
{
public class Mt5LockTicksEventArgs : EventArgs
{
internal Mt5LockTicksEventArgs(string symbol)
{
Symbol = symbol;
}
public string Symbol { get; }
}
}
+8 -2
View File
@@ -1,4 +1,5 @@
using MTApiService;
using System;
using MTApiService;
namespace MtApi5
{
@@ -8,8 +9,13 @@ namespace MtApi5
public double Bid { get; }
public double Ask { get; }
public int ExpertHandle { get; set; }
public DateTime Time { get; set; }
public double Last { get; set; }
public ulong Volume { get; set; }
// public long TimeMsc { get; set; }
// public uint Flags { get; set; }
private Mt5Quote(string instrument, double bid, double ask)
internal Mt5Quote(string instrument, double bid, double ask)
{
Instrument = instrument;
Bid = bid;
+18
View File
@@ -0,0 +1,18 @@
using System;
namespace MtApi5
{
public class Mt5TimeBarArgs: EventArgs
{
internal Mt5TimeBarArgs(int expertHandle, string symbol, MqlRates rates)
{
ExpertHandle = expertHandle;
Rates = rates;
Symbol = symbol;
}
public int ExpertHandle { get; }
public string Symbol { get; }
public MqlRates Rates { get; }
}
}
+10 -3
View File
@@ -32,8 +32,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
@@ -49,7 +49,12 @@
<ItemGroup>
<Compile Include="CopyTicksFlag.cs" />
<Compile Include="Events\OnBookEvent.cs" />
<Compile Include="Events\OnLastTimeBarEvent.cs" />
<Compile Include="Events\OnLockTicksEvent.cs" />
<Compile Include="Events\OnTickEvent.cs" />
<Compile Include="Events\OnTradeTransactionEvent.cs" />
<Compile Include="Mt5LockTicksEventArgs.cs" />
<Compile Include="Mt5TimeBarArgs.cs" />
<Compile Include="MqlBookInfo.cs" />
<Compile Include="MqlParam.cs" />
<Compile Include="MqlRates.cs" />
@@ -84,6 +89,8 @@
<Compile Include="Requests\OrderCheckRequest.cs" />
<Compile Include="Requests\OrderCheckResult.cs" />
<Compile Include="Requests\OrderSendRequest.cs" />
<Compile Include="Requests\PositionCloseRequest.cs" />
<Compile Include="Requests\PositionCloseResult.cs" />
<Compile Include="Requests\PositionOpenRequest.cs" />
<Compile Include="Requests\RequestBase.cs" />
<Compile Include="Requests\RequestType.cs" />
@@ -91,6 +98,7 @@
<Compile Include="Requests\Response.cs" />
<Compile Include="Requests\SymbolInfoStringRequest.cs" />
<Compile Include="Requests\SymbolInfoStringResult.cs" />
<Compile Include="Requests\SymbolInfoTickRequest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MTApiService\MTApiService.csproj">
@@ -101,7 +109,6 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
+267 -32
View File
@@ -40,12 +40,21 @@ namespace MtApi5
private volatile bool _isBacktestingMode;
private Mt5ConnectionState _connectionState = Mt5ConnectionState.Disconnected;
private int _executorHandle;
private readonly Dictionary<Mt5EventTypes, Action<int, string>> _mtEventHandlers =
new Dictionary<Mt5EventTypes, Action<int, string>>();
#endregion
#region Public Methods
public MtApi5Client()
{
LogConfigurator.Setup(LogProfileName);
_mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent;
_mtEventHandlers[Mt5EventTypes.OnTick] = ReceivedOnTickEvent;
_mtEventHandlers[Mt5EventTypes.OnTradeTransaction] = ReceivedOnTradeTransactionEvent;
_mtEventHandlers[Mt5EventTypes.OnLastTimeBar] = ReceivedOnLastTimeBarEvent;
_mtEventHandlers[Mt5EventTypes.OnLockTicks] = ReceivedOnLockTicksEvent;
}
///<summary>
@@ -512,11 +521,20 @@ namespace MtApi5
///<summary>
///Close all open positions.
///</summary>
[Obsolete("OrderCloseAll is deprecated, please use PositionCloseAll instead.")]
public bool OrderCloseAll()
{
return SendCommand<bool>(Mt5CommandType.OrderCloseAll, null);
}
///<summary>
///Close all open positions. Returns count of closed positions.
///</summary>
public int PositionCloseAll()
{
return SendCommand<int>(Mt5CommandType.PositionCloseAll, null);
}
///<summary>
///Closes a position with the specified ticket.
///</summary>
@@ -529,6 +547,36 @@ namespace MtApi5
return SendCommand<bool>(Mt5CommandType.PositionClose, commandParameters);
}
///<summary>
///Closes a position with the specified ticket.
///</summary>
///<param name="ticket">Ticket of the closed position.</param>
///<param name="deviation">Maximal deviation from the current price (in points).</param>
/// <param name="result">output result</param>
public bool PositionClose(ulong ticket, ulong deviation, out MqlTradeResult result)
{
Log.Debug($"PositionClose: ticket = {ticket}, deviation = {deviation}");
var response = SendRequest<PositionCloseResult>(new PositionCloseRequest
{
Ticket = ticket,
Deviation = deviation
});
result = response?.TradeResult;
return response != null && response.RetVal;
}
///<summary>
///Closes a position with the specified ticket.
///</summary>
///<param name="ticket">Ticket of the closed position.</param>
/// <param name="result">output result</param>
public bool PositionClose(ulong ticket, out MqlTradeResult result)
{
return PositionClose(ticket, ulong.MaxValue, out result);
}
/// <summary>
/// Opens a position with the specified parameters.
/// </summary>
@@ -559,7 +607,7 @@ namespace MtApi5
/// <param name="comment">comment</param>
/// <param name="result">output result</param>
/// <returns>true - successful check of the basic structures, otherwise - false.</returns>
public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, string comment , out MqlTradeResult result)
public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, string comment, out MqlTradeResult result)
{
Log.Debug($"PositionOpen: symbol = {symbol}, orderType = {orderType}, volume = {volume}, price = {price}, sl = {sl}, tp = {tp}, comment = {comment}");
@@ -577,15 +625,31 @@ namespace MtApi5
result = response?.TradeResult;
return response != null && response.RetVal;
}
/// <summary>
/// Opens a position with the specified parameters.
/// </summary>
/// <param name="symbol">symbol</param>
/// <param name="orderType">order type to open position </param>
/// <param name="volume">position volume</param>
/// <param name="price">execution price</param>
/// <param name="sl">Stop Loss price</param>
/// <param name="tp">Take Profit price</param>
/// <param name="result">output result</param>
/// <returns>true - successful check of the basic structures, otherwise - false.</returns>
public bool PositionOpen(string symbol, ENUM_ORDER_TYPE orderType, double volume, double price, double sl, double tp, out MqlTradeResult result)
{
return PositionOpen(symbol, orderType, volume, price, sl, tp, "", out result);
}
#endregion
#region Account Information functions
///<summary>
///Returns the value of the corresponding account property.
///</summary>
///<param name="propertyId">Identifier of the property.</param>
public double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE propertyId)
///<summary>
///Returns the value of the corresponding account property.
///</summary>
///<param name="propertyId">Identifier of the property.</param>
public double AccountInfoDouble(ENUM_ACCOUNT_INFO_DOUBLE propertyId)
{
var commandParameters = new ArrayList { (int)propertyId };
@@ -734,7 +798,7 @@ namespace MtApi5
ratesArray = new MqlRates[retVal.Length];
for(var i = 0; i < retVal.Length; i++)
{
ratesArray[i] = new MqlRates(Mt5TimeConverter.ConvertFromMtTime(retVal[i].time)
ratesArray[i] = new MqlRates(retVal[i].time
, retVal[i].open
, retVal[i].high
, retVal[i].low
@@ -768,7 +832,7 @@ namespace MtApi5
ratesArray = new MqlRates[retVal.Length];
for (var i = 0; i < retVal.Length; i++)
{
ratesArray[i] = new MqlRates(Mt5TimeConverter.ConvertFromMtTime(retVal[i].time)
ratesArray[i] = new MqlRates(retVal[i].time
, retVal[i].open
, retVal[i].high
, retVal[i].low
@@ -802,7 +866,7 @@ namespace MtApi5
ratesArray = new MqlRates[retVal.Length];
for (var i = 0; i < retVal.Length; i++)
{
ratesArray[i] = new MqlRates(Mt5TimeConverter.ConvertFromMtTime(retVal[i].time)
ratesArray[i] = new MqlRates(retVal[i].time
, retVal[i].open
, retVal[i].high
, retVal[i].low
@@ -1412,19 +1476,27 @@ namespace MtApi5
///<param name="tick"> Link to the structure of the MqlTick type, to which the current prices and time of the last price update will be placed.</param>
public bool SymbolInfoTick(string symbol, out MqlTick tick)
{
var commandParameters = new ArrayList { symbol };
var retVal = SendCommand<MtMqlTick>(Mt5CommandType.SymbolInfoTick, commandParameters);
tick = null;
if (retVal != null)
tick = SendRequest<MqlTick>(new SymbolInfoTickRequest
{
tick = new MqlTick { MtTime = retVal.time, ask = retVal.ask, bid = retVal.bid, last = retVal.last, volume = retVal.volume };
}
SymbolName = symbol
});
return tick != null;
}
///<summary>
///The function returns current prices of a specified symbol in a variable of the MqlTick type.
///</summary>
///<param name="symbol">Symbol name.</param>
public MqlTick SymbolInfoTick(string symbol)
{
var tick = SendRequest<MqlTick>(new SymbolInfoTickRequest
{
SymbolName = symbol
});
return tick;
}
///<summary>
///Allows receiving time of beginning and end of the specified quoting sessions for a specified symbol and weekday.
@@ -2022,9 +2094,24 @@ namespace MtApi5
///<param name="nwin">Number of the chart subwindow. 0 means the main chart window. The specified subwindow must exist, otherwise the function returns false.</param>
///<param name="time">The time coordinate of the first anchor.</param>
///<param name="price">The price coordinate of the first anchor point.</param>
public bool ObjectCreate(long chartId, string name, ENUM_OBJECT type, int nwin, DateTime time, double price)
///<param name="listOfCoordinates">List of further anchor points (tuple of time and price).</param>
public bool ObjectCreate(long chartId, string name, ENUM_OBJECT type, int nwin, DateTime time, double price, List<Tuple<DateTime, double>> listOfCoordinates = null)
{
var commandParameters = new ArrayList { chartId, name, (int)type, nwin, Mt5TimeConverter.ConvertToMtTime(time), price };
//Count the additional coordinates
int iAdditionalCoordinates = (listOfCoordinates != null) ? listOfCoordinates.Count() : 0;
if(iAdditionalCoordinates > 29)
{
throw new ArgumentOutOfRangeException("listOfCoordinates", "The maximum amount of coordinates in 30.");
}
int nParameter = 6 + iAdditionalCoordinates * 2;
var commandParameters = new ArrayList { nParameter, chartId, name, (int)type, nwin, Mt5TimeConverter.ConvertToMtTime(time), price };
foreach (Tuple<DateTime, double> coordinateTuple in listOfCoordinates)
{
commandParameters.Add(Mt5TimeConverter.ConvertToMtTime(coordinateTuple.Item1));
commandParameters.Add(coordinateTuple.Item2);
}
return SendCommand<bool>(Mt5CommandType.ObjectCreate, commandParameters);
}
@@ -2887,6 +2974,135 @@ namespace MtApi5
#endregion
#region Global Variables
///<summary>
///Checks the existence of a global variable with the specified name.
///</summary>
///<param name="name">Global variable name.</param>
public bool GlobalVariableCheck(string name)
{
var commandParameters = new ArrayList { name };
return SendCommand<bool>(Mt5CommandType.GlobalVariableCheck, commandParameters);
}
///<summary>
///Returns the time when the global variable was last accessed.
///</summary>
///<param name="name">Name of the global variable.</param>
public DateTime GlobalVariableTime(string name)
{
var commandParameters = new ArrayList { name };
var res = SendCommand<int>(Mt5CommandType.GlobalVariableTime, commandParameters);
return Mt5TimeConverter.ConvertFromMtTime(res);
}
///<summary>
///Deletes a global variable from the client terminal.
///</summary>
///<param name="name">Name of the global variable.</param>
public bool GlobalVariableDel(string name)
{
var commandParameters = new ArrayList { name };
return SendCommand<bool>(Mt5CommandType.GlobalVariableDel, commandParameters);
}
///<summary>
///Returns the value of an existing global variable of the client terminal.
///</summary>
///<param name="name">Global variable name.</param>
public double GlobalVariableGet(string name)
{
var commandParameters = new ArrayList { name };
return SendCommand<double>(Mt5CommandType.GlobalVariableGet, commandParameters);
}
///<summary>
///Returns the name of a global variable by its ordinal number.
///</summary>
///<param name="index">Sequence number in the list of global variables. It should be greater than or equal to 0 and less than GlobalVariablesTotal().</param>
public string GlobalVariableName(int index)
{
var commandParameters = new ArrayList { index };
return SendCommand<string>(Mt5CommandType.GlobalVariableName, commandParameters);
}
///<summary>
///Sets a new value for a global variable. If the variable does not exist, the system creates a new global variable.
///</summary>
///<param name="name">Global variable name.</param>
///<param name="value">The new numerical value.</param>
public DateTime GlobalVariableSet(string name, double value)
{
var commandParameters = new ArrayList { name, value };
var res = SendCommand<int>(Mt5CommandType.GlobalVariableSet, commandParameters);
return Mt5TimeConverter.ConvertFromMtTime(res);
}
///<summary>
///Forcibly saves contents of all global variables to a disk.
///</summary>
public void GlobalVariablesFlush()
{
SendCommand<object>(Mt5CommandType.GlobalVariablesFlush, null);
}
///<summary>
///The function attempts to create a temporary global variable. If the variable doesn't exist, the system creates a new temporary global variable.
///</summary>
///<param name="name">The name of a temporary global variable.</param>
public bool GlobalVariableTemp(string name)
{
var commandParameters = new ArrayList { name };
return SendCommand<bool>(Mt5CommandType.GlobalVariableTemp, commandParameters);
}
///<summary>
///Sets the new value of the existing global variable if the current value equals to the third parameter check_value. If there is no global variable, the function will generate an error ERR_GLOBALVARIABLE_NOT_FOUND (4501) and return false.
///</summary>
///<param name="name">The name of a global variable.</param>
///<param name="value">New value.</param>
///<param name="checkValue">The value to check the current value of the global variable.</param>
public bool GlobalVariableSetOnCondition(string name, double value, double checkValue)
{
var commandParameters = new ArrayList { name, value, checkValue };
return SendCommand<bool>(Mt5CommandType.GlobalVariableSetOnCondition, commandParameters);
}
///<summary>
///Deletes global variables of the client terminal.
///</summary>
///<param name="prefixName">Name prefix global variables to remove. If you specify a prefix NULL or empty string, then all variables that meet the data criterion will be deleted.</param>
///<param name="limitData">Date to select global variables by the time of their last modification. The function removes global variables, which were changed before this date. If the parameter is zero, then all variables that meet the first criterion (prefix) are deleted.</param>
public int GlobalVariablesDeleteAll(string prefixName = "", DateTime? limitData = null)
{
if (prefixName == null)
prefixName = "";
var commandParameters = new ArrayList { prefixName, Mt5TimeConverter.ConvertToMtTime(limitData) };
return SendCommand<int>(Mt5CommandType.GlobalVariablesDeleteAll, commandParameters);
}
///<summary>
///Returns the total number of global variables of the client terminal.
///</summary>
public int GlobalVariablesTotal()
{
return SendCommand<int>(Mt5CommandType.GlobalVariablesTotal, null);
}
#endregion
#region Backtesting functions
///<summary>
///The function unlock ticks in backtesting mode.
///</summary>
public void UnlockTicks()
{
SendCommand<object>(Mt5CommandType.UnlockTicks, null);
}
#endregion
#endregion // Public Methods
#region Properties
@@ -2934,6 +3150,8 @@ namespace MtApi5
public event EventHandler<Mt5ConnectionEventArgs> ConnectionStateChanged;
public event EventHandler<Mt5TradeTransactionEventArgs> OnTradeTransaction;
public event EventHandler<Mt5BookEventArgs> OnBookEvent;
public event EventHandler<Mt5TimeBarArgs> OnLastTimeBar;
public event EventHandler<Mt5LockTicksEventArgs> OnLockTicks;
#endregion
#region Private Methods
@@ -3002,24 +3220,14 @@ namespace MtApi5
}
}
private void _client_MtEventReceived(MtEvent e)
{
var eventType = (Mt5EventTypes)e.EventType;
switch (eventType)
{
case Mt5EventTypes.OnTradeTransaction:
ReceivedOnTradeTransaction(e.ExpertHandle, e.Payload);
break;
case Mt5EventTypes.OnBookEvent:
ReceivedOnBookEvent(e.ExpertHandle, e.Payload);
break;
default:
throw new ArgumentOutOfRangeException();
}
_mtEventHandlers[eventType](e.ExpertHandle, e.Payload);
}
private void ReceivedOnTradeTransaction(int expertHandler, string payload)
private void ReceivedOnTradeTransactionEvent(int expertHandler, string payload)
{
var e = JsonConvert.DeserializeObject<OnTradeTransactionEvent>(payload);
OnTradeTransaction?.Invoke(this, new Mt5TradeTransactionEventArgs
@@ -3041,6 +3249,33 @@ namespace MtApi5
});
}
private void ReceivedOnTickEvent(int expertHandler, string payload)
{
var e = JsonConvert.DeserializeObject<OnTickEvent>(payload);
var quote = new Mt5Quote(e.Instrument, e.Tick.bid, e.Tick.ask)
{
ExpertHandle = expertHandler,
Volume = e.Tick.volume,
Time = e.Tick.time,
Last = e.Tick.last
};
QuoteUpdated?.Invoke(this, quote.Instrument, quote.Bid, quote.Ask);
QuoteUpdate?.Invoke(this, new Mt5QuoteEventArgs(quote));
}
private void ReceivedOnLastTimeBarEvent(int expertHandler, string payload)
{
var e = JsonConvert.DeserializeObject<OnLastTimeBarEvent>(payload);
OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandler, e.Instrument, e.Rates));
}
private void ReceivedOnLockTicksEvent(int expertHandler, string payload)
{
var e = JsonConvert.DeserializeObject<OnLockTicksEvent>(payload);
OnLockTicks?.Invoke(this, new Mt5LockTicksEventArgs(e.Instrument));
}
private void Connect(string host, int port)
{
var client = new MtClient(host, port);
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.18")]
[assembly: AssemblyFileVersion("1.0.18")]
[assembly: AssemblyVersion("1.0.20")]
[assembly: AssemblyFileVersion("1.0.20")]
+10
View File
@@ -0,0 +1,10 @@
namespace MtApi5.Requests
{
internal class PositionCloseRequest : RequestBase
{
public override RequestType RequestType => RequestType.PositionClose;
public ulong Ticket { get; set; }
public ulong Deviation { get; set; }
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace MtApi5.Requests
{
internal class PositionCloseResult
{
public bool RetVal { get; set; }
public MqlTradeResult TradeResult { get; set; }
}
}
+3 -1
View File
@@ -14,6 +14,8 @@ namespace MtApi5.Requests
IndicatorCreate = 7,
SymbolInfoString = 8,
ChartTimePriceToXY = 9,
ChartXYToTimePrice = 10
ChartXYToTimePrice = 10,
PositionClose = 11,
SymbolInfoTick = 12
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MtApi5.Requests
{
internal class SymbolInfoTickRequest : RequestBase
{
public override RequestType RequestType => RequestType.SymbolInfoTick;
public string SymbolName { get; set; }
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net40" />
</packages>
+14 -15
View File
@@ -1,24 +1,23 @@
# MtApi - .NET API for MetaTrader trading platform (MetaQuotes).
MtApi provides an .NET API interface to work with famous trading platfroms MetaTrader4 and MetaTrader5 (MetaQuotes).
The api is using directly connection to MetaTrader terminal and is working with MQL functions and the most functions of the api have MQL interface.
# MtApi - .NET API for MetaTrader Trading Platform (MetaQuotes).
MtApi provides a .NET API to work with famous trading platfroms MetaTrader4 and MetaTrader5 (MetaQuotes).
The API connects directly to the MetaTrader terminal and works with MQL functions. Most functions of the API have MQL interface.
The connection can be local or remote (by TCP).
# MtApi structure
# MtApi Structure
The project has two parts:
- client side (C#): MtApi and MtApi5;
- server side (C# and C++/CLI): MTApiService, MTConnector, MT5Connector, MQL experts.
Server side was designed with using WCF framework so it can be flaxible to setup connections but can be more slow compared with another connections types (for example, shared memory).
MTApiService is common engine communication project of the API for MT4 and MT5.
MTApiService library should be placed in Windows GAC (Global Assembly Cache). Installers in the project will copied it to GAC automatically.
Server side was designed using WCF framework with the intention of using flexibility to setup connections. One downside of using the WCF framework is the slower speed compared to other connection types (for example, shared memory).
MTApiService is a common engine communication project of the API for MT4 and MT5.
MTApiService library should be placed in Windows GAC (Global Assembly Cache). Installers in the project will be copied to GAC automatically.
# How to build solution
The project is supported by Visual Studio 2015.
It also requires WIX Tools (http://wixtoolset.org/).
# How to Build Solution
The project is supported by Visual Studio 2015 and requires WIX Tools (http://wixtoolset.org/).
To make api for MetaTrader4 use MtApiInstaller and for MetaTrader5 use MtApi5Installer.
All installers will be placed in folder "[root]\build\installers\" and all *.dll files will be placed in "[root]\build\products\".
MQL files have been build to ex4 and stored into folders "mq4" for MetaTrader and "mq5" for MetaTrader5. They are ready to using in terminals.
If you change source code of MQL expert you have to recompile it with MetaEditor. In this case you need to copy files "hash.mqh" and "json.mqh" to MetaEditor include folder.
To make an API for MetaTrader4 use MtApiInstaller and for MetaTrader5 use MtApi5Installer.
All installers will be placed in the folder "[root]\build\installers\" and all *.dll files will be placed in "[root]\build\products\".
MQL files have been build to ex4 and stored into folders "mq4" for MetaTrader and "mq5" for MetaTrader5. They are ready to be used in terminals.
Changing the source code of MQL expert requires recompilation with MetaEditor. Resulting in the need to copy files "hash.mqh" and "json.mqh" to the MetaEditor include folder.
# Home website
# Home Website
Please visit http://mtapi4.net
+55 -5
View File
@@ -481,10 +481,21 @@
</WrapPanel>
</TabItem>
<TabItem Header="CTrade">
<WrapPanel VerticalAlignment="Top" Margin="5">
<Button Command="{Binding PositionOpenCommand}" Content="PositionOpen" Margin="2"/>
</WrapPanel>
<TabItem Header="CTrade (Positions)">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Command="{Binding PositionOpenCommand}" Content="PositionOpen" Margin="2" HorizontalAlignment="Left"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="4">
<TextBlock Text="Ticket:" VerticalAlignment="Center"/>
<TextBox Text="{Binding PositionTicketValue}" Width="150" Margin="2"/>
<Button Command="{Binding PositionCloseCommand}" Content="PositionClose" Margin="2"/>
</StackPanel>
<Button Grid.Row="2" Command="{Binding PositionCloseAllCommand}" Content="PositionCloseAll" Margin="2" HorizontalAlignment="Left"/>
</Grid>
</TabItem>
<TabItem Header="Indicators">
@@ -565,6 +576,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WrapPanel VerticalAlignment="Top" Margin="5">
@@ -572,7 +584,9 @@
<Button Command="{Binding ResetLastErrorCommand}" Content="ResetLastError" Margin="2"/>
</WrapPanel>
<Grid Margin="10" Grid.Row="1">
<Button Grid.Row="1" Content="UnlockTicks" HorizontalAlignment="Left" Margin="5" Command="{Binding UnlockTicksCommand}"/>
<Grid Margin="10" Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
@@ -586,6 +600,42 @@
</Grid>
</Grid>
</TabItem>
<TabItem Header="Global Variables">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="Global Variable Name" Margin="2,0,0,0"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding GlobalVarName}" Margin="4,0,0,0"/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="Global Variable Value" Margin="2,2,0,0"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding GlobalVarValue}" Margin="4,2,0,0"/>
</Grid>
<WrapPanel VerticalAlignment="Top" Grid.Row="1" Margin="0,5,0,0">
<Button Command="{Binding GlobalVariableCheckCommand}" Content="GlobalVariableCheck" Margin="2"/>
<Button Command="{Binding GlobalVariableTimeCommand}" Content="GlobalVariableTime" Margin="2"/>
<Button Command="{Binding GlobalVariableDelCommand}" Content="GlobalVariableDel" Margin="2"/>
<Button Command="{Binding GlobalVariableGetCommand}" Content="GlobalVariableGet" Margin="2"/>
<Button Command="{Binding GlobalVariableNameCommand}" Content="GlobalVariableName" Margin="2"/>
<Button Command="{Binding GlobalVariableSetCommand}" Content="GlobalVariableSet" Margin="2"/>
<Button Command="{Binding GlobalVariablesFlushCommand}" Content="GlobalVariablesFlush" Margin="2"/>
<Button Command="{Binding GlobalVariableTempCommand}" Content="GlobalVariableTemp" Margin="2"/>
<Button Command="{Binding GlobalVariableSetOnConditionCommand}" Content="GlobalVariableSetOnCondition" Margin="2"/>
<Button Command="{Binding GlobalVariablesDeleteAllCommand}" Content="GlobalVariablesDeleteAll" Margin="2"/>
<Button Command="{Binding GlobalVariablesTotalCommand}" Content="GlobalVariablesTotal" Margin="2"/>
</WrapPanel>
</Grid>
</TabItem>
</TabControl>
</Grid>
+191 -8
View File
@@ -66,6 +66,8 @@ namespace MtApi5TestClient
public DelegateCommand MarketBookGetCommand { get; private set; }
public DelegateCommand PositionOpenCommand { get; private set; }
public DelegateCommand PositionCloseCommand { get; private set; }
public DelegateCommand PositionCloseAllCommand { get; private set; }
public DelegateCommand GetLastErrorCommand { get; private set; }
public DelegateCommand ResetLastErrorCommand { get; private set; }
@@ -108,6 +110,20 @@ namespace MtApi5TestClient
public DelegateCommand TimeTradeServerCommand { get; private set; }
public DelegateCommand TimeLocalCommand { get; private set; }
public DelegateCommand TimeGMTCommand { get; private set; }
public DelegateCommand GlobalVariableCheckCommand { get; private set; }
public DelegateCommand GlobalVariableTimeCommand { get; private set; }
public DelegateCommand GlobalVariableDelCommand { get; private set; }
public DelegateCommand GlobalVariableGetCommand { get; private set; }
public DelegateCommand GlobalVariableNameCommand { get; private set; }
public DelegateCommand GlobalVariableSetCommand { get; private set; }
public DelegateCommand GlobalVariablesFlushCommand { get; private set; }
public DelegateCommand GlobalVariableTempCommand { get; private set; }
public DelegateCommand GlobalVariableSetOnConditionCommand { get; private set; }
public DelegateCommand GlobalVariablesDeleteAllCommand { get; private set; }
public DelegateCommand GlobalVariablesTotalCommand { get; private set; }
public DelegateCommand UnlockTicksCommand { get; private set; }
#endregion
#region Properties
@@ -229,6 +245,39 @@ namespace MtApi5TestClient
OnPropertyChanged("ChartFunctionsChartIdValue");
}
}
private string _globalVarName;
public string GlobalVarName
{
get { return _globalVarName; }
set
{
_globalVarName = value;
OnPropertyChanged("GlobalVarName");
}
}
private double _globalVarValue;
public double GlobalVarValue
{
get { return _globalVarValue; }
set
{
_globalVarValue = value;
OnPropertyChanged("GlobalVarValue");
}
}
private ulong _positionTicketValue;
public ulong PositionTicketValue
{
get { return _positionTicketValue; }
set
{
_positionTicketValue = value;
OnPropertyChanged("PositionTicketValue");
}
}
#endregion
#region Public Methods
@@ -240,10 +289,11 @@ namespace MtApi5TestClient
_mtApiClient.ConnectionStateChanged += mMtApiClient_ConnectionStateChanged;
_mtApiClient.QuoteAdded += mMtApiClient_QuoteAdded;
_mtApiClient.QuoteRemoved += mMtApiClient_QuoteRemoved;
_mtApiClient.QuoteUpdated += mMtApiClient_QuoteUpdated;
_mtApiClient.QuoteUpdate += mMtApiClient_QuoteUpdate;
_mtApiClient.OnTradeTransaction += mMtApiClient_OnTradeTransaction;
_mtApiClient.OnBookEvent += _mtApiClient_OnBookEvent;
_mtApiClient.OnLastTimeBar += _mtApiClient_OnLastTimeBar;
_mtApiClient.OnLockTicks += _mtApiClient_OnLockTicks;
ConnectionState = _mtApiClient.ConnectionState;
ConnectionMessage = "Disconnected";
@@ -325,6 +375,8 @@ namespace MtApi5TestClient
MarketBookGetCommand = new DelegateCommand(ExecuteMarketBookGet);
PositionOpenCommand = new DelegateCommand(ExecutePositionOpen);
PositionCloseCommand = new DelegateCommand(ExecutePositionClose);
PositionCloseAllCommand = new DelegateCommand(ExecutePositionCloseAll);
PrintCommand = new DelegateCommand(ExecutePrint);
AlertCommand = new DelegateCommand(ExecuteAlert);
@@ -366,6 +418,20 @@ namespace MtApi5TestClient
TimeTradeServerCommand = new DelegateCommand(ExecuteTimeTradeServer);
TimeLocalCommand = new DelegateCommand(ExecuteTimeLocal);
TimeGMTCommand = new DelegateCommand(ExecuteTimeGMT);
GlobalVariableCheckCommand = new DelegateCommand(ExecuteGlobalVariableCheck);
GlobalVariableTimeCommand = new DelegateCommand(ExecuteGlobalVariableTime);
GlobalVariableDelCommand = new DelegateCommand(ExecuteGlobalVariableDel);
GlobalVariableGetCommand = new DelegateCommand(ExecuteGlobalVariableGet);
GlobalVariableNameCommand = new DelegateCommand(ExecuteGlobalVariableName);
GlobalVariableSetCommand = new DelegateCommand(ExecuteGlobalVariableSet);
GlobalVariablesFlushCommand = new DelegateCommand(ExecuteGlobalVariablesFlush);
GlobalVariableTempCommand = new DelegateCommand(ExecuteGlobalVariableTemp);
GlobalVariableSetOnConditionCommand = new DelegateCommand(ExecuteGlobalVariableSetOnCondition);
GlobalVariablesDeleteAllCommand = new DelegateCommand(ExecuteGlobalVariablesDeleteAll);
GlobalVariablesTotalCommand = new DelegateCommand(ExecuteGlobalVariablesTotal);
UnlockTicksCommand = new DelegateCommand(ExecuteUnlockTicks);
}
private bool CanExecuteConnect(object o)
@@ -762,7 +828,7 @@ namespace MtApi5TestClient
foreach (var rates in result)
{
TimeSeriesResults.Add(
$"time={rates.time}; open={rates.open}; high={rates.high}; low={rates.low}; close={rates.close}; tick_volume={rates.tick_volume}; spread={rates.spread}; real_volume={rates.tick_volume}");
$"time={rates.time}; mt_time={rates.mt_time}; open={rates.open}; high={rates.high}; low={rates.low}; close={rates.close}; tick_volume={rates.tick_volume}; spread={rates.spread}; real_volume={rates.tick_volume}");
}
});
@@ -926,6 +992,12 @@ namespace MtApi5TestClient
{
var retVal = await Execute(() => _mtApiClient.SymbolInfoDouble("EURUSD", ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BID));
AddLog($"SymbolInfoDouble(EURUSD, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BID): result = {retVal}");
retVal = await Execute(() => _mtApiClient.SymbolInfoDouble("EURUSD", ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_REAL));
AddLog($"SymbolInfoDouble(EURUSD, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_REAL): result = {retVal}");
retVal = await Execute(() => _mtApiClient.SymbolInfoDouble("EURUSD", ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUMEHIGH_REAL));
AddLog($"SymbolInfoDouble(EURUSD, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUMEHIGH_REAL): result = {retVal}");
retVal = await Execute(() => _mtApiClient.SymbolInfoDouble("EURUSD", ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUMELOW_REAL));
AddLog($"SymbolInfoDouble(EURUSD, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUMELOW_REAL): result = {retVal}");
}
private async void ExecuteSymbolInfoInteger(object o)
@@ -964,6 +1036,7 @@ namespace MtApi5TestClient
AddLog($"SymbolInfoTick(EURUSD) tick.ask = {result.ask}");
AddLog($"SymbolInfoTick(EURUSD) tick.last = {result.last}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume = {result.volume}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume_real = {result.volume_real}");
}
private async void ExecuteSymbolInfoSessionQuote(object o)
@@ -1034,7 +1107,7 @@ namespace MtApi5TestClient
for (var i = 0; i < result.Length; i++)
{
AddLog($"MarketBookGet: [{i}] - {result[i].price} | {result[i].volume} | {result[i].type}");
AddLog($"MarketBookGet: [{i}] - {result[i].price} | {result[i].volume} | {result[i].type} | {result[i].volume_real}");
}
}
@@ -1053,6 +1126,21 @@ namespace MtApi5TestClient
AddLog($"PositionOpen: symbol EURUSD retVal = {retVal}, result = {tradeResult}");
}
private async void ExecutePositionClose(object obj)
{
var ticket = PositionTicketValue;
MqlTradeResult tradeResult = null;
var retVal = await Execute(() => _mtApiClient.PositionClose(ticket, out tradeResult));
AddLog($"PositionClose: ticket {ticket} retVal = {retVal}, result = {tradeResult}");
}
private async void ExecutePositionCloseAll(object obj)
{
var retVal = await Execute(() => _mtApiClient.PositionCloseAll());
AddLog($"PositionCloseAll: count = {retVal}");
}
private async void ExecutePrint(object obj)
{
var message = MessageText;
@@ -1116,6 +1204,86 @@ namespace MtApi5TestClient
AddLog($"TimeGMT: {retVal}");
}
#region Global Variable Commands
private async void ExecuteGlobalVariableCheck(object obj)
{
var name = GlobalVarName;
var retVal = await Execute(() => _mtApiClient.GlobalVariableCheck(name));
AddLog($"GlobalVariableCheck: {retVal}");
}
private async void ExecuteGlobalVariableTime(object obj)
{
var name = GlobalVarName;
var retVal = await Execute(() => _mtApiClient.GlobalVariableTime(name));
AddLog($"GlobalVariableTime: {retVal}");
}
private async void ExecuteGlobalVariableDel(object obj)
{
var name = GlobalVarName;
var retVal = await Execute(() => _mtApiClient.GlobalVariableDel(name));
AddLog($"GlobalVariableDel: {retVal}");
}
private async void ExecuteGlobalVariableGet(object obj)
{
var name = GlobalVarName;
var retVal = await Execute(() => _mtApiClient.GlobalVariableGet(name));
GlobalVarValue = retVal;
AddLog($"GlobalVariableGet: {retVal}");
}
private async void ExecuteGlobalVariableName(object obj)
{
var retVal = await Execute(() => _mtApiClient.GlobalVariableName(0));
GlobalVarName = retVal;
AddLog($"GlobalVariableName: {retVal}");
}
private async void ExecuteGlobalVariableSet(object obj)
{
var name = GlobalVarName;
var value = GlobalVarValue;
var retVal = await Execute(() => _mtApiClient.GlobalVariableSet(name, value));
AddLog($"GlobalVariableSet: {retVal}");
}
private void ExecuteGlobalVariablesFlush(object obj)
{
_mtApiClient.GlobalVariablesFlush();
AddLog("GlobalVariablesFlush: executed.");
}
private async void ExecuteGlobalVariableTemp(object obj)
{
var name = GlobalVarName;
var retVal = await Execute(() => _mtApiClient.GlobalVariableTemp(name));
AddLog($"GlobalVariableTemp: {retVal}");
}
private async void ExecuteGlobalVariableSetOnCondition(object obj)
{
var name = GlobalVarName;
var value = GlobalVarValue;
const double checkValue = 2;
var retVal = await Execute(() => _mtApiClient.GlobalVariableSetOnCondition(name, value, checkValue));
AddLog($"GlobalVariableSetOnCondition: {retVal}");
}
private async void ExecuteGlobalVariablesDeleteAll(object obj)
{
var retVal = await Execute(() => _mtApiClient.GlobalVariablesDeleteAll());
AddLog($"GlobalVariablesDeleteAll: {retVal}");
}
private async void ExecuteGlobalVariablesTotal(object obj)
{
var retVal = await Execute(() => _mtApiClient.GlobalVariablesTotal());
AddLog($"GlobalVariablesTotal: {retVal}");
}
#endregion
#region Chart Commands
private async void ExecuteChartOpen(object o)
{
@@ -1417,6 +1585,11 @@ namespace MtApi5TestClient
}
#endregion
private void ExecuteUnlockTicks(object o)
{
_mtApiClient.UnlockTicks();
}
private static void RunOnUiThread(Action action)
{
Application.Current?.Dispatcher.Invoke(action);
@@ -1427,13 +1600,13 @@ namespace MtApi5TestClient
Application.Current?.Dispatcher.Invoke(action, args);
}
private static void mMtApiClient_QuoteUpdated(object sender, string symbol, double bid, double ask)
{
Console.WriteLine(@"Quote: Symbol = {0}, Bid = {1}, Ask = {2}", symbol, bid, ask);
}
private void mMtApiClient_QuoteUpdate(object sender, Mt5QuoteEventArgs e)
{
var q = e.Quote;
Console.WriteLine(@"Quote: Symbol = {0}, Bid = {1}, Ask = {2}, Volume = {3}, Time = {4}, Last = {5}"
, q.Instrument, q.Bid, q.Ask, q.Volume, q.Time, q.Last);
if (_quotesMap.ContainsKey(e.Quote.ExpertHandle))
{
var qvm = _quotesMap[e.Quote.ExpertHandle];
@@ -1493,6 +1666,16 @@ namespace MtApi5TestClient
AddLog($"OnBookEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}");
}
private void _mtApiClient_OnLastTimeBar(object sender, Mt5TimeBarArgs e)
{
AddLog($"OnBookEvent: 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}");
}
private void _mtApiClient_OnLockTicks(object sender, Mt5LockTicksEventArgs e)
{
AddLog($"OnLockTicksEvent: Symbol = {e.Symbol}");
}
private void AddQuote(Mt5Quote quote)
{
if (_quotesMap.ContainsKey(quote.ExpertHandle))
BIN
View File
Binary file not shown.
+466 -65
View File
@@ -1,7 +1,7 @@
#property copyright "Vyacheslav Demidyuk"
#property link ""
#property version "1.5"
#property version "1.6"
#property description "MtApi (MT5) connection expert"
#include <json.mqh>
@@ -25,8 +25,6 @@
bool sendULongResponse(int expertHandle, ulong response, string& err);
bool sendLongArrayResponse(int expertHandle, long& values[], int size, string& err);
bool sendMqlRatesArrayResponse(int expertHandle, MqlRates& values[], int size, string& err);
bool sendMqlTickResponse(int expertHandle, MqlTick& response, string& err);
bool sendMqlBookInfoArrayResponse(int expertHandle, MqlBookInfo& values[], int size, string& err);
bool sendErrorResponse(int expertHandle, int code, string message, string& err);
bool sendEvent(int expertHandle, int eventType, string payload, string& err);
@@ -43,7 +41,15 @@
//#define __DEBUG_LOG__
enum LockTickType
{
NO_LOCK,
LOCK_EVERY_TICK,
LOCK_EVERY_CANDLE
};
input int Port = 8228;
input LockTickType BacktestingLockTicks = NO_LOCK;
int ExpertHandle;
@@ -53,6 +59,9 @@ bool isCrashed = false;
bool IsRemoteReadyForTesting = false;
long _last_bar_open_time = 0;
bool _is_ticks_locked = false;
string PARAM_SEPARATOR = ";";
int OnInit()
@@ -74,8 +83,48 @@ void OnDeinit(const int reason)
void OnTick()
{
start();
if (IsTesting()) OnTimer();
string symbol = Symbol();
bool lastbar_time_changed = false;
long lastbar_time = SeriesInfoInteger(symbol, Period(), SERIES_LASTBAR_DATE);
if (_last_bar_open_time != lastbar_time)
{
if (_last_bar_open_time != 0)
{
MqlRates rates_array[];
CopyRates(symbol, Period(), 1, 1, rates_array);
MtTimeBarEvent* time_bar = new MtTimeBarEvent(symbol, rates_array[0]);
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
delete time_bar;
lastbar_time_changed = true;
}
_last_bar_open_time = lastbar_time;
}
MqlTick last_tick;
SymbolInfoTick(Symbol(),last_tick);
MtOnTickEvent * tick_event = new MtOnTickEvent(symbol, last_tick);
SendMtEvent(ON_TICK_EVENT, tick_event);
delete tick_event;
if (IsTesting())
{
if (BacktestingLockTicks == LOCK_EVERY_TICK ||
(BacktestingLockTicks == LOCK_EVERY_CANDLE && lastbar_time_changed))
{
_is_ticks_locked = true;
MtLockTickEvent * lock_tick_event = new MtLockTickEvent(symbol);
SendMtEvent(ON_LOCK_TICKS_EVENT, lock_tick_event);
delete lock_tick_event;
}
OnTimer();
}
}
void OnTradeTransaction(
@@ -213,30 +262,17 @@ int deinit()
return (0);
}
int start()
{
MqlTick last_tick;
SymbolInfoTick(Symbol(),last_tick);
double Bid = last_tick.bid;
double Ask = last_tick.ask;
if (!updateQuote(ExpertHandle, Symbol(), Bid, Ask, _error))
{
Print("updateQuote: [ERROR] ", _error);
}
return (0);
}
void OnTimer()
{
while(true)
{
int executedCommand = executeCommand();
if (_is_ticks_locked)
continue;
if (executedCommand == 0)
{
return;
}
break;
}
}
@@ -494,9 +530,8 @@ int executeCommand()
case 56: //SymbolInfoString
Execute_SymbolInfoString();
break;
case 57: //SymbolInfoTick
Execute_SymbolInfoTick();
break;
// case 57: //SymbolInfoTick
// break;
case 58: //SymbolInfoSessionQuote
Execute_SymbolInfoSessionQuote();
break;
@@ -714,9 +749,48 @@ int executeCommand()
case 143: //ResetLastError
Execute_ResetLastError();
break;
case 146: //GlobalVariableCheck
Execute_GlobalVariableCheck();
break;
case 147: //GlobalVariableTime
Execute_GlobalVariableTime();
break;
case 148: //GlobalVariableDel
Execute_GlobalVariableDel();
break;
case 149: //GlobalVariableGet
Execute_GlobalVariableGet();
break;
case 150: //GlobalVariableName
Execute_GlobalVariableName();
break;
case 151: //GlobalVariableSet
Execute_GlobalVariableSet();
break;
case 152: //GlobalVariablesFlush
Execute_GlobalVariablesFlush();
break;
case 153: //TerminalInfoString
Execute_TerminalInfoString();
break;
case 154: //GlobalVariableTemp
Execute_GlobalVariableTemp();
break;
case 156: //GlobalVariableSetOnCondition
Execute_GlobalVariableSetOnCondition();
break;
case 157: //GlobalVariablesDeleteAll
Execute_GlobalVariablesDeleteAll();
break;
case 158: //GlobalVariablesTotal
Execute_GlobalVariablesTotal();
break;
case 159: //UnlockTiks
Execute_UnlockTicks();
break;
case 160: //PositionCloseAll
Execute_PositionCloseAll();
break;
case 204: //TerminalInfoInteger
Execute_TerminalInfoInteger();
break;
@@ -3073,37 +3147,6 @@ void Execute_SymbolInfoString()
}
}
void Execute_SymbolInfoTick()
{
string symbol;
StringInit(symbol, 100, 0);
if (!getStringValue(ExpertHandle, 0, symbol, _error))
{
PrintParamError("SymbolInfoTick", "symbol", _error);
sendErrorResponse(ExpertHandle, -1, _error, _response_error);
return;
}
MqlTick tick={0};
bool ok = SymbolInfoTick(symbol, tick);
if (ok)
{
if (!sendMqlTickResponse(ExpertHandle, tick, _response_error))
{
PrintResponseError("SymbolInfoTick", _response_error);
}
}
else
{
if (!sendVoidResponse(ExpertHandle, _response_error))
{
PrintResponseError("SymbolInfoTick", _response_error);
}
}
}
void Execute_SymbolInfoSessionQuote()
{
string symbol;
@@ -5668,6 +5711,114 @@ void Execute_ResetLastError()
SEND_VOID_RESPONSE
}
void Execute_GlobalVariableCheck()
{
string name;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s", __FUNCTION__, name);
#endif
bool res = GlobalVariableCheck(name);
SEND_BOOL_RESPONSE(res)
}
void Execute_GlobalVariableTime()
{
string name;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s", __FUNCTION__, name);
#endif
datetime time = GlobalVariableTime(name);
SEND_INT_RESPONSE((int)time)
}
void Execute_GlobalVariableDel()
{
string name;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s", __FUNCTION__, name);
#endif
bool res = GlobalVariableDel(name);
SEND_BOOL_RESPONSE(res)
}
void Execute_GlobalVariableGet()
{
string name;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s", __FUNCTION__, name);
#endif
double res = GlobalVariableGet(name);
SEND_DOUBLE_RESPONSE(res)
}
void Execute_GlobalVariableName()
{
int index;
GET_INT_VALUE(0, index, "index")
#ifdef __DEBUG_LOG__
PrintFormat("%s: index = %d", __FUNCTION__, index);
#endif
string name = GlobalVariableName(index);
SEND_STRING_RESPONSE(name)
}
void Execute_GlobalVariableSet()
{
string name;
double value;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
GET_DOUBLE_VALUE(1, value, "value")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s, value = %f", __FUNCTION__, name, value);
#endif
datetime res = GlobalVariableSet(name, value);
SEND_INT_RESPONSE((int)res)
}
void Execute_GlobalVariablesFlush()
{
#ifdef __DEBUG_LOG__
PrintFormat("%s: called.", __FUNCTION__);
#endif
GlobalVariablesFlush();
SEND_VOID_RESPONSE
}
void Execute_ChartOpen()
{
string symbol;
@@ -6256,6 +6407,106 @@ void Execute_TerminalInfoString()
}
}
void Execute_GlobalVariableTemp()
{
string name;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s", __FUNCTION__, name);
#endif
bool res = GlobalVariableTemp(name);
SEND_BOOL_RESPONSE(res)
}
void Execute_GlobalVariableSetOnCondition()
{
string name;
double value;
double check_value;
StringInit(name, 500);
GET_STRING_VALUE(0, name, "name")
GET_DOUBLE_VALUE(1, value, "value")
GET_DOUBLE_VALUE(2, check_value, "check_value")
#ifdef __DEBUG_LOG__
PrintFormat("%s: name = %s, value = %f, check_value = %f", __FUNCTION__, name, value, check_value);
#endif
bool res = GlobalVariableSetOnCondition(name, value, check_value);
#ifdef __DEBUG_LOG__
PrintFormat("%s: result = %s", __FUNCTION__, BoolToString(res));
#endif
SEND_BOOL_RESPONSE(res)
}
void Execute_GlobalVariablesDeleteAll()
{
string prefix_name;
int limit_data;
StringInit(prefix_name, 500);
GET_STRING_VALUE(0, prefix_name, "prefix_name")
GET_INT_VALUE(1, limit_data, "limit_data")
#ifdef __DEBUG_LOG__
PrintFormat("%s: prefix_name = %s, limit_data = %d", __FUNCTION__, prefix_name, limit_data);
#endif
int res = GlobalVariablesDeleteAll(prefix_name, (datetime)limit_data);
#ifdef __DEBUG_LOG__
PrintFormat("%s: result = %d", __FUNCTION__, res);
#endif
SEND_INT_RESPONSE(res)
}
void Execute_GlobalVariablesTotal()
{
int res = GlobalVariablesTotal();
#ifdef __DEBUG_LOG__
PrintFormat("%s: result = %d", __FUNCTION__, res);
#endif
SEND_INT_RESPONSE(res)
}
void Execute_UnlockTicks()
{
if (!IsTesting())
{
Print("WARNING: function UnlockTicks can be used only for backtesting");
return;
}
_is_ticks_locked = false;
if (!sendVoidResponse(ExpertHandle, _response_error))
{
PrintResponseError("UnlockTicks", _response_error);
}
}
void Execute_PositionCloseAll()
{
int res = PositionCloseAll();
#ifdef __DEBUG_LOG__
PrintFormat("%s: result = %d", __FUNCTION__, res);
#endif
SEND_INT_RESPONSE(res)
}
void Execute_TerminalInfoInteger()
{
int propertyId;
@@ -6443,6 +6694,18 @@ bool OrderCloseAll()
return true;
}
int PositionCloseAll()
{
CTrade trade;
int total = PositionsTotal();
int i = total -1;
while (i >= 0)
{
if (trade.PositionClose(PositionGetSymbol(i))) i--;
}
return total;
}
//------------ Requests -------------------------------------------------------
string OnRequest(string json)
@@ -6495,6 +6758,12 @@ string OnRequest(string json)
case 10: //ChartXYToTimePrice
response = ExecuteRequest_ChartXYToTimePrice(jo);
break;
case 11: //PositionClose
response = ExecuteRequest_PositionClose(jo);
break;
case 12: //SymbolInfoTick
response = ExecuteRequest_SymbolInfoTick(jo);
break;
default:
PrintFormat("%s [WARNING]: Unknown request type %d", __FUNCTION__, requestType);
response = CreateErrorResponse(-1, "Unknown request type");
@@ -6783,6 +7052,7 @@ JSONObject* MqlBookInfoToJson(MqlBookInfo& info)
jo.put("type", new JSONNumber((int)info.type));
jo.put("price", new JSONNumber(info.price));
jo.put("volume", new JSONNumber(info.volume));
jo.put("volume_real", new JSONNumber(info.volume_real));
return jo;
}
@@ -6975,12 +7245,65 @@ string ExecuteRequest_ChartXYToTimePrice(JSONObject *jo)
return CreateSuccessResponse("Value", result_value_jo);
}
string ExecuteRequest_PositionClose(JSONObject *jo)
{
//Ticket
CHECK_JSON_VALUE(jo, "Ticket", CreateErrorResponse(-1, "Undefinded mandatory parameter Ticket"));
ulong ticket = jo.getLong("Ticket");
//Deviation
CHECK_JSON_VALUE(jo, "Deviation", CreateErrorResponse(-1, "Undefinded mandatory parameter Deviation"));
ulong deviation = jo.getLong("Deviation");
#ifdef __DEBUG_LOG__
PrintFormat("%s: Ticket = %d, Deviation = %d", __FUNCTION__, ticket, deviation);
#endif
CTrade trade;
bool ok = trade.PositionClose(ticket, deviation);
MqlTradeResult trade_result={0};
trade.Result(trade_result);
#ifdef __DEBUG_LOG__
Print("ExecuteRequest_PositionClose: retcode = ", trade.ResultRetcode());
#endif
JSONObject* result_value_jo = new JSONObject();
result_value_jo.put("RetVal", new JSONBool(ok));
result_value_jo.put("TradeResult", MqlTradeResultToJson(trade_result));
return CreateSuccessResponse("Value", result_value_jo);
}
string ExecuteRequest_SymbolInfoTick(JSONObject *jo)
{
CHECK_JSON_VALUE(jo, "SymbolName", CreateErrorResponse(-1, "Undefinded mandatory parameter SymbolName"));
string symbol_name = jo.getString("SymbolName");
#ifdef __DEBUG_LOG__
PrintFormat("%s: symbol_name = %s", __FUNCTION__, symbol_name);
#endif
MqlTick tick={0};
bool ok = SymbolInfoTick(symbol_name, tick);
#ifdef __DEBUG_LOG__
PrintFormat("%s: ok = %s", __FUNCTION__, BoolToString(ok));
#endif
return CreateSuccessResponse("Value", MqlTickToJson(tick));
}
//------------ Events -------------------------------------------------------
enum MtEventTypes
{
ON_TRADE_TRANSACTION_EVENT = 1,
ON_BOOK_EVENT = 2
ON_BOOK_EVENT = 2,
ON_TICK_EVENT = 3,
ON_LAST_TIME_BAR_EVENT = 4,
ON_LOCK_TICKS_EVENT = 5
};
class MtEvent
@@ -7033,12 +7356,73 @@ private:
string _symbol;
};
class MtOnTickEvent : public MtEvent
{
public:
MtOnTickEvent(string symbol, const MqlTick& tick)
{
_symbol = symbol;
_tick = tick;
}
virtual JSONObject* CreateJson()
{
JSONObject *jo = new JSONObject();
jo.put("Tick", MqlTickToJson(_tick));
jo.put("Instrument", new JSONString(_symbol));
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
return jo;
}
private:
string _symbol;
MqlTick _tick;
};
class MtTimeBarEvent: public MtEvent
{
public:
MtTimeBarEvent(string symbol, const MqlRates& rates)
{
_symbol = symbol;
_rates = rates;
}
virtual JSONObject* CreateJson()
{
JSONObject *jo = new JSONObject();
jo.put("Rates", MqlRatesToJson(_rates));
jo.put("Instrument", new JSONString(_symbol));
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
return jo;
}
private:
string _symbol;
MqlRates _rates;
};
class MtLockTickEvent: public MtEvent
{
public:
MtLockTickEvent(string symbol)
{
_symbol = symbol;
}
virtual JSONObject* CreateJson()
{
JSONObject *jo = new JSONObject();
jo.put("Instrument", new JSONString(_symbol));
return jo;
}
private:
string _symbol;
};
void SendMtEvent(MtEventTypes eventType, MtEvent* mtEvent)
{
#ifdef __DEBUG_LOG__
PrintFormat("%s: eventType = %d", __FUNCTION__, eventType);
#endif
JSONObject* json = mtEvent.CreateJson();
if (sendEvent(ExpertHandle, (int)eventType, json.toString(), _error))
{
@@ -7070,9 +7454,11 @@ bool JsonToMqlTradeRequest(JSONObject *jo, MqlTradeRequest& request)
request.order = jo.getLong("Order");
//Symbol
CHECK_JSON_VALUE(jo, "Symbol", false);
StringInit(request.symbol, 100, 0);
request.symbol = jo.getString("Symbol");
if (jo.getValue("Symbol") != NULL)
{
StringInit(request.symbol, 100, 0);
request.symbol = jo.getString("Symbol");
}
//Volume
CHECK_JSON_VALUE(jo, "Volume", false);
@@ -7140,6 +7526,7 @@ JSONObject* MqlTickToJson(MqlTick& tick)
jo.put("ask", new JSONNumber(tick.ask));
jo.put("last", new JSONNumber(tick.last));
jo.put("volume", new JSONNumber(tick.volume));
jo.put("volume_real", new JSONNumber(tick.volume_real));
return jo;
}
@@ -7213,4 +7600,18 @@ JSONObject* MqlTradeRequestToJson(MqlTradeRequest& request)
jo.put("MtExpiration", new JSONNumber((int)request.expiration));
jo.put("Comment", new JSONString(request.comment));
return jo;
}
JSONObject* MqlRatesToJson(MqlRates& rates)
{
JSONObject *jo = new JSONObject();
jo.put("mt_time", new JSONNumber((int)rates.time));
jo.put("open", new JSONNumber(rates.open));
jo.put("high", new JSONNumber(rates.high));
jo.put("low", new JSONNumber(rates.low));
jo.put("close", new JSONNumber(rates.close));
jo.put("tick_volume", new JSONNumber(rates.tick_volume));
jo.put("spread", new JSONNumber(rates.spread));
jo.put("real_volume", new JSONNumber(rates.real_volume));
return jo;
}