mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-13 10:48:08 +00:00
Added Request/Response mechanism into mtapi. Added structure MtOrder. Added functions GetOrder, GetOrders.
This commit is contained in:
@@ -43,9 +43,14 @@
|
|||||||
</AssemblyOriginatorKeyFile>
|
</AssemblyOriginatorKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
@@ -56,8 +61,11 @@
|
|||||||
<Compile Include="ChartPeriod.cs" />
|
<Compile Include="ChartPeriod.cs" />
|
||||||
<Compile Include="ExtensionMethods.cs" />
|
<Compile Include="ExtensionMethods.cs" />
|
||||||
<Compile Include="MtConnectionEventArgs.cs" />
|
<Compile Include="MtConnectionEventArgs.cs" />
|
||||||
|
<Compile Include="MtConnectionException.cs" />
|
||||||
<Compile Include="MtConnectionState.cs" />
|
<Compile Include="MtConnectionState.cs" />
|
||||||
<Compile Include="MtCommandType.cs" />
|
<Compile Include="MtCommandType.cs" />
|
||||||
|
<Compile Include="MtExecutionException.cs" />
|
||||||
|
<Compile Include="MtOrder.cs" />
|
||||||
<Compile Include="MtQuote.cs" />
|
<Compile Include="MtQuote.cs" />
|
||||||
<Compile Include="MtQuoteEventArgs.cs" />
|
<Compile Include="MtQuoteEventArgs.cs" />
|
||||||
<Compile Include="MtTypes.cs" />
|
<Compile Include="MtTypes.cs" />
|
||||||
@@ -67,6 +75,14 @@
|
|||||||
<Compile Include="MtApiColorConverter.cs" />
|
<Compile Include="MtApiColorConverter.cs" />
|
||||||
<Compile Include="OrderSelectMode.cs" />
|
<Compile Include="OrderSelectMode.cs" />
|
||||||
<Compile Include="OrderSelectSource.cs" />
|
<Compile Include="OrderSelectSource.cs" />
|
||||||
|
<Compile Include="Requests\GetOrderRequest.cs" />
|
||||||
|
<Compile Include="Requests\GetOrdersRequest.cs" />
|
||||||
|
<Compile Include="Requests\RequestBase.cs" />
|
||||||
|
<Compile Include="Requests\RequestContainer.cs" />
|
||||||
|
<Compile Include="Requests\RequestType.cs" />
|
||||||
|
<Compile Include="Responses\GetOrderResponse.cs" />
|
||||||
|
<Compile Include="Responses\GetOrdersResponse.cs" />
|
||||||
|
<Compile Include="Responses\ResponseBase.cs" />
|
||||||
<Compile Include="SeriesIdentifier.cs" />
|
<Compile Include="SeriesIdentifier.cs" />
|
||||||
<Compile Include="TradeOperation.cs" />
|
<Compile Include="TradeOperation.cs" />
|
||||||
<Compile Include="MtApiTimeConverter.cs" />
|
<Compile Include="MtApiTimeConverter.cs" />
|
||||||
@@ -78,6 +94,10 @@
|
|||||||
<Name>MTApiService</Name>
|
<Name>MTApiService</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ using MTApiService;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.ServiceModel;
|
||||||
|
using MtApi.Requests;
|
||||||
|
using MtApi.Responses;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace MtApi
|
namespace MtApi
|
||||||
{
|
{
|
||||||
@@ -345,6 +349,18 @@ namespace MtApi
|
|||||||
{
|
{
|
||||||
return sendCommand<bool>(MtCommandType.OrderCloseAll, null);
|
return sendCommand<bool>(MtCommandType.OrderCloseAll, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MtOrder GetOrder(int index, OrderSelectMode select, OrderSelectSource pool)
|
||||||
|
{
|
||||||
|
var response = SendRequest<GetOrderResponse>(new GetOrderRequest { Index = index, Select = (int) select, Pool = (int) pool});
|
||||||
|
return response != null ? response.Order : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<MtOrder> GetOrders(OrderSelectSource pool)
|
||||||
|
{
|
||||||
|
var response = SendRequest<GetOrdersResponse>(new GetOrdersRequest { Pool = (int)pool });
|
||||||
|
return response != null ? response.Orders : null;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Check Status
|
#region Check Status
|
||||||
@@ -1310,6 +1326,38 @@ namespace MtApi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private T SendRequest<T>(RequestBase request) where T : ResponseBase, new()
|
||||||
|
{
|
||||||
|
if (request == null)
|
||||||
|
return default(T);
|
||||||
|
|
||||||
|
var serializer = RequestContainer.CreateNew(request).Serialize();
|
||||||
|
var commandParameters = new ArrayList { serializer };
|
||||||
|
|
||||||
|
MtResponseString res;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res = (MtResponseString)mClient.SendCommand((int)MtCommandType.MtRequest, commandParameters);
|
||||||
|
}
|
||||||
|
catch (CommunicationException ex)
|
||||||
|
{
|
||||||
|
throw new MtConnectionException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == null)
|
||||||
|
{
|
||||||
|
throw new MtExecutionException(-1, "Response from MetaTrader is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = JsonConvert.DeserializeObject<T>(res.Value);
|
||||||
|
if (response.ErrorCode != 0)
|
||||||
|
{
|
||||||
|
throw new MtExecutionException(response.ErrorCode, response.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
private void mClient_QuoteUpdated(MTApiService.MtQuote quote)
|
private void mClient_QuoteUpdated(MTApiService.MtQuote quote)
|
||||||
{
|
{
|
||||||
if (quote != null)
|
if (quote != null)
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ namespace MtApi
|
|||||||
RefreshRates = 150,
|
RefreshRates = 150,
|
||||||
//
|
//
|
||||||
TerminalInfoString = 153,
|
TerminalInfoString = 153,
|
||||||
SymbolInfoString = 154
|
SymbolInfoString = 154,
|
||||||
|
|
||||||
|
//Requests
|
||||||
|
MtRequest = 155
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MtApi
|
||||||
|
{
|
||||||
|
public class MtConnectionException: Exception
|
||||||
|
{
|
||||||
|
public MtConnectionException()
|
||||||
|
: this(null, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public MtConnectionException(string message)
|
||||||
|
: this(message, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public MtConnectionException(string message, Exception exception)
|
||||||
|
: base(message, exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MtApi
|
||||||
|
{
|
||||||
|
public class MtExecutionException: Exception
|
||||||
|
{
|
||||||
|
public MtExecutionException(int errorCode, string message)
|
||||||
|
:base(message)
|
||||||
|
{
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ErrorCode { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MtApi
|
||||||
|
{
|
||||||
|
public class MtOrder
|
||||||
|
{
|
||||||
|
public int Ticket { get; set; }
|
||||||
|
public string Symbol { get; set; }
|
||||||
|
public TradeOperation Operation { get; set; }
|
||||||
|
public double OpenPrice { get; set; }
|
||||||
|
public double ClosePrice { get; set; }
|
||||||
|
public double Lots { get; set; }
|
||||||
|
public int MtOpenTime { get; set; }
|
||||||
|
public int MtCloseTime { get; set; }
|
||||||
|
public double Profit { get; set; }
|
||||||
|
public string Comment { get; set; }
|
||||||
|
public double Commission { get; set; }
|
||||||
|
public int MagicNumber { get; set; }
|
||||||
|
|
||||||
|
public DateTime OpenTime
|
||||||
|
{
|
||||||
|
get { return MtApiTimeConverter.ConvertFromMtTime(MtOpenTime); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime CloseTime
|
||||||
|
{
|
||||||
|
get { return MtApiTimeConverter.ConvertFromMtTime(MtCloseTime); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace MtApi.Requests
|
||||||
|
{
|
||||||
|
public class GetOrderRequest: RequestBase
|
||||||
|
{
|
||||||
|
public int Index { get; set; }
|
||||||
|
public int Select { get; set; }
|
||||||
|
public int Pool { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MtApi.Requests
|
||||||
|
{
|
||||||
|
public class GetOrdersRequest: RequestBase
|
||||||
|
{
|
||||||
|
public int Pool { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace MtApi.Requests
|
||||||
|
{
|
||||||
|
public abstract class RequestBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace MtApi.Requests
|
||||||
|
{
|
||||||
|
public class RequestContainer
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, RequestType> RequestTypes = new Dictionary<Type, RequestType>();
|
||||||
|
|
||||||
|
static RequestContainer()
|
||||||
|
{
|
||||||
|
RequestTypes[typeof (GetOrderRequest)] = RequestType.GetOrder;
|
||||||
|
RequestTypes[typeof(GetOrdersRequest)] = RequestType.GetOrders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestType RequestType { get; set; }
|
||||||
|
public RequestBase Request { get; set; }
|
||||||
|
|
||||||
|
public virtual string Serialize()
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RequestContainer CreateNew<T>(T request) where T: RequestBase
|
||||||
|
{
|
||||||
|
if (RequestTypes.ContainsKey(request.GetType()) == false)
|
||||||
|
throw new ArgumentException("Unknown request type");
|
||||||
|
|
||||||
|
return new RequestContainer { RequestType = RequestTypes[request.GetType()], Request = request };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace MtApi.Requests
|
||||||
|
{
|
||||||
|
public enum RequestType
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
GetOrder = 1,
|
||||||
|
GetOrders = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MtApi.Responses
|
||||||
|
{
|
||||||
|
public class GetOrderResponse: ResponseBase
|
||||||
|
{
|
||||||
|
public MtOrder Order { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MtApi.Responses
|
||||||
|
{
|
||||||
|
public class GetOrdersResponse: ResponseBase
|
||||||
|
{
|
||||||
|
public List<MtOrder> Orders { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace MtApi.Responses
|
||||||
|
{
|
||||||
|
public class ResponseBase
|
||||||
|
{
|
||||||
|
public int ErrorCode { get; set; }
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" />
|
||||||
|
</packages>
|
||||||
Generated
+118
-24
@@ -28,6 +28,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
this.textBoxServerName = new System.Windows.Forms.TextBox();
|
this.textBoxServerName = new System.Windows.Forms.TextBox();
|
||||||
this.textBoxPort = new System.Windows.Forms.TextBox();
|
this.textBoxPort = new System.Windows.Forms.TextBox();
|
||||||
this.buttonConnect = new System.Windows.Forms.Button();
|
this.buttonConnect = new System.Windows.Forms.Button();
|
||||||
@@ -46,6 +47,10 @@
|
|||||||
this.listBoxEventLog = new System.Windows.Forms.ListBox();
|
this.listBoxEventLog = new System.Windows.Forms.ListBox();
|
||||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||||
|
this.button17 = new System.Windows.Forms.Button();
|
||||||
|
this.comboBox2 = new System.Windows.Forms.ComboBox();
|
||||||
|
this.comboBox1 = new System.Windows.Forms.ComboBox();
|
||||||
|
this.button16 = new System.Windows.Forms.Button();
|
||||||
this.label21 = new System.Windows.Forms.Label();
|
this.label21 = new System.Windows.Forms.Label();
|
||||||
this.textBoxIndexTicket = new System.Windows.Forms.TextBox();
|
this.textBoxIndexTicket = new System.Windows.Forms.TextBox();
|
||||||
this.comboBoxSelectedCommand = new System.Windows.Forms.ComboBox();
|
this.comboBoxSelectedCommand = new System.Windows.Forms.ComboBox();
|
||||||
@@ -79,6 +84,7 @@
|
|||||||
this.label9 = new System.Windows.Forms.Label();
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
this.listBoxSendedOrders = new System.Windows.Forms.ListBox();
|
this.listBoxSendedOrders = new System.Windows.Forms.ListBox();
|
||||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||||
|
this.buttonRefreshRates = new System.Windows.Forms.Button();
|
||||||
this.label22 = new System.Windows.Forms.Label();
|
this.label22 = new System.Windows.Forms.Label();
|
||||||
this.textBoxErrorCode = new System.Windows.Forms.TextBox();
|
this.textBoxErrorCode = new System.Windows.Forms.TextBox();
|
||||||
this.button3 = new System.Windows.Forms.Button();
|
this.button3 = new System.Windows.Forms.Button();
|
||||||
@@ -111,9 +117,10 @@
|
|||||||
this.button6 = new System.Windows.Forms.Button();
|
this.button6 = new System.Windows.Forms.Button();
|
||||||
this.listBoxProceHistory = new System.Windows.Forms.ListBox();
|
this.listBoxProceHistory = new System.Windows.Forms.ListBox();
|
||||||
this.tabPage6 = new System.Windows.Forms.TabPage();
|
this.tabPage6 = new System.Windows.Forms.TabPage();
|
||||||
|
this.button15 = new System.Windows.Forms.Button();
|
||||||
this.button14 = new System.Windows.Forms.Button();
|
this.button14 = new System.Windows.Forms.Button();
|
||||||
this.button13 = new System.Windows.Forms.Button();
|
this.button13 = new System.Windows.Forms.Button();
|
||||||
this.buttonRefreshRates = new System.Windows.Forms.Button();
|
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||||
this.groupBox1.SuspendLayout();
|
this.groupBox1.SuspendLayout();
|
||||||
this.statusStrip1.SuspendLayout();
|
this.statusStrip1.SuspendLayout();
|
||||||
this.groupBox2.SuspendLayout();
|
this.groupBox2.SuspendLayout();
|
||||||
@@ -202,7 +209,7 @@
|
|||||||
this.toolStripStatusConnection});
|
this.toolStripStatusConnection});
|
||||||
this.statusStrip1.Location = new System.Drawing.Point(0, 637);
|
this.statusStrip1.Location = new System.Drawing.Point(0, 637);
|
||||||
this.statusStrip1.Name = "statusStrip1";
|
this.statusStrip1.Name = "statusStrip1";
|
||||||
this.statusStrip1.Size = new System.Drawing.Size(638, 22);
|
this.statusStrip1.Size = new System.Drawing.Size(713, 22);
|
||||||
this.statusStrip1.TabIndex = 11;
|
this.statusStrip1.TabIndex = 11;
|
||||||
this.statusStrip1.Text = "statusStrip1";
|
this.statusStrip1.Text = "statusStrip1";
|
||||||
//
|
//
|
||||||
@@ -225,6 +232,9 @@
|
|||||||
//
|
//
|
||||||
// listViewQuotes
|
// listViewQuotes
|
||||||
//
|
//
|
||||||
|
this.listViewQuotes.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.listViewQuotes.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
this.listViewQuotes.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||||
this.colSymbol,
|
this.colSymbol,
|
||||||
this.colBid,
|
this.colBid,
|
||||||
@@ -256,14 +266,20 @@
|
|||||||
//
|
//
|
||||||
// listBoxEventLog
|
// listBoxEventLog
|
||||||
//
|
//
|
||||||
|
this.listBoxEventLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.listBoxEventLog.ContextMenuStrip = this.contextMenuStrip1;
|
||||||
this.listBoxEventLog.FormattingEnabled = true;
|
this.listBoxEventLog.FormattingEnabled = true;
|
||||||
this.listBoxEventLog.Location = new System.Drawing.Point(12, 543);
|
this.listBoxEventLog.Location = new System.Drawing.Point(12, 543);
|
||||||
this.listBoxEventLog.Name = "listBoxEventLog";
|
this.listBoxEventLog.Name = "listBoxEventLog";
|
||||||
this.listBoxEventLog.Size = new System.Drawing.Size(611, 82);
|
this.listBoxEventLog.Size = new System.Drawing.Size(690, 82);
|
||||||
this.listBoxEventLog.TabIndex = 14;
|
this.listBoxEventLog.TabIndex = 14;
|
||||||
//
|
//
|
||||||
// tabControl1
|
// tabControl1
|
||||||
//
|
//
|
||||||
|
this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.tabControl1.Controls.Add(this.tabPage2);
|
this.tabControl1.Controls.Add(this.tabPage2);
|
||||||
this.tabControl1.Controls.Add(this.tabPage1);
|
this.tabControl1.Controls.Add(this.tabPage1);
|
||||||
this.tabControl1.Controls.Add(this.tabPage3);
|
this.tabControl1.Controls.Add(this.tabPage3);
|
||||||
@@ -273,11 +289,15 @@
|
|||||||
this.tabControl1.Location = new System.Drawing.Point(12, 147);
|
this.tabControl1.Location = new System.Drawing.Point(12, 147);
|
||||||
this.tabControl1.Name = "tabControl1";
|
this.tabControl1.Name = "tabControl1";
|
||||||
this.tabControl1.SelectedIndex = 0;
|
this.tabControl1.SelectedIndex = 0;
|
||||||
this.tabControl1.Size = new System.Drawing.Size(615, 388);
|
this.tabControl1.Size = new System.Drawing.Size(690, 388);
|
||||||
this.tabControl1.TabIndex = 15;
|
this.tabControl1.TabIndex = 15;
|
||||||
//
|
//
|
||||||
// tabPage2
|
// tabPage2
|
||||||
//
|
//
|
||||||
|
this.tabPage2.Controls.Add(this.button17);
|
||||||
|
this.tabPage2.Controls.Add(this.comboBox2);
|
||||||
|
this.tabPage2.Controls.Add(this.comboBox1);
|
||||||
|
this.tabPage2.Controls.Add(this.button16);
|
||||||
this.tabPage2.Controls.Add(this.label21);
|
this.tabPage2.Controls.Add(this.label21);
|
||||||
this.tabPage2.Controls.Add(this.textBoxIndexTicket);
|
this.tabPage2.Controls.Add(this.textBoxIndexTicket);
|
||||||
this.tabPage2.Controls.Add(this.comboBoxSelectedCommand);
|
this.tabPage2.Controls.Add(this.comboBoxSelectedCommand);
|
||||||
@@ -290,26 +310,71 @@
|
|||||||
this.tabPage2.Location = new System.Drawing.Point(4, 22);
|
this.tabPage2.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage2.Name = "tabPage2";
|
this.tabPage2.Name = "tabPage2";
|
||||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage2.Size = new System.Drawing.Size(607, 362);
|
this.tabPage2.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage2.TabIndex = 1;
|
this.tabPage2.TabIndex = 1;
|
||||||
this.tabPage2.Text = "Trade Operations";
|
this.tabPage2.Text = "Trade Operations";
|
||||||
this.tabPage2.UseVisualStyleBackColor = true;
|
this.tabPage2.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
|
// button17
|
||||||
|
//
|
||||||
|
this.button17.Location = new System.Drawing.Point(601, 290);
|
||||||
|
this.button17.Name = "button17";
|
||||||
|
this.button17.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.button17.TabIndex = 12;
|
||||||
|
this.button17.Text = "GetOrders";
|
||||||
|
this.button17.UseVisualStyleBackColor = true;
|
||||||
|
this.button17.Click += new System.EventHandler(this.button17_Click);
|
||||||
|
//
|
||||||
|
// comboBox2
|
||||||
|
//
|
||||||
|
this.comboBox2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.comboBox2.FormattingEnabled = true;
|
||||||
|
this.comboBox2.Items.AddRange(new object[] {
|
||||||
|
"MODE_TRADES",
|
||||||
|
"MODE_HISTORY"});
|
||||||
|
this.comboBox2.Location = new System.Drawing.Point(481, 261);
|
||||||
|
this.comboBox2.Name = "comboBox2";
|
||||||
|
this.comboBox2.Size = new System.Drawing.Size(114, 21);
|
||||||
|
this.comboBox2.TabIndex = 11;
|
||||||
|
//
|
||||||
|
// comboBox1
|
||||||
|
//
|
||||||
|
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.comboBox1.FormattingEnabled = true;
|
||||||
|
this.comboBox1.Items.AddRange(new object[] {
|
||||||
|
"SELECT_BY_POS",
|
||||||
|
"SELECT_BY_TICKET"});
|
||||||
|
this.comboBox1.Location = new System.Drawing.Point(356, 261);
|
||||||
|
this.comboBox1.Name = "comboBox1";
|
||||||
|
this.comboBox1.Size = new System.Drawing.Size(119, 21);
|
||||||
|
this.comboBox1.TabIndex = 10;
|
||||||
|
//
|
||||||
|
// button16
|
||||||
|
//
|
||||||
|
this.button16.Location = new System.Drawing.Point(601, 261);
|
||||||
|
this.button16.Name = "button16";
|
||||||
|
this.button16.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.button16.TabIndex = 9;
|
||||||
|
this.button16.Text = "GetOrder";
|
||||||
|
this.button16.UseVisualStyleBackColor = true;
|
||||||
|
this.button16.Click += new System.EventHandler(this.button16_Click);
|
||||||
|
//
|
||||||
// label21
|
// label21
|
||||||
//
|
//
|
||||||
this.label21.AutoSize = true;
|
this.label21.AutoSize = true;
|
||||||
this.label21.Location = new System.Drawing.Point(213, 264);
|
this.label21.Location = new System.Drawing.Point(213, 264);
|
||||||
this.label21.Name = "label21";
|
this.label21.Name = "label21";
|
||||||
this.label21.Size = new System.Drawing.Size(36, 13);
|
this.label21.Size = new System.Drawing.Size(71, 13);
|
||||||
this.label21.TabIndex = 8;
|
this.label21.TabIndex = 8;
|
||||||
this.label21.Text = "Index:";
|
this.label21.Text = "Index/Ticket:";
|
||||||
//
|
//
|
||||||
// textBoxIndexTicket
|
// textBoxIndexTicket
|
||||||
//
|
//
|
||||||
this.textBoxIndexTicket.Location = new System.Drawing.Point(255, 261);
|
this.textBoxIndexTicket.Location = new System.Drawing.Point(290, 261);
|
||||||
this.textBoxIndexTicket.Name = "textBoxIndexTicket";
|
this.textBoxIndexTicket.Name = "textBoxIndexTicket";
|
||||||
this.textBoxIndexTicket.Size = new System.Drawing.Size(60, 20);
|
this.textBoxIndexTicket.Size = new System.Drawing.Size(60, 20);
|
||||||
this.textBoxIndexTicket.TabIndex = 7;
|
this.textBoxIndexTicket.TabIndex = 7;
|
||||||
|
this.textBoxIndexTicket.Text = "0";
|
||||||
//
|
//
|
||||||
// comboBoxSelectedCommand
|
// comboBoxSelectedCommand
|
||||||
//
|
//
|
||||||
@@ -364,10 +429,12 @@
|
|||||||
//
|
//
|
||||||
// listBoxClosedOrders
|
// listBoxClosedOrders
|
||||||
//
|
//
|
||||||
|
this.listBoxClosedOrders.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.listBoxClosedOrders.FormattingEnabled = true;
|
this.listBoxClosedOrders.FormattingEnabled = true;
|
||||||
this.listBoxClosedOrders.Location = new System.Drawing.Point(213, 151);
|
this.listBoxClosedOrders.Location = new System.Drawing.Point(213, 151);
|
||||||
this.listBoxClosedOrders.Name = "listBoxClosedOrders";
|
this.listBoxClosedOrders.Name = "listBoxClosedOrders";
|
||||||
this.listBoxClosedOrders.Size = new System.Drawing.Size(388, 108);
|
this.listBoxClosedOrders.Size = new System.Drawing.Size(463, 108);
|
||||||
this.listBoxClosedOrders.TabIndex = 5;
|
this.listBoxClosedOrders.TabIndex = 5;
|
||||||
//
|
//
|
||||||
// button2
|
// button2
|
||||||
@@ -613,11 +680,14 @@
|
|||||||
//
|
//
|
||||||
// listBoxSendedOrders
|
// listBoxSendedOrders
|
||||||
//
|
//
|
||||||
|
this.listBoxSendedOrders.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.listBoxSendedOrders.FormattingEnabled = true;
|
this.listBoxSendedOrders.FormattingEnabled = true;
|
||||||
this.listBoxSendedOrders.Location = new System.Drawing.Point(213, 23);
|
this.listBoxSendedOrders.Location = new System.Drawing.Point(213, 23);
|
||||||
this.listBoxSendedOrders.Name = "listBoxSendedOrders";
|
this.listBoxSendedOrders.Name = "listBoxSendedOrders";
|
||||||
this.listBoxSendedOrders.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple;
|
this.listBoxSendedOrders.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple;
|
||||||
this.listBoxSendedOrders.Size = new System.Drawing.Size(388, 108);
|
this.listBoxSendedOrders.Size = new System.Drawing.Size(463, 108);
|
||||||
this.listBoxSendedOrders.TabIndex = 1;
|
this.listBoxSendedOrders.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// tabPage1
|
// tabPage1
|
||||||
@@ -630,11 +700,21 @@
|
|||||||
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage1.Name = "tabPage1";
|
this.tabPage1.Name = "tabPage1";
|
||||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage1.Size = new System.Drawing.Size(607, 362);
|
this.tabPage1.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage1.TabIndex = 2;
|
this.tabPage1.TabIndex = 2;
|
||||||
this.tabPage1.Text = "Check Status";
|
this.tabPage1.Text = "Check Status";
|
||||||
this.tabPage1.UseVisualStyleBackColor = true;
|
this.tabPage1.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
|
// buttonRefreshRates
|
||||||
|
//
|
||||||
|
this.buttonRefreshRates.Location = new System.Drawing.Point(10, 172);
|
||||||
|
this.buttonRefreshRates.Name = "buttonRefreshRates";
|
||||||
|
this.buttonRefreshRates.Size = new System.Drawing.Size(128, 23);
|
||||||
|
this.buttonRefreshRates.TabIndex = 4;
|
||||||
|
this.buttonRefreshRates.Text = "RefreshRates";
|
||||||
|
this.buttonRefreshRates.UseVisualStyleBackColor = true;
|
||||||
|
this.buttonRefreshRates.Click += new System.EventHandler(this.buttonRefreshRates_Click);
|
||||||
|
//
|
||||||
// label22
|
// label22
|
||||||
//
|
//
|
||||||
this.label22.AutoSize = true;
|
this.label22.AutoSize = true;
|
||||||
@@ -698,7 +778,7 @@
|
|||||||
this.tabPage3.Location = new System.Drawing.Point(4, 22);
|
this.tabPage3.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage3.Name = "tabPage3";
|
this.tabPage3.Name = "tabPage3";
|
||||||
this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage3.Size = new System.Drawing.Size(607, 362);
|
this.tabPage3.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage3.TabIndex = 3;
|
this.tabPage3.TabIndex = 3;
|
||||||
this.tabPage3.Text = "Account Information";
|
this.tabPage3.Text = "Account Information";
|
||||||
this.tabPage3.UseVisualStyleBackColor = true;
|
this.tabPage3.UseVisualStyleBackColor = true;
|
||||||
@@ -809,7 +889,7 @@
|
|||||||
this.tabPage4.Location = new System.Drawing.Point(4, 22);
|
this.tabPage4.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage4.Name = "tabPage4";
|
this.tabPage4.Name = "tabPage4";
|
||||||
this.tabPage4.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage4.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage4.Size = new System.Drawing.Size(607, 362);
|
this.tabPage4.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage4.TabIndex = 4;
|
this.tabPage4.TabIndex = 4;
|
||||||
this.tabPage4.Text = "MarketInfo";
|
this.tabPage4.Text = "MarketInfo";
|
||||||
this.tabPage4.UseVisualStyleBackColor = true;
|
this.tabPage4.UseVisualStyleBackColor = true;
|
||||||
@@ -891,7 +971,7 @@
|
|||||||
this.tabPage5.Location = new System.Drawing.Point(4, 22);
|
this.tabPage5.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage5.Name = "tabPage5";
|
this.tabPage5.Name = "tabPage5";
|
||||||
this.tabPage5.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage5.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage5.Size = new System.Drawing.Size(607, 362);
|
this.tabPage5.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage5.TabIndex = 5;
|
this.tabPage5.TabIndex = 5;
|
||||||
this.tabPage5.Text = "Timeframes";
|
this.tabPage5.Text = "Timeframes";
|
||||||
this.tabPage5.UseVisualStyleBackColor = true;
|
this.tabPage5.UseVisualStyleBackColor = true;
|
||||||
@@ -1009,16 +1089,27 @@
|
|||||||
//
|
//
|
||||||
// tabPage6
|
// tabPage6
|
||||||
//
|
//
|
||||||
|
this.tabPage6.Controls.Add(this.button15);
|
||||||
this.tabPage6.Controls.Add(this.button14);
|
this.tabPage6.Controls.Add(this.button14);
|
||||||
this.tabPage6.Controls.Add(this.button13);
|
this.tabPage6.Controls.Add(this.button13);
|
||||||
this.tabPage6.Location = new System.Drawing.Point(4, 22);
|
this.tabPage6.Location = new System.Drawing.Point(4, 22);
|
||||||
this.tabPage6.Name = "tabPage6";
|
this.tabPage6.Name = "tabPage6";
|
||||||
this.tabPage6.Padding = new System.Windows.Forms.Padding(3);
|
this.tabPage6.Padding = new System.Windows.Forms.Padding(3);
|
||||||
this.tabPage6.Size = new System.Drawing.Size(607, 362);
|
this.tabPage6.Size = new System.Drawing.Size(682, 362);
|
||||||
this.tabPage6.TabIndex = 6;
|
this.tabPage6.TabIndex = 6;
|
||||||
this.tabPage6.Text = "Client Terminal";
|
this.tabPage6.Text = "Client Terminal";
|
||||||
this.tabPage6.UseVisualStyleBackColor = true;
|
this.tabPage6.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
|
// button15
|
||||||
|
//
|
||||||
|
this.button15.Location = new System.Drawing.Point(223, 184);
|
||||||
|
this.button15.Name = "button15";
|
||||||
|
this.button15.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.button15.TabIndex = 2;
|
||||||
|
this.button15.Text = "button15";
|
||||||
|
this.button15.UseVisualStyleBackColor = true;
|
||||||
|
this.button15.Click += new System.EventHandler(this.button15_Click);
|
||||||
|
//
|
||||||
// button14
|
// button14
|
||||||
//
|
//
|
||||||
this.button14.Location = new System.Drawing.Point(13, 45);
|
this.button14.Location = new System.Drawing.Point(13, 45);
|
||||||
@@ -1039,21 +1130,18 @@
|
|||||||
this.button13.UseVisualStyleBackColor = true;
|
this.button13.UseVisualStyleBackColor = true;
|
||||||
this.button13.Click += new System.EventHandler(this.button13_Click);
|
this.button13.Click += new System.EventHandler(this.button13_Click);
|
||||||
//
|
//
|
||||||
// buttonRefreshRates
|
// contextMenuStrip1
|
||||||
//
|
//
|
||||||
this.buttonRefreshRates.Location = new System.Drawing.Point(10, 172);
|
this.contextMenuStrip1.Name = "contextMenuStrip1";
|
||||||
this.buttonRefreshRates.Name = "buttonRefreshRates";
|
this.contextMenuStrip1.Size = new System.Drawing.Size(61, 4);
|
||||||
this.buttonRefreshRates.Size = new System.Drawing.Size(128, 23);
|
this.contextMenuStrip1.Text = "Clear";
|
||||||
this.buttonRefreshRates.TabIndex = 4;
|
|
||||||
this.buttonRefreshRates.Text = "RefreshRates";
|
|
||||||
this.buttonRefreshRates.UseVisualStyleBackColor = true;
|
|
||||||
this.buttonRefreshRates.Click += new System.EventHandler(this.buttonRefreshRates_Click);
|
|
||||||
//
|
//
|
||||||
// Form1
|
// Form1
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(638, 659);
|
this.ClientSize = new System.Drawing.Size(713, 659);
|
||||||
|
this.ContextMenuStrip = this.contextMenuStrip1;
|
||||||
this.Controls.Add(this.listBoxEventLog);
|
this.Controls.Add(this.listBoxEventLog);
|
||||||
this.Controls.Add(this.tabControl1);
|
this.Controls.Add(this.tabControl1);
|
||||||
this.Controls.Add(this.groupBox2);
|
this.Controls.Add(this.groupBox2);
|
||||||
@@ -1175,6 +1263,12 @@
|
|||||||
private System.Windows.Forms.Button button13;
|
private System.Windows.Forms.Button button13;
|
||||||
private System.Windows.Forms.Button button14;
|
private System.Windows.Forms.Button button14;
|
||||||
private System.Windows.Forms.Button buttonRefreshRates;
|
private System.Windows.Forms.Button buttonRefreshRates;
|
||||||
|
private System.Windows.Forms.Button button15;
|
||||||
|
private System.Windows.Forms.Button button16;
|
||||||
|
private System.Windows.Forms.ComboBox comboBox1;
|
||||||
|
private System.Windows.Forms.ComboBox comboBox2;
|
||||||
|
private System.Windows.Forms.Button button17;
|
||||||
|
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+129
-10
@@ -11,6 +11,7 @@ using System.IO;
|
|||||||
using MtApi;
|
using MtApi;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TestApiClientUI
|
namespace TestApiClientUI
|
||||||
{
|
{
|
||||||
@@ -32,6 +33,9 @@ namespace TestApiClientUI
|
|||||||
apiClient.ConnectionStateChanged += apiClient_ConnectionStateChanged;
|
apiClient.ConnectionStateChanged += apiClient_ConnectionStateChanged;
|
||||||
|
|
||||||
initOrderCommandsGroup();
|
initOrderCommandsGroup();
|
||||||
|
|
||||||
|
comboBox1.SelectedIndex = 0;
|
||||||
|
comboBox2.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initOrderCommandsGroup()
|
private void initOrderCommandsGroup()
|
||||||
@@ -62,14 +66,14 @@ namespace TestApiClientUI
|
|||||||
GroupOrderCommands.Add(new PerformCommandHandler(orderType));
|
GroupOrderCommands.Add(new PerformCommandHandler(orderType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunOnUIThread(Action action)
|
private void RunOnUiThread(Action action)
|
||||||
{
|
{
|
||||||
this.BeginInvoke(action);
|
this.BeginInvoke(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void apiClient_ConnectionStateChanged(object sender, MtConnectionEventArgs e)
|
private void apiClient_ConnectionStateChanged(object sender, MtConnectionEventArgs e)
|
||||||
{
|
{
|
||||||
RunOnUIThread(() =>
|
RunOnUiThread(() =>
|
||||||
{
|
{
|
||||||
toolStripStatusConnection.Text = e.Status.ToString();
|
toolStripStatusConnection.Text = e.Status.ToString();
|
||||||
});
|
});
|
||||||
@@ -77,11 +81,11 @@ namespace TestApiClientUI
|
|||||||
switch (e.Status)
|
switch (e.Status)
|
||||||
{
|
{
|
||||||
case MtConnectionState.Connected:
|
case MtConnectionState.Connected:
|
||||||
RunOnUIThread(onConnected);
|
RunOnUiThread(onConnected);
|
||||||
break;
|
break;
|
||||||
case MtConnectionState.Disconnected:
|
case MtConnectionState.Disconnected:
|
||||||
case MtConnectionState.Failed:
|
case MtConnectionState.Failed:
|
||||||
RunOnUIThread(onDisconnected);
|
RunOnUiThread(onDisconnected);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +94,7 @@ namespace TestApiClientUI
|
|||||||
{
|
{
|
||||||
string instrument = e.Quote.Instrument;
|
string instrument = e.Quote.Instrument;
|
||||||
|
|
||||||
RunOnUIThread(() =>
|
RunOnUiThread(() =>
|
||||||
{
|
{
|
||||||
removeQuote(e.Quote);
|
removeQuote(e.Quote);
|
||||||
});
|
});
|
||||||
@@ -98,7 +102,7 @@ namespace TestApiClientUI
|
|||||||
|
|
||||||
private void apiClient_QuoteAdded(object sender, MtQuoteEventArgs e)
|
private void apiClient_QuoteAdded(object sender, MtQuoteEventArgs e)
|
||||||
{
|
{
|
||||||
RunOnUIThread(() =>
|
RunOnUiThread(() =>
|
||||||
{
|
{
|
||||||
addNewQuote(e.Quote);
|
addNewQuote(e.Quote);
|
||||||
});
|
});
|
||||||
@@ -217,7 +221,7 @@ namespace TestApiClientUI
|
|||||||
{
|
{
|
||||||
int orderId = apiClient.OrderSend(symbol, command, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
|
int orderId = apiClient.OrderSend(symbol, command, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);
|
||||||
|
|
||||||
RunOnUIThread(() =>
|
RunOnUiThread(() =>
|
||||||
{
|
{
|
||||||
if (orderId >= 0)
|
if (orderId >= 0)
|
||||||
{
|
{
|
||||||
@@ -542,9 +546,12 @@ namespace TestApiClientUI
|
|||||||
|
|
||||||
private void addToLog(string msg)
|
private void addToLog(string msg)
|
||||||
{
|
{
|
||||||
listBoxEventLog.Items.Add(msg);
|
RunOnUiThread(() =>
|
||||||
listBoxEventLog.SetSelected(listBoxEventLog.Items.Count - 1, true);
|
{
|
||||||
listBoxEventLog.SetSelected(listBoxEventLog.Items.Count - 1, false);
|
listBoxEventLog.Items.Add(msg);
|
||||||
|
listBoxEventLog.SetSelected(listBoxEventLog.Items.Count - 1, true);
|
||||||
|
listBoxEventLog.SetSelected(listBoxEventLog.Items.Count - 1, false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void button3_Click(object sender, EventArgs e)
|
private void button3_Click(object sender, EventArgs e)
|
||||||
@@ -857,5 +864,117 @@ namespace TestApiClientUI
|
|||||||
var retVal = apiClient.RefreshRates();
|
var retVal = apiClient.RefreshRates();
|
||||||
addToLog(string.Format("RefreshRates result: {0}", retVal));
|
addToLog(string.Format("RefreshRates result: {0}", retVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void button15_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
var ticket = i;
|
||||||
|
Task.Factory.StartNew(() =>
|
||||||
|
{
|
||||||
|
MtOrder order = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
order = apiClient.GetOrder(ticket, OrderSelectMode.SELECT_BY_POS, OrderSelectSource.MODE_TRADES);
|
||||||
|
}
|
||||||
|
catch (MtConnectionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message);
|
||||||
|
}
|
||||||
|
catch (MtExecutionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
string result;
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
string.Format(
|
||||||
|
"Order: Ticket = {0}, Symbol = {1}, Operation = {2}, OpenPrice = {3}, ClosePrice = {4}, Lots = {5}, Profit = {6}, Comment = {7}, Commission = {8}, MagicNumber = {9}, OpenTime = {10}, CloseTime = {11}",
|
||||||
|
order.Ticket, order.Symbol, order.Operation, order.OpenPrice, order.ClosePrice, order.Lots, order.Profit, order.Comment, order.Commission, order.MagicNumber, order.OpenTime, order.CloseTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = "Order is null";
|
||||||
|
}
|
||||||
|
|
||||||
|
addToLog(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button16_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var ticket = int.Parse(textBoxIndexTicket.Text);
|
||||||
|
var selectMode = (OrderSelectMode) comboBox1.SelectedIndex;
|
||||||
|
var selectSource = (OrderSelectSource) comboBox2.SelectedIndex;
|
||||||
|
|
||||||
|
MtOrder order = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
order = apiClient.GetOrder(ticket, selectMode, selectSource);
|
||||||
|
}
|
||||||
|
catch (MtConnectionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (MtExecutionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message + "; ErrorCode = " + ex.ErrorCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order == null)
|
||||||
|
{
|
||||||
|
addToLog("Order is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result =
|
||||||
|
string.Format(
|
||||||
|
"Order: Ticket = {0}, Symbol = {1}, Operation = {2}, OpenPrice = {3}, ClosePrice = {4}, Lots = {5}, Profit = {6}, Comment = {7}, Commission = {8}, MagicNumber = {9}, OpenTime = {10}, CloseTime = {11}",
|
||||||
|
order.Ticket, order.Symbol, order.Operation, order.OpenPrice, order.ClosePrice, order.Lots, order.Profit, order.Comment, order.Commission, order.MagicNumber, order.OpenTime, order.CloseTime);
|
||||||
|
addToLog(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button17_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var selectSource = (OrderSelectSource)comboBox2.SelectedIndex;
|
||||||
|
|
||||||
|
|
||||||
|
IEnumerable<MtOrder> orders = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
orders = apiClient.GetOrders(selectSource);
|
||||||
|
}
|
||||||
|
catch (MtConnectionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (MtExecutionException ex)
|
||||||
|
{
|
||||||
|
addToLog("MtExecutionException: " + ex.Message + "; ErrorCode = " + ex.ErrorCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orders == null)
|
||||||
|
{
|
||||||
|
addToLog("Orders is null");
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var order in orders)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
string.Format(
|
||||||
|
"Order: Ticket = {0}, Symbol = {1}, Operation = {2}, OpenPrice = {3}, ClosePrice = {4}, Lots = {5}, Profit = {6}, Comment = {7}, Commission = {8}, MagicNumber = {9}, OpenTime = {10}, CloseTime = {11}",
|
||||||
|
order.Ticket, order.Symbol, order.Operation, order.OpenPrice, order.ClosePrice, order.Lots, order.Profit, order.Comment, order.Commission, order.MagicNumber, order.OpenTime, order.CloseTime);
|
||||||
|
addToLog(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,4 +120,7 @@
|
|||||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>17, 17</value>
|
<value>17, 17</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>133, 17</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
Binary file not shown.
+189
-11
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <WinUser32.mqh>
|
#include <WinUser32.mqh>
|
||||||
#include <stdlib.mqh>
|
#include <stdlib.mqh>
|
||||||
|
#include <json.mqh>
|
||||||
|
|
||||||
#import "MTConnector.dll"
|
#import "MTConnector.dll"
|
||||||
bool initExpert(int expertHandle, int port, string symbol, double bid, double ask, string& err);
|
bool initExpert(int expertHandle, int port, string symbol, double bid, double ask, string& err);
|
||||||
@@ -40,6 +41,7 @@ string subjectValue;
|
|||||||
string some_textValue;
|
string some_textValue;
|
||||||
string nameValue;
|
string nameValue;
|
||||||
string prefix_nameValue;
|
string prefix_nameValue;
|
||||||
|
string requestValue;
|
||||||
|
|
||||||
int barsCount;
|
int barsCount;
|
||||||
int priceCount;
|
int priceCount;
|
||||||
@@ -126,17 +128,18 @@ double myAsk;
|
|||||||
|
|
||||||
int preinit()
|
int preinit()
|
||||||
{
|
{
|
||||||
message = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "";
|
StringInit(message,200,0);
|
||||||
symbolValue = "222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" + "";
|
StringInit(symbolValue,200,0);
|
||||||
commentValue = "333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + "";
|
StringInit(commentValue,200,0);
|
||||||
msgValue = "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444" + "";
|
StringInit(msgValue,200,0);
|
||||||
captionValue = "555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555" + "";
|
StringInit(captionValue,200,0);
|
||||||
filenameValue = "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666" + "";
|
StringInit(filenameValue,200,0);
|
||||||
ftp_pathValue = "777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777" + "";
|
StringInit(ftp_pathValue,200,0);
|
||||||
subjectValue = "888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" + "";
|
StringInit(subjectValue,200,0);
|
||||||
some_textValue = "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + "";
|
StringInit(some_textValue,200,0);
|
||||||
nameValue = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "";
|
StringInit(nameValue,200,0);
|
||||||
prefix_nameValue = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "";
|
StringInit(prefix_nameValue,200,0);
|
||||||
|
StringInit(requestValue, 500, "\0");
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -234,12 +237,35 @@ int executeCommand()
|
|||||||
|
|
||||||
int commandType = pCommandType;
|
int commandType = pCommandType;
|
||||||
|
|
||||||
|
if (commandType > 0)
|
||||||
|
{
|
||||||
|
Print("executeCommand: commnad type = ", commandType);
|
||||||
|
}
|
||||||
|
|
||||||
switch (commandType)
|
switch (commandType)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
//NoCommand
|
//NoCommand
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 155: //SignalServiceCommand
|
||||||
|
{
|
||||||
|
if (!getStringValue(ExpertHandle, 0, requestValue))
|
||||||
|
{
|
||||||
|
PrintParamError("Signal");
|
||||||
|
}
|
||||||
|
|
||||||
|
string response = "";
|
||||||
|
|
||||||
|
if (requestValue != "")
|
||||||
|
{
|
||||||
|
Print("executeCommand: incoming signal = ", requestValue);
|
||||||
|
response = OnRequest(requestValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendStringResponse(ExpertHandle, response);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 1: // OrderSend
|
case 1: // OrderSend
|
||||||
if (!getStringValue(ExpertHandle, 0, symbolValue))
|
if (!getStringValue(ExpertHandle, 0, symbolValue))
|
||||||
{
|
{
|
||||||
@@ -3557,3 +3583,155 @@ bool OrderCloseAll()
|
|||||||
|
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CreateErrorResponse(int code, string message)
|
||||||
|
{
|
||||||
|
JSONObject *joResponse = new JSONObject();
|
||||||
|
joResponse.put("ErrorCode", new JSONNumber(code));
|
||||||
|
joResponse.put("ErrorMessage", new JSONString(message));
|
||||||
|
|
||||||
|
string result = joResponse.toString();
|
||||||
|
delete joResponse;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string CreateSuccessResponse(string responseName, JSONValue* responseBody)
|
||||||
|
{
|
||||||
|
JSONObject *joResponse = new JSONObject();
|
||||||
|
joResponse.put("ErrorCode", new JSONNumber(ERR_NO_ERROR));
|
||||||
|
|
||||||
|
if (responseBody != NULL)
|
||||||
|
{
|
||||||
|
joResponse.put(responseName, responseBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
string result = joResponse.toString();
|
||||||
|
delete joResponse;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string OnRequest(string json)
|
||||||
|
{
|
||||||
|
string response = "";
|
||||||
|
|
||||||
|
JSONParser *parser = new JSONParser();
|
||||||
|
JSONValue *jv = parser.parse(json);
|
||||||
|
|
||||||
|
if(jv == NULL)
|
||||||
|
{
|
||||||
|
Print("OnRequest [ERROR]:" + (string)parser.getErrorCode() + parser.getErrorMessage());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(jv.isObject())
|
||||||
|
{
|
||||||
|
JSONObject *jo = jv;
|
||||||
|
int requestType = jo.getInt("RequestType");
|
||||||
|
JSONObject *joRequest = jo.getObject("Request");
|
||||||
|
|
||||||
|
if (joRequest != NULL)
|
||||||
|
{
|
||||||
|
Print("OnRequest: RequestType = ", requestType);
|
||||||
|
|
||||||
|
switch(requestType)
|
||||||
|
{
|
||||||
|
case 1: //GetOrder
|
||||||
|
response = ExecuteRequestGetOrder(joRequest);
|
||||||
|
break;
|
||||||
|
case 2: //GetOrders
|
||||||
|
response = ExecuteRequestGetOrders(joRequest);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Print("OnRequest [WARNING]: Unknown request type ", requestType);
|
||||||
|
response = CreateErrorResponse(-1, "Unknown request type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Print("OnRequest [WARNING]: Request field is not defined");
|
||||||
|
response = CreateErrorResponse(-1, "Request field is not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete jv;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete parser;
|
||||||
|
|
||||||
|
Print("OnRequest: Response = ", response);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject* GetOrderJson(int index, int select, int pool)
|
||||||
|
{
|
||||||
|
if (OrderSelect(index, select, pool) == false)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ticket = OrderTicket();
|
||||||
|
string symbol = OrderSymbol();
|
||||||
|
int operation = OrderType();
|
||||||
|
double openPrice = OrderOpenPrice();
|
||||||
|
double closePrice = OrderClosePrice();
|
||||||
|
double lots = OrderLots();
|
||||||
|
double profit = OrderProfit();
|
||||||
|
string comment = OrderComment();
|
||||||
|
double commission = OrderCommission();
|
||||||
|
int magicNumber = OrderMagicNumber();
|
||||||
|
datetime openTime = OrderOpenTime();
|
||||||
|
datetime closeTime = OrderCloseTime();
|
||||||
|
|
||||||
|
JSONObject *joOrder = new JSONObject();
|
||||||
|
joOrder.put("Ticket", new JSONNumber(ticket));
|
||||||
|
joOrder.put("Symbol", new JSONString(symbol));
|
||||||
|
joOrder.put("Operation", new JSONNumber(operation));
|
||||||
|
joOrder.put("OpenPrice", new JSONNumber(openPrice));
|
||||||
|
joOrder.put("ClosePrice", new JSONNumber(closePrice));
|
||||||
|
joOrder.put("Lots", new JSONNumber(lots));
|
||||||
|
joOrder.put("Profit", new JSONNumber(profit));
|
||||||
|
joOrder.put("Comment", new JSONString(comment));
|
||||||
|
joOrder.put("Commission", new JSONString(commission));
|
||||||
|
joOrder.put("MagicNumber", new JSONNumber(magicNumber));
|
||||||
|
joOrder.put("Commission", new JSONString(commission));
|
||||||
|
joOrder.put("MagicNumber", new JSONNumber(magicNumber));
|
||||||
|
joOrder.put("MtOpenTime", new JSONNumber(openTime));
|
||||||
|
joOrder.put("MtCloseTime", new JSONNumber(closeTime));
|
||||||
|
|
||||||
|
return joOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
string ExecuteRequestGetOrder(JSONObject *jo)
|
||||||
|
{
|
||||||
|
int index = jo.getInt("Index");
|
||||||
|
int select = jo.getInt("Select");
|
||||||
|
int pool = jo.getInt("Pool");
|
||||||
|
|
||||||
|
Print("ExecuteRequestGetOrder: Index = ", index, "; Select = ", select, "; Pool = ", pool);
|
||||||
|
|
||||||
|
JSONObject* joOrder = GetOrderJson(index, select, pool);
|
||||||
|
if (joOrder == NULL)
|
||||||
|
return CreateErrorResponse(GetLastError(), "GetOrder failed");
|
||||||
|
return CreateSuccessResponse("Order", joOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ExecuteRequestGetOrders(JSONObject *jo)
|
||||||
|
{
|
||||||
|
int pool = jo.getInt("Pool");
|
||||||
|
|
||||||
|
Print("ExecuteRequestGetOrders: Pool = ", pool);
|
||||||
|
|
||||||
|
int total=OrdersTotal();
|
||||||
|
JSONArray* joOrders = new JSONArray();
|
||||||
|
for(int pos = 0; pos < total; pos++)
|
||||||
|
{
|
||||||
|
JSONObject* joOrder = GetOrderJson(pos, SELECT_BY_POS, pool);
|
||||||
|
if (joOrder == NULL)
|
||||||
|
return CreateErrorResponse(GetLastError(), "GetOrders failed");
|
||||||
|
joOrders.put(pos, joOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateSuccessResponse("Orders", joOrders);
|
||||||
|
}
|
||||||
|
|||||||
+672
@@ -0,0 +1,672 @@
|
|||||||
|
// $Id: hash.mqh 125 2014-03-03 08:38:32Z ydrol $
|
||||||
|
#ifndef YDROL_HASH_MQH
|
||||||
|
#define YDROL_HASH_MQH
|
||||||
|
|
||||||
|
//#property strict
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is losely ported from a C version I have which was in turn modified from hashtable.c by Christopher Clark.
|
||||||
|
Copyright (C) 2014, Andrew Lord (NICKNAME=lordy) <forex@NICKNAME.org.uk>
|
||||||
|
Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
|
||||||
|
|
||||||
|
2014/02/21 - Readded PrimeNumber sizes and auto rehashing when load factor hit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Any value stored in a Hash must be a subclass of HashValue
|
||||||
|
class HashValue {
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Linked list of values - there will be one list for each hash value
|
||||||
|
class HashEntry {
|
||||||
|
public:
|
||||||
|
string _key;
|
||||||
|
HashValue * _val;
|
||||||
|
HashEntry *_next;
|
||||||
|
|
||||||
|
HashEntry() {
|
||||||
|
_key=NULL;
|
||||||
|
_val=NULL;
|
||||||
|
_next=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashEntry(string key,HashValue* val) {
|
||||||
|
_key=key;
|
||||||
|
_val=val;
|
||||||
|
_next=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HashEntry() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Convenience class for storing strings as hash values.
|
||||||
|
class HashString : public HashValue {
|
||||||
|
private:
|
||||||
|
string val;
|
||||||
|
public:
|
||||||
|
HashString(string v) { val=v;}
|
||||||
|
string getVal() { return val; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Convenience class for storing doubles as hash values.
|
||||||
|
class HashDouble : public HashValue {
|
||||||
|
private:
|
||||||
|
double val;
|
||||||
|
public:
|
||||||
|
HashDouble(double v) { val=v;}
|
||||||
|
double getVal() { return val; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Convenience class for storing ints as hash values.
|
||||||
|
class HashInt : public HashValue {
|
||||||
|
private:
|
||||||
|
int val;
|
||||||
|
public:
|
||||||
|
HashInt(int v) { val=v;}
|
||||||
|
int getVal() { return val; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Convenience class for storing longs as hash values.
|
||||||
|
class HashLong : public HashValue {
|
||||||
|
private:
|
||||||
|
long val;
|
||||||
|
public:
|
||||||
|
HashLong(datetime v) { val=v;}
|
||||||
|
long getVal() { return val; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Convenience class for storing datetimes as hash values.
|
||||||
|
class HashDatetime : public HashValue {
|
||||||
|
private:
|
||||||
|
datetime val;
|
||||||
|
public:
|
||||||
|
HashDatetime(datetime v) { val=v;}
|
||||||
|
datetime getVal() { return val; }
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Hash class allows objects to be stored in a table index by strings.
|
||||||
|
/// the stored Objects must be a sub class of the HashValue class.
|
||||||
|
///
|
||||||
|
/// There are some convenience classes to hold atomic types as values HashString,HashDouble,HashInt
|
||||||
|
///
|
||||||
|
///EXAMPLE:
|
||||||
|
///
|
||||||
|
/// <pre>
|
||||||
|
/// class myClass: public HashValue {
|
||||||
|
/// public: int v;
|
||||||
|
/// myClass(int a) { v = a;}
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Create the objects as needed
|
||||||
|
///
|
||||||
|
/// myClass *a = new myClass(1);
|
||||||
|
/// myClass *b = new myClass(2);
|
||||||
|
/// myClass *c = new myClass(3);
|
||||||
|
///
|
||||||
|
/// // Then to insert into hash etc.
|
||||||
|
///
|
||||||
|
/// Hash* h = new Hash(193,true);
|
||||||
|
/// // 'true' means when the hash will adopt the values and delete them when they are removed from the hash or when the hash is deleted.
|
||||||
|
///
|
||||||
|
/// h.hPut("a",a);
|
||||||
|
/// h.hPut("b",b);
|
||||||
|
/// h.hPut("c",c);
|
||||||
|
///
|
||||||
|
/// myClass *d = h.hGet("b");
|
||||||
|
///
|
||||||
|
/// etc.
|
||||||
|
///
|
||||||
|
/// // Iterate over hash
|
||||||
|
/// HashLoop *l
|
||||||
|
/// for (l = new HashLoop(h) ; l.hasNext() ; l.next() ) {
|
||||||
|
/// string key = l.key();
|
||||||
|
/// MyClass *c = l.val();
|
||||||
|
/// }
|
||||||
|
/// delete l;
|
||||||
|
///
|
||||||
|
/// // Delete from hash - This will also delete 'a' because we set the 'adopt' flag on the hash.
|
||||||
|
/// h.hDel("a");
|
||||||
|
///
|
||||||
|
/// //Delete the hash - this will also delete 'b' and 'c' because of the adopt flag.
|
||||||
|
/// delete h;
|
||||||
|
/// </pre>
|
||||||
|
class Hash : public HashValue {
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Number of slots in the hashtable.
|
||||||
|
/// this should be approx number of elements to store. Depending on hash algorithm
|
||||||
|
/// it may optimally be a prime or a power of two etc. but probably not important
|
||||||
|
/// for MQL4 performance. A future optimisation might be to move the hashcode function to a DLL??
|
||||||
|
uint _hashSlots;
|
||||||
|
|
||||||
|
/// Number of elements at which hash will get resized.
|
||||||
|
int _resizeThreshold;
|
||||||
|
|
||||||
|
/// number of things in the hash
|
||||||
|
int _hashEntryCount;
|
||||||
|
|
||||||
|
/// an array of linked lists (HashEntry). one for each hash value.
|
||||||
|
/// To store an object against a string(key) - get the string hashcode, then insert pair (key,val) into the linked list for that hashcode.
|
||||||
|
/// To fetch an object against a string(key) - get the string hashcode, get linked-list at that hashcode index, then search for the key and return the val.
|
||||||
|
HashEntry* _buckets[];
|
||||||
|
|
||||||
|
/// If true the hash will free(delete) values as they are removed, or at cleanup.
|
||||||
|
bool _adoptValues;
|
||||||
|
|
||||||
|
int _errCode;
|
||||||
|
string _errText;
|
||||||
|
|
||||||
|
void init(uint size,bool adoptValues)
|
||||||
|
{
|
||||||
|
_hashSlots = 0;
|
||||||
|
_hashEntryCount = 0;
|
||||||
|
clearError();
|
||||||
|
setAdoptValues(adoptValues);
|
||||||
|
|
||||||
|
rehash(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash table distribution is better when size is prime, eg if hash function procduces numbers
|
||||||
|
// that are multiples of x, then there may be grouping occuring around gcd(x,slots) gcd(2x,slots) etc
|
||||||
|
// using a prime size helps spread the distribution.
|
||||||
|
uint size2prime(uint size) {
|
||||||
|
int pmax=ArraySize(_primes);
|
||||||
|
for(int p=0 ; p<pmax; p++ ) {
|
||||||
|
if (_primes[p] >= size) {
|
||||||
|
return _primes[p];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Primes that approx double in size, used for hash table sizes to avoid gcd causing bunching
|
||||||
|
static uint _primes[];
|
||||||
|
|
||||||
|
/// After reviewing quite a few hash functions I settled on the one below.
|
||||||
|
/// http://www.cse.yorku.ca/~oz/hash.html
|
||||||
|
/// this is the bottleneck function. Shame mql hash no default hash method for objects.
|
||||||
|
uint hash(string s)
|
||||||
|
{
|
||||||
|
|
||||||
|
uchar c[];
|
||||||
|
uint h = 0;
|
||||||
|
|
||||||
|
if (s != NULL) {
|
||||||
|
h = 5381;
|
||||||
|
int n = StringToCharArray(s,c);
|
||||||
|
for(int i = 0 ; i < n ; i++ ) {
|
||||||
|
h = ((h << 5 ) + h ) + c[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h % _hashSlots;
|
||||||
|
}
|
||||||
|
void clearError() {
|
||||||
|
setError(0,"");
|
||||||
|
}
|
||||||
|
void setError(int e,string m) {
|
||||||
|
_errCode = e;
|
||||||
|
_errText = m;
|
||||||
|
//error((string)e,m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Constructor: Create a Hash Object
|
||||||
|
Hash() {
|
||||||
|
init(17,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Constructor: Create a Hash Object
|
||||||
|
/// @param adoptValues : If true the hash destructor will <b>delete</b> all dynamically allocated hash values.
|
||||||
|
Hash(bool adoptValues) {
|
||||||
|
init(17,adoptValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor: Create a Hash Object
|
||||||
|
/// @param size : Approximate size (actual size will be a larger prime number close to a power of 2)
|
||||||
|
/// @param adoptValues : If true the hash destructor will <b>delete</b> all dynamically allocated hash values.
|
||||||
|
Hash(int size,bool adoptValues) {
|
||||||
|
init(size,adoptValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Hash() {
|
||||||
|
|
||||||
|
// Free entries.
|
||||||
|
for(uint i = 0 ; i< _hashSlots ; i++) {
|
||||||
|
HashEntry *nextEntry = NULL;
|
||||||
|
for(HashEntry *entry = _buckets[i] ; entry!= NULL ; entry = nextEntry )
|
||||||
|
{
|
||||||
|
nextEntry = entry._next;
|
||||||
|
|
||||||
|
if (_adoptValues && entry._val != NULL && CheckPointer(entry._val) == POINTER_DYNAMIC ) {
|
||||||
|
delete entry._val;
|
||||||
|
}
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
_buckets[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return any error that has occured. This should be used when
|
||||||
|
/// retriving values in a Hash that may contain NULLs. hGet()
|
||||||
|
/// methods can return NULL if not found, in which case getErrorCode
|
||||||
|
/// will be set.
|
||||||
|
int getErrCode() {
|
||||||
|
return _errCode;
|
||||||
|
}
|
||||||
|
/// Return text of the error message.
|
||||||
|
string getErrText() {
|
||||||
|
return _errText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If true the hash destructor will <b>delete</b> all dynamically allocated hash values.
|
||||||
|
void setAdoptValues(bool v) {
|
||||||
|
_adoptValues = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if the hash destructor will <b>delete</b> all dynamically allocated hash values.
|
||||||
|
bool getAdoptValues() {
|
||||||
|
return _adoptValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint _foundIndex; // After find() is called is set to hashindex for name whether found or not.
|
||||||
|
HashEntry* _foundEntry; // After find() is called is set to the HashEntry that contains the key.
|
||||||
|
HashEntry* _foundPrev; // After find() is called is set to the HashEntry before the entry
|
||||||
|
// (could use double linked list but requires more memory).
|
||||||
|
|
||||||
|
/// Look for the required entry for key 'name' true if found.
|
||||||
|
bool find(string keyName) {
|
||||||
|
|
||||||
|
//Alert("finding");
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// Get the index using the hashcode of the string
|
||||||
|
_foundIndex = hash(keyName);
|
||||||
|
|
||||||
|
|
||||||
|
if (_foundIndex>_hashSlots ) {
|
||||||
|
|
||||||
|
setError(1,"hGet: bad hashIndex="+(string)_foundIndex+" size "+(string)_hashSlots);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Search the linked list determined by the index.
|
||||||
|
|
||||||
|
for(HashEntry *e = _buckets[_foundIndex] ; e != NULL ; e = e._next ) {
|
||||||
|
if (e._key == keyName) {
|
||||||
|
_foundEntry = e;
|
||||||
|
found=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Track the item before the target item in case deleting from single linked list.
|
||||||
|
_foundPrev = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// This is used by the HashLoop class to get start of LinkedList at bucket[i]
|
||||||
|
HashEntry*getEntry(int i) {
|
||||||
|
return _buckets[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of slots/buckets (not number of elements)
|
||||||
|
uint getSlots() {
|
||||||
|
return _hashSlots;
|
||||||
|
}
|
||||||
|
/// Return the number of elements in the Hash
|
||||||
|
int getCount() {
|
||||||
|
return _hashEntryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the hash size and re-allocate values to new buckets.
|
||||||
|
bool rehash(uint newSize) {
|
||||||
|
bool ret = false;
|
||||||
|
HashEntry* oldTable[];
|
||||||
|
|
||||||
|
uint oldSize = _hashSlots;
|
||||||
|
newSize = size2prime(newSize);
|
||||||
|
//info("rehashing from "+(string)_hashSlots+" to "+(string)newSize+" "+(string)GetTickCount());
|
||||||
|
|
||||||
|
if (newSize <= getSlots()) {
|
||||||
|
setError(2,"rehash "+(string)newSize+" <= "+(string)_hashSlots);
|
||||||
|
} else if (ArrayResize(_buckets,newSize) != newSize) {
|
||||||
|
setError(3,"unable to resize ");
|
||||||
|
} else if (ArrayResize(oldTable,oldSize) != oldSize) {
|
||||||
|
setError(4,"unable to resize old copy ");
|
||||||
|
} else {
|
||||||
|
//Copy old table.
|
||||||
|
uint i;
|
||||||
|
for(i = 0 ; i < oldSize ; i++ ) oldTable[i] = _buckets[i];
|
||||||
|
// Init new entries - not sure if MQL does this anyway
|
||||||
|
for(i = 0 ; i<newSize ; i++ ) _buckets[i] = NULL;
|
||||||
|
|
||||||
|
// Move entries to new slots
|
||||||
|
_hashSlots = newSize;
|
||||||
|
_resizeThreshold = (int)_hashSlots / 4 * 3; // Just use the default load factor value of Javas HashTable
|
||||||
|
|
||||||
|
// Look through all slots
|
||||||
|
for(uint oldHashCode = 0 ; oldHashCode<oldSize ; oldHashCode++ ) {
|
||||||
|
HashEntry *next = NULL;
|
||||||
|
|
||||||
|
// Walk linked list
|
||||||
|
for(HashEntry *e = oldTable[oldHashCode] ; e != NULL ; e = next ) {
|
||||||
|
|
||||||
|
next = e._next;
|
||||||
|
|
||||||
|
uint newHashCode = hash(e._key);
|
||||||
|
// Insert at head of new list.
|
||||||
|
e._next = _buckets[newHashCode];
|
||||||
|
_buckets[newHashCode] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldTable[oldHashCode] = NULL;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the hash contains the given key
|
||||||
|
/// @param keyName : The key
|
||||||
|
/// @return: true if found otherwise false
|
||||||
|
bool hContainsKey(string keyName) {
|
||||||
|
return find(keyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch a value using string key
|
||||||
|
/// @return :HashValue associated with the key (or NULL if none found)
|
||||||
|
/// If the Hashtable contains legitimate NULL values then also check errCode()
|
||||||
|
/// Examples:
|
||||||
|
/// If not storing nulls use
|
||||||
|
/// obj = hash.hGet(x); if (obj != NULL) OK
|
||||||
|
///
|
||||||
|
/// If storing nulls use
|
||||||
|
/// obj = hash.hGet(x); if (obj != NULL || hash.errCode() == 0 ) OK
|
||||||
|
HashValue* hGet(string keyName) {
|
||||||
|
|
||||||
|
HashValue *obj = NULL;
|
||||||
|
clearError();
|
||||||
|
bool found=false;
|
||||||
|
|
||||||
|
if (find(keyName)) {
|
||||||
|
obj = _foundEntry._val;
|
||||||
|
} else {
|
||||||
|
//If Hash contains nulls then also check the errorCode=0 when retrieving
|
||||||
|
if (!found) {
|
||||||
|
setError(1,"not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience method for getting values from a HashString value (see hPutString())
|
||||||
|
string hGetString(string keyName) {
|
||||||
|
string ret = NULL;
|
||||||
|
HashString *v = hGet(keyName);
|
||||||
|
if (v != NULL) {
|
||||||
|
ret = v.getVal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// Convenience method for getting values from a HashDouble value (see hPutDouble())
|
||||||
|
double hGetDouble(string keyName) {
|
||||||
|
double ret = NULL;
|
||||||
|
HashDouble *v = hGet(keyName);
|
||||||
|
if (v != NULL) {
|
||||||
|
ret = v.getVal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// Convenience method for getting values from a HashInt value (see hPutInt())
|
||||||
|
int hGetInt(string keyName) {
|
||||||
|
int ret = NULL;
|
||||||
|
HashInt *v = hGet(keyName);
|
||||||
|
if (v != NULL) {
|
||||||
|
ret = v.getVal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// Convenience method for getting values from a HashLong ( see hPutLong())
|
||||||
|
long hGetLong(string keyName) {
|
||||||
|
long ret = NULL;
|
||||||
|
HashLong *v = hGet(keyName);
|
||||||
|
if (v != NULL) {
|
||||||
|
ret = v.getVal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// Convenience method for getting values from a HashDatetime ( see hPutDatetime())
|
||||||
|
datetime hGetDatetime(string keyName) {
|
||||||
|
datetime ret = NULL;
|
||||||
|
HashDatetime *v = hGet(keyName);
|
||||||
|
if (v != NULL) {
|
||||||
|
ret = v.getVal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store a hash value against the <b>keyName</b> key. This will overwrite any existing
|
||||||
|
/// value. It adoptValues is set, it will also free the value if applicable.
|
||||||
|
/// @param keyName : key name
|
||||||
|
/// @param obj : Value to store
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue *hPut(string keyName,HashValue *obj) {
|
||||||
|
|
||||||
|
HashValue *ret = NULL;
|
||||||
|
clearError();
|
||||||
|
|
||||||
|
if (find(keyName)) {
|
||||||
|
// Return revious value
|
||||||
|
ret = _foundEntry._val;
|
||||||
|
/*
|
||||||
|
// Replace entry contents
|
||||||
|
if (_adoptValues && _foundEntry._val != NULL && CheckPointer(_foundEntry._val) == POINTER_DYNAMIC ) {
|
||||||
|
delete _foundEntry._val;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
_foundEntry._val = obj;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Insert new entry at head of list
|
||||||
|
HashEntry* e = new HashEntry(keyName,obj);
|
||||||
|
HashEntry* first = _buckets[_foundIndex];
|
||||||
|
e._next = first;
|
||||||
|
_buckets[_foundIndex] = e;
|
||||||
|
_hashEntryCount++;
|
||||||
|
|
||||||
|
//info((string)_hashEntryCount+" vs. "+(string)_resizeThreshold);
|
||||||
|
// Auto Resize if number of entries hits _resizeThreshold
|
||||||
|
if (_hashEntryCount > _resizeThreshold ) {
|
||||||
|
rehash(_hashSlots/2*3); // this will snap to the next prime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// Store a string as hash value (HashString)
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue* hPutString(string keyName,string s) {
|
||||||
|
HashString *v = new HashString(s);
|
||||||
|
return hPut(keyName,v);
|
||||||
|
}
|
||||||
|
/// Store a double as hash value (HashDouble)
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue* hPutDouble(string keyName,double d) {
|
||||||
|
HashDouble *v = new HashDouble(d);
|
||||||
|
return hPut(keyName,v);
|
||||||
|
}
|
||||||
|
/// Store an int as hash value (HashInt)
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue* hPutInt(string keyName,int i) {
|
||||||
|
HashInt *v = new HashInt(i);
|
||||||
|
return hPut(keyName,v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store a datetime as hash value (HashLong)
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue* hPutLong(string keyName,long i) {
|
||||||
|
HashLong *v = new HashLong(i);
|
||||||
|
return hPut(keyName,v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store a datetime as hash value (HashDatetime)
|
||||||
|
/// @return the previous value of the key or NULL if there wasnt one
|
||||||
|
HashValue* hPutDatetime(string keyName,datetime i) {
|
||||||
|
HashDatetime *v = new HashDatetime(i);
|
||||||
|
return hPut(keyName,v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an entry from the hash.
|
||||||
|
bool hDel(string keyName) {
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
clearError();
|
||||||
|
|
||||||
|
if (find(keyName)) {
|
||||||
|
HashEntry *next = _foundEntry._next;
|
||||||
|
if (_foundPrev != NULL) {
|
||||||
|
//Remove entry from the middle of the list.
|
||||||
|
_foundPrev._next = next;
|
||||||
|
} else {
|
||||||
|
// remove from head of list
|
||||||
|
_buckets[_foundIndex] = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_adoptValues && _foundEntry._val != NULL&& CheckPointer(_foundEntry._val) == POINTER_DYNAMIC) {
|
||||||
|
delete _foundEntry._val;
|
||||||
|
}
|
||||||
|
delete _foundEntry;
|
||||||
|
_hashEntryCount--;
|
||||||
|
found=true;
|
||||||
|
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
uint Hash::_primes[] = {
|
||||||
|
17, 53, 97, 193, 389,
|
||||||
|
769, 1543, 3079, 6151,
|
||||||
|
12289, 24593, 49157, 98317,
|
||||||
|
196613, 393241, 786433, 1572869,
|
||||||
|
3145739, 6291469, 12582917, 25165843,
|
||||||
|
50331653, 100663319, 201326611, 402653189,
|
||||||
|
805306457, 1610612741};
|
||||||
|
|
||||||
|
/// Class to iterate over a Hash using ...
|
||||||
|
/// <pre>
|
||||||
|
/// HashLoop *l
|
||||||
|
/// for (l = new HashLoop(h) ; l.hasNext() ; l.next() ) {
|
||||||
|
/// string key = l.key();
|
||||||
|
/// MyClass *c = l.val();
|
||||||
|
/// }
|
||||||
|
/// delete l;
|
||||||
|
/// </pre>
|
||||||
|
class HashLoop {
|
||||||
|
private:
|
||||||
|
uint _index;
|
||||||
|
HashEntry *_currentEntry;
|
||||||
|
Hash *_hash;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Create iterator for a hash - move to first item
|
||||||
|
HashLoop(Hash *h) {
|
||||||
|
setHash(h);
|
||||||
|
}
|
||||||
|
~HashLoop() {};
|
||||||
|
|
||||||
|
/// Clear current state and move to first item (if any).
|
||||||
|
void reset() {
|
||||||
|
_index=0;
|
||||||
|
_currentEntry = _hash.getEntry(_index);
|
||||||
|
|
||||||
|
// Move to first item
|
||||||
|
if (_currentEntry == NULL) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the hash over which to iterate.
|
||||||
|
void setHash(Hash *h) {
|
||||||
|
_hash = h;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if more items.
|
||||||
|
bool hasNext() {
|
||||||
|
bool ret = ( _currentEntry != NULL);
|
||||||
|
//config("hasNext=",ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move to next item.
|
||||||
|
void next() {
|
||||||
|
|
||||||
|
//config("next : index = ",_index);
|
||||||
|
|
||||||
|
// Advance
|
||||||
|
if (_currentEntry != NULL) {
|
||||||
|
_currentEntry = _currentEntry._next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep advancing if _currentEntry is null
|
||||||
|
while (_currentEntry==NULL) {
|
||||||
|
_index++;
|
||||||
|
if (_index >= _hash.getSlots() ) return ;
|
||||||
|
_currentEntry = _hash.getEntry(_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the key name of the current item.
|
||||||
|
string key() {
|
||||||
|
if (_currentEntry != NULL) {
|
||||||
|
return _currentEntry._key;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the value.
|
||||||
|
HashValue *val() {
|
||||||
|
if (_currentEntry != NULL) {
|
||||||
|
return _currentEntry._val;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience functions for retriving int from a current HashInt entry
|
||||||
|
int valInt() {
|
||||||
|
return ((HashInt *)val()).getVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience functions for retriving int from a current HashString entry
|
||||||
|
string valString() {
|
||||||
|
return ((HashString *)val()).getVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience functions for retriving int from a current HashDouble entry
|
||||||
|
double valDouble() {
|
||||||
|
return ((HashDouble *)val()).getVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience functions for retriving int from a current HashLong entry
|
||||||
|
long valLong() {
|
||||||
|
return ((HashLong *)val()).getVal();
|
||||||
|
}
|
||||||
|
/// Convenience functions for retriving int from a current HashDatetime entry
|
||||||
|
datetime valDatetime() {
|
||||||
|
return ((HashDatetime *)val()).getVal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+1013
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user