Compare commits

..

140 Commits

Author SHA1 Message Date
Viacheslav Demydiuk 1a1b0cd822 Issue #218: Used refenrces instead of pointers in C++ functions 2020-11-01 15:59:11 +02:00
Viacheslav Demydiuk f6659ed91d MTApiService version 1.0.34 2020-11-01 15:52:51 +02:00
Viacheslav Demydiuk 56a48e328b Issue #218: signed MtApiSerivce.dll 2020-11-01 13:13:08 +02:00
Viacheslav Demydiuk f9a589c2c4 MtApi [MT5] version 1.0.24 2020-11-01 12:23:30 +02:00
Viacheslav Demydiuk df579ccdd1 [MT5] logging improvements 2020-11-01 12:16:54 +02:00
Viacheslav Demydiuk 318bae3852 Issue #209: [MT5] Added function ChartId to get chart id by expert handle. 2020-10-25 19:20:44 +02:00
Vyacheslav Demidyuk 60c8a646ff Merge pull request #217 from KptKuck/dev_matlab_basic_example
add a simple MatLab example with Output Windows
2020-10-25 15:58:40 +02:00
Vyacheslav Demidyuk 8e6c677e67 Merge pull request #216 from KptKuck/dev_matlab_adv_example
Add a advanced MatLab example
2020-10-25 15:54:04 +02:00
Vyacheslav Demidyuk ee3d47d625 Merge pull request #214 from KptKuck/dev_labor
add a simple python example
2020-10-25 15:48:45 +02:00
Christian_x7 258a98f7d5 add a simple MatLab example with Output Windows 2020-10-24 11:47:42 +02:00
Christian_x7 a6e3c2a3e8 forgotten files :-) 2020-10-24 10:24:10 +02:00
Christian_x7 76a6216cf7 Add a advanced example
It uses its own API which I packed between MTApi5 and MatLab.
Possible that this is useless, but errors from the .NET assembly are more tradable.
2020-10-24 10:14:58 +02:00
Christian_x7 06516d1d46 add a simple python example 2020-10-24 05:04:59 +02:00
Viacheslav Demydiuk 9eedf15e9e Issue #208: fixed issue with calling CheckOrders after starting TradeMonitor event MtApi has disconnected state 2020-10-22 22:26:17 +03:00
Viacheslav Demydiuk 373bfe4997 [MT4] Log improvements 2020-10-22 21:24:28 +03:00
Viacheslav Demydiuk 0cd8edb933 Updated LogConfigurator to avoid creation of many log files during several clients in one app session 2020-10-22 21:19:30 +03:00
Viacheslav Demydiuk a66f18c2b3 MTApiService version 1.0.33 2020-10-22 20:11:51 +03:00
Viacheslav Demydiuk 71964c3303 MtApi (MT4) version 1.0.42 2020-10-22 16:25:18 +03:00
Vyacheslav Demidyuk 4e7f8b93f4 Merge pull request #208 from mbochmann/dev
Changed design of monitors for better extensibility
2020-10-22 18:57:16 +03:00
Mitja Bochmann 5715e7e2b8 Update readme.md 2020-10-18 11:12:28 +02:00
Mitja 833ce1f192 Added ModifiedOrdersMonitor, added some more doc 2020-10-18 11:05:18 +02:00
m.bochmann 724162f29d Updated documentation of newly added classes 2020-10-13 15:52:55 +02:00
m.bochmann 739567d871 Bugfix in TimerTradeMonitor
SyncTrigger should only be set to true by default when the trigger will be initialized in the constructor.
2020-10-13 15:36:59 +02:00
m.bochmann a12ddba765 Changed design of monitors for better extensibility 2020-10-13 15:10:26 +02:00
Viacheslav Demydiuk 9a5acac2db Update readme: updated links 2020-10-13 15:19:26 +03:00
Viacheslav Demydiuk 7a776de8d3 Update readme: added link to telegram's chat 2020-10-13 15:18:03 +03:00
Viacheslav Demydiuk ce7953eee0 Issue #204: [MT5] Added function OrderSendAsync 2020-10-13 15:16:55 +03:00
Viacheslav Demydiuk 93aed4e44c Issue #202: [MT5] added Buy/Sell functions 2020-10-13 14:14:59 +03:00
Viacheslav Demydiuk 4c8c3b8766 MtApi [MT5] version 1.0.23 2020-09-04 12:10:26 +03:00
Viacheslav Demydiuk 73ebde8b6b Added link on Telegram's channel to readme 2020-08-30 12:28:54 +03:00
Viacheslav Demydiuk e33ba5b51f Issue #190: updated MtApi5.mq5 to version 1.7. Init string variable _erro 2020-08-28 18:54:33 +03:00
Viacheslav Demydiuk a0a4263e24 Issue #190: implemented function sendErrorResponse in Mt5Connector 2020-08-28 17:39:49 +03:00
Viacheslav Demydiuk 5d18dd4ad3 MTApiService version 1.0.32 2020-08-28 17:28:34 +03:00
Viacheslav Demydiuk 03ff1f9176 MtApi [MT5] version 1.0.22 2020-08-28 16:48:31 +03:00
Viacheslav Demydiuk f376b4e0e5 MtApi (MT4) version 1.0.41 2020-08-26 22:59:21 +03:00
Viacheslav Demydiuk fc54b5dd4a Updated test application (MT5) to perform testing functions iBullsPower, iBearsPower, BarsCalculated, CopyBuffer. 2020-08-26 21:06:26 +03:00
Viacheslav Demydiuk dd05804082 Issue #201: call iBullsPower instead iBearsPower in MQL 2020-08-26 17:53:31 +03:00
Viacheslav Demydiuk 4349eb3538 Issue #186: Implemented function PositionClosePartial 2020-08-24 22:43:20 +03:00
Vyacheslav Demidyuk e0daf9a82e Merge pull request #198 from KptKuck/dev
Add switchable Events / fix typo in AddLog()
2020-08-09 11:00:55 +03:00
Christian_X3 3997b6df74 add switchable Events
The function SendMtEvent requires a lot of computing time. To improve the speed of the tester, the events can now be switched off individually
2020-06-18 05:57:05 +02:00
Christian_X3 abfe1a281a fix typo in Addlog() 2020-06-18 05:03:21 +02:00
Viacheslav Demydiuk 93bfe8e56f removed redundant old projects from repo 2020-02-20 17:33:30 +02:00
Viacheslav Demydiuk bb27b4e50d #187: removed reference to Newtonsoft.Json in project TestApiClientUI 2020-02-20 17:29:06 +02:00
vdemydiuk 0f809cd60a MtApi [MT5] version 1.0.21 2019-11-11 12:52:28 +02:00
vdemydiuk f22a6c21f0 Updated gitignore file: added .vs folder 2019-11-07 15:45:19 +02:00
vdemydiuk 625753d83a Issue #142: removed old solution of VS 2015. Updated readme file related to VS 2017 2019-11-07 15:12:26 +02:00
vdemydiuk d621312a8b Merged fix of issue #175 from master 2019-11-06 11:59:41 +02:00
Vyacheslav Demidyuk a4df4bbf1e Merge pull request #177 from vlariono/master
#175 Fix null reference exception
2019-11-06 11:46:18 +02:00
vdemydiuk 43ef628c69 Issue #142: added support VS 2017 2019-11-05 17:03:58 +02:00
vdemydiuk 688149bd67 Merge branch 'master' into dev 2019-11-05 17:01:37 +02:00
Vyacheslav Demidyuk c33a5ed6f5 Merge pull request #174 from HengzheLi/fix-#173
#173 update IF checking
2019-11-05 15:39:28 +02:00
Vasily Larionov 828c1185b3 Position modify 2019-09-24 18:52:56 +03:00
Vasily Larionov 4b384d9da2 Fix null reference exception 2019-09-21 17:20:31 +03:00
hectorli 26de553443 #173 update IF checking 2019-08-27 22:15:59 +08:00
vdemydiuk ee81cfe012 Issue #143: Added function TesterStop [MT5] 2019-05-04 10:36:46 +03:00
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
vdemydiuk 52ca4fae1e MtApi5.ex5: Update version to 1.5. Disable debug logging 2018-03-27 11:25:22 +03:00
vdemydiuk 6b327e017a Removed unnecessary Windows Operations from MtApi5 code (MT5) 2018-03-27 11:11:33 +03:00
vdemydiuk 10a758bd93 Updated test application (MT5) to perform testing functions ChartIndicatorAdd, ChartIndicatorGet 2018-03-27 10:22:16 +03:00
vdemydiuk 4a9642b60c Issue #109: Fixed typo 'Magic' to 'Order' in MQL function JsonToMqlTradeRequest 2018-03-26 18:06:39 +03:00
vdemydiuk 6ba6496e46 Implemented functions ChartIndicatorAdd and ChartIndicatorGet 2018-03-24 21:45:35 +02:00
vdemydiuk 1ffbba5ee3 Updated test application (MT5) to perform testing functions ChartNavigate, ChartIndicatorDelete, ChartIndicatorName, ChartIndicatorsTotal, ChartWindowOnDropped, ChartPriceOnDropped, ChartTimeOnDropped, ChartXOnDropped, ChartYOnDropped, ChartSetSymbolPeriod, ChartScreenShot 2018-03-24 19:08:40 +02:00
vdemydiuk 8cdfd6fb91 Updated test application (MT5) to perform testing function ChartGetDouble and ChartGetInteger 2018-03-19 19:10:51 +02:00
vdemydiuk 7c3ddbabac Updated test application (MT5) to perform testing function ChartSetInteger and ChartSetString 2018-03-19 18:58:12 +02:00
vdemydiuk 83e0145a3a Updated test application (MT5) to perform testing function ChartPeriod and ChartSetDouble 2018-03-19 18:39:15 +02:00
vdemydiuk f17c7cd554 Updated test application (MT5) to perform testing function ChartWindowFind and ChartClose 2018-03-19 17:23:16 +02:00
vdemydiuk 4aefdd554b Updated test application (MT5) to perform testing function ChartId and ChartRedraw 2018-03-19 16:23:55 +02:00
vdemydiuk 820ed9a631 Refactored UI test client (MT5) 2018-03-19 15:10:09 +02:00
vdemydiuk 95c55e90be Added field ExpertHandle into class Mt5Quote 2018-03-19 15:09:02 +02:00
vdemydiuk 486a1979a6 Implemented functions ChartIndicatorName, ChartIndicatorsTotal, ChartWindowOnDropped, ChartPriceOnDropped, ChartTimeOnDropped, ChartXOnDropped, ChartYOnDropped, ChartSetSymbolPeriod, ChartScreenShot (MT5) 2018-03-15 17:44:53 +02:00
vdemydiuk faef5f7d18 Implemented function ChartIndicatorDelete (MT5) 2018-03-15 13:15:50 +02:00
vdemydiuk bd45c45fa1 Implemented function ChartNavigate (MT5) 2018-03-15 12:55:46 +02:00
vdemydiuk 29be184136 Implemented functions ChartGetDouble, ChartGetInteger (MT5) 2018-03-15 11:20:20 +02:00
vdemydiuk 9bfda95cf7 Implemented functions ChartSetDouble, ChartSetInteger, ChartSetString (MT5) 2018-03-14 19:53:53 +02:00
vdemydiuk 24b881d8a0 Implemented function ChartPeriod (MT5) 2018-03-14 19:16:29 +02:00
vdemydiuk 07dd83f890 Implemented functions ChartId, ChartRedraw, ChartWindowFind, ChartClose (MT5) 2018-03-14 18:10:44 +02:00
vdemydiuk 9afd30e463 Implemented function Alert (MT5) 2018-03-13 18:24:40 +02:00
vdemydiuk 16f454ca61 Implemented functions ChartTimePriceToXY, ChartXYToTimePrice (MT5) 2018-03-13 17:28:21 +02:00
vdemydiuk f3a3a582fd Issue #100: update test application for testing function SymbolInfoString (MT5) 2018-03-13 11:40:16 +02:00
vdemydiuk 93aaae86ed Issue #100: implemented second function SymbolInfoString (MT5) 2018-03-13 11:20:55 +02:00
Vyacheslav Demidyuk bce68fd168 Merge pull request #104 from Janderson/master
TerminalInfo Commands and ChartTemplate Commands
2018-03-13 10:54:16 +02:00
Janderson 0812229538 Chart Commands:
- ChartSaveTemplate Implemented
2018-03-12 23:08:04 -03:00
Janderson d0fa4af1d0 - Bug fix - when click in chartApplyTemplateButton, store template file in right place 2018-03-12 22:44:08 -03:00
Janderson 8eb4bcfabe Commands to handle with Terminal:
- TerminalInfoDoublePropertyId
- TerminalInfoIntegerPropertyId
- TerminalInfoStringPropertyId
2018-03-12 22:37:06 -03:00
Vyacheslav Demidyuk 9ea58354be Merge pull request #103 from Janderson/master
Missing function to mql5
2018-03-12 16:49:21 +02:00
Janderson FFerreira 02774d7328 Merge branch 'mt5_1_0_18' into master 2018-03-12 11:34:00 -03:00
Janderson FFerreira cbff71f8d0 - Correction of Test Client
- Missing codes in mtapi5.mq5
2018-03-12 11:17:12 -03:00
Janderson FFerreira 951a91976c - missing mql5 file 2018-03-11 19:56:28 -03:00
Janderson FFerreira 6a37826486 - Add some commands to handle with Chart to MT5 api
- Add some commands to handle with windows to MT5 api
2018-03-11 19:26:25 -03:00
vdemydiuk cab2de6d24 Issue #100: implemented functions GetLastError, ResetLastError() in MtApi (MT5) 2018-03-09 19:18:54 +02:00
vdemydiuk ec6c71607b Issue #96: Implemented function PositionGetTicket in MtApi (MT5) 2018-03-08 17:45:22 +02:00
vdemydiuk 0a39b69b15 Issue #95: Added default constructors to classes MqlBookInfo, MqlTradeCheckResult 2018-03-08 16:22:37 +02:00
vdemydiuk fe94ec21de Issue #102: fixed long type of result in function SeriesInfoInteger 2018-03-08 15:31:02 +02:00
vdemydiuk 34c78c73c0 Started version 1.0.18 (MT5) 2018-03-08 15:26:29 +02:00
vdemydiuk d7b8ef894c Issue #93: Fixed typo Cction (Action) in MtApi5.mq5 2018-03-02 13:22:40 +02:00
vdemydiuk 7f33cebce1 MtApi5: Set version 1.0.17 2018-03-02 12:21:54 +02:00
vdemydiuk 84740787d5 Issue #94: Added event handler OnBookEvent (MT5). 2018-03-02 11:43:03 +02:00
vdemydiuk ad6bad5187 Issue #93: Added event OnTradeTransaction. Udpated json.mqh to fix JSONNumber for correct serialization zero integer value". 2018-03-01 11:20:25 +02:00
vdemydiuk 0086b02bc8 Issue #92: Updated test application (MT5) to use functions IndicatorCreate and IndicatorRelease 2018-02-27 18:26:37 +02:00
vdemydiuk f7e06c1570 Issue #92: Added functions IndicatorCreate and IndicatorRelease 2018-02-27 09:49:26 +02:00
vdemydiuk c86a3a3752 Issue #91: Added MarketBookGetRequest to perform function MarketBookGet (MT5) 2018-02-21 14:43:25 +02:00
vdemydiuk be8a17c0fd Issue #88: Activate execute commands in tester mode (MT5) 2018-02-19 19:21:29 +02:00
vdemydiuk 5c6751de9b Issue #90: Added time functions: TimeCurrent, TimeTradeServer, TimeLocal, TimeGMT 2018-02-19 18:48:31 +02:00
vdemydiuk 83776f8b7a Minor refactoring to remote redundant code 2018-02-19 17:12:26 +02:00
vdemydiuk f1c1df1e00 Issue #89: Changed function OrderCheck to use json request/response 2018-02-19 17:02:19 +02:00
vdemydiuk d6640300f5 Issue #89: Changed function PositionOpen to use json request/response 2018-02-19 15:54:03 +02:00
vdemydiuk c9c188f697 Minor refactoring to remove code syle warnings 2018-02-19 13:37:43 +02:00
vdemydiuk 3a4f561836 Issue #87: Added event QuoteUpdate to MtApi5Client (MT5) for compatibility with MATLAB 2018-02-19 11:49:52 +02:00
vdemydiuk bdb30edee3 Issue #82: Responsed moved to Request folder 2018-02-19 11:27:07 +02:00
vdemydiuk 29f501b055 Issue #82: Refactored request responses (MtAp5). Added iCustom functions with string and boolean parameters. Added button iCustom in test application (MT5). 2018-02-19 11:07:37 +02:00
vdemydiuk 521d7ea2c0 Issue #82: Disabled debug mode in MtApi5.ex5. Updated test client to send order with values Expiration and Comment 2018-02-18 20:24:27 +02:00
DW 0e5bb40a6f Issue #82: Refactored MQL5 expert to use json in function OrderSend 2018-02-17 00:10:10 +02:00
vdemydiuk 14079dc3c1 Issue #82: Added stub class OrderSendRequest 2018-02-15 20:32:22 +02:00
vdemydiuk 3600a86971 MtApiService version 1.0.29. Added log wrapper class MtLog 2018-02-15 17:37:08 +02:00
vdemydiuk 83e62fbff7 Started version 1.0.16 (MT5) 2018-02-15 17:33:02 +02:00
vdemydiuk 5c96aeb2fd Issue #81: Added function TimeGMT into MtApi (MT4) 2018-02-13 19:02:08 +02:00
vdemydiuk a238e5eb36 Issue #80: Fixed wrong condition on fetch first parameter in function Execute_TerminalInfoString 2018-02-13 18:35:40 +02:00
vdemydiuk 11fd5b7527 Started version 1.0.40 (MT4) 2018-02-13 18:33:11 +02:00
171 changed files with 14427 additions and 3139 deletions
+3
View File
@@ -18,6 +18,9 @@ bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Roslyn cache directories
*.ide/
-30
View File
@@ -1,30 +0,0 @@
<Window x:Class="ConnectionsManager.AboutWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="About" Height="130" Width="300"
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<BitmapImage x:Key="MtApiIcon" UriSource="pack://application:,,,/ConnectionsManager;component/favicon.ico"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{StaticResource MtApiIcon}" Width="50" Height="50" HorizontalAlignment="Left" Margin="5"/>
<TextBlock Grid.Column="1" Text="Connection manager for MtApi" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<Button Grid.Row="1" Content="OK" Margin="5"
Width="70" IsDefault="True" IsCancel="True"
DockPanel.Dock="Bottom"
VerticalAlignment="Center"/>
</Grid>
</Window>
-28
View File
@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace ConnectionsManager
{
/// <summary>
/// Interaction logic for AboutWindow.xaml
/// </summary>
public partial class AboutWindow : Window
{
public AboutWindow(Window owner)
{
InitializeComponent();
this.Owner = owner;
}
}
}
-43
View File
@@ -1,43 +0,0 @@
<Window x:Class="ConnectionsManager.AddProfileDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Add new connection profile" Height="180" Width="300"
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner">
<Grid x:Name="_MainLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Profile name" Margin="5"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="5"
Text="{Binding Path=ProfileName, UpdateSourceTrigger=PropertyChanged}"
TextChanged="TextBox_TextChanged"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Host" Margin="5"/>
<ComboBox Grid.Row="1" Grid.Column="1" Margin="5"
ItemsSource="{Binding HostList}"
SelectedItem="{Binding Host}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Port" Margin="5"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="5"
Text="{Binding Path=Port, UpdateSourceTrigger=PropertyChanged}"
PreviewTextInput="TextBox_PreviewTextInput"
TextChanged="TextBox_TextChanged"/>
<StackPanel Grid.Row="3" Grid.ColumnSpan="2" Margin="0,10,0,0"
Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<Button Content="OK" Width="70" Margin="4" IsDefault="True" Command="{Binding OkCommand}"/>
<Button Content="Cancel" Width="70" Margin="4" IsCancel="True"/>
</StackPanel>
</Grid>
</Window>
@@ -1,97 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Net;
namespace ConnectionsManager
{
/// <summary>
/// Interaction logic for AddProfileDialog.xaml
/// </summary>
public partial class AddProfileDialog : Window
{
// private const string PIPE_SERVER_NAME = "localhost(pipe)";
private const string LOCALHOST_NAME = "localhost";
public string ProfileName { get; set; }
public static readonly DependencyProperty HostProperty = DependencyProperty.Register("Host", typeof(string), typeof(AddProfileDialog));
public string Host
{
get { return (string)this.GetValue(HostProperty); }
set { this.SetValue(HostProperty, value); }
}
public string Port { get; set; }
public DelegateCommand OkCommand { get; set; }
public List<string> HostList { get; set; }
public AddProfileDialog(Window owner)
{
InitializeComponent();
this.Owner = owner;
OkCommand = new DelegateCommand(ExecuteOk, CanExecuteOk);
_MainLayout.DataContext = this;
Loaded += (sender, e) => MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());
HostList = new List<string>();
HostList.Add(string.Empty);
HostList.Add(LOCALHOST_NAME);
if (ips != null)
{
foreach (IPAddress ipAddress in ips.AddressList)
{
HostList.Add(ipAddress.ToString());
}
}
Host = HostList.First();
}
private bool CanExecuteOk(object o)
{
return string.IsNullOrEmpty(ProfileName) == false
&& string.IsNullOrEmpty(Port) == false;
}
private void ExecuteOk(object o)
{
this.DialogResult = true;
Close();
}
private static bool IsTextAllowed(string text)
{
Regex regex = new Regex("[^0-9]+");
return !regex.IsMatch(text);
}
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = !IsTextAllowed(e.Text);
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
OkCommand.RaiseCanExecuteChanged();
}
}
}
-8
View File
@@ -1,8 +0,0 @@
<Application x:Class="ConnectionsManager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
-16
View File
@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace ConnectionsManager
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C8751BA1-6A85-468C-87BD-758F37B8C0DD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ConnectionsManager</RootNamespace>
<AssemblyName>ConnectionsManager</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisLogFile>bin\Debug\ConnectionsManager.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisLogFile>bin\Release\ConnectionsManager.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="AboutWindow.xaml.cs">
<DependentUpon>AboutWindow.xaml</DependentUpon>
</Compile>
<Compile Include="AddProfileDialog.xaml.cs">
<DependentUpon>AddProfileDialog.xaml</DependentUpon>
</Compile>
<Compile Include="DelegateCommand.cs" />
<Compile Include="ViewModel.cs" />
<Page Include="AboutWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="AddProfileDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MTApiService\MTApiService.csproj">
<Project>{DE76D5C7-B99C-4467-8408-78173BDD84E0}</Project>
<Name>MTApiService</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="favicon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy $(TargetPath) $(SolutionDir)Release\</PostBuildEvent>
</PropertyGroup>
<!-- 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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
-51
View File
@@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
namespace ConnectionsManager
{
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
-35
View File
@@ -1,35 +0,0 @@
<Window x:Class="ConnectionsManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MtApi Connections Manager" Height="300" Width="440"
Loaded="Window_Loaded">
<Grid x:Name="_MainLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu>
<MenuItem Header="Edit">
<MenuItem Header="Add Profile..." Command="{Binding AddProfileCommand}"/>
<MenuItem Header="Delete Profile" Command="{Binding DeleteProfileCommand}"/>
</MenuItem>
<MenuItem Header="Help">
<MenuItem Header="About" Command="{Binding ShowAboutCommand}"/>
</MenuItem>
</Menu>
<ListView Grid.Row="1"
ItemsSource="{Binding ConnectionProfiles}"
SelectionMode="Single"
SelectedItem="{Binding SelectedProfile}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Profile" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="180" Header="Host" DisplayMemberBinding="{Binding Host}" />
<GridViewColumn Width="80" Header="Port" DisplayMemberBinding="{Binding Port}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
-37
View File
@@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ConnectionsManager
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm = new ViewModel();
_MainLayout.DataContext = _vm;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_vm.Initialize();
}
}
}
@@ -1,55 +0,0 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConnectionsManager")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConnectionsManager")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
-63
View File
@@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18034
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ConnectionsManager.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConnectionsManager.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-26
View File
@@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18034
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ConnectionsManager.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
-114
View File
@@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using MTApiService;
using System.ComponentModel;
using System.Windows;
namespace ConnectionsManager
{
class ViewModel : INotifyPropertyChanged
{
#region Properties
private ObservableCollection<MtConnectionProfile> _ConnectionProfiles = new ObservableCollection<MtConnectionProfile>();
public ObservableCollection<MtConnectionProfile> ConnectionProfiles
{
get { return _ConnectionProfiles; }
}
public DelegateCommand AddProfileCommand { get; private set; }
public DelegateCommand DeleteProfileCommand { get; private set; }
public DelegateCommand ShowAboutCommand { get; private set; }
private MtConnectionProfile _SelectedProfile;
public MtConnectionProfile SelectedProfile
{
get { return _SelectedProfile; }
set
{
_SelectedProfile = value;
OnPropertyChanged("SelectedProfile");
DeleteProfileCommand.RaiseCanExecuteChanged();
}
}
#endregion
#region Public Methods
public ViewModel()
{
AddProfileCommand = new DelegateCommand(ExecuteAddProfile);
DeleteProfileCommand = new DelegateCommand(ExecuteDeleteProfile, CanExecuteDeleteProfile);
ShowAboutCommand = new DelegateCommand(ExecuteShowAbout);
}
public void Initialize()
{
var profiles = MtRegistryManager.LoadConnectionProfiles();
if (profiles != null)
{
foreach(var prof in profiles)
{
ConnectionProfiles.Add(prof);
}
}
}
#endregion
#region Private Methods
private void ExecuteAddProfile(object o)
{
var dlg = new AddProfileDialog(App.Current.MainWindow);
var result = dlg.ShowDialog();
if (result == true)
{
var profile = new MtConnectionProfile(dlg.ProfileName);
profile.Host = dlg.Host;
profile.Port = int.Parse(dlg.Port);
MtRegistryManager.AddConnectionProfile(profile);
ConnectionProfiles.Add(profile);
}
}
private bool CanExecuteDeleteProfile(object o)
{
return SelectedProfile != null;
}
private void ExecuteDeleteProfile(object o)
{
var result = MessageBox.Show("Do you want to delete connection profile '" + SelectedProfile.Name + "' ?"
, "Question", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
MtRegistryManager.RemoveConnectionProfile(SelectedProfile.Name);
ConnectionProfiles.Remove(SelectedProfile);
}
}
private void ExecuteShowAbout(object o)
{
var dlg = new AboutWindow(App.Current.MainWindow);
dlg.ShowDialog();
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Fields
#endregion
}
}
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

@@ -0,0 +1,283 @@
classdef Bars < handle
%BARS Summary of this class goes here
% Detailed explanation goes here
properties
chSymbol = 'EURUSD' ;
iSize = int32(0) ;
iLast = int32(0) ;
sStart = "" ;
sEnd = "" ;
sdtStart = System.DateTime.Now;
sdtEnd = System.DateTime.Now;
enTimeframe = MtApi5.ENUM_TIMEFRAMES;
mqlRates = NET.createArray('MtApi5.MqlRates', 0);
sdOpen = NET.createArray('System.Double[]', 3) ;
sdHigh = NET.createArray('System.Double[]', 3) ;
sdLow = NET.createArray('System.Double[]', 3) ;
sdClose = NET.createArray('System.Double[]', 3) ;
sdtTime = NET.createArray('System.DateTime[]', 3) ;
si32Spread = NET.createArray('System.Int32[]', 3) ;
si64TickVolume = NET.createArray('System.Int64[]', 3) ;
si64RealVolume = NET.createArray('System.Int64[]', 3) ;
si64RealVolumeH = NET.createArray('System.Int64[]', 3) ;
si64RealVolumeL = NET.createArray('System.Int64[]', 3) ;
dOpen = double(0);
dHigh = double(0);
dLow = double(0);
dClose = double(0);
i64MTtime = int64(0) ;
dtTime = datetime();
i32Spread = int32(0) ;
i64TickVol = int64(0) ;
i64RealVol = int64(0) ;
i64RealVolH = int64(0) ;
i64RealVolL = int64(0) ;
end
methods
function obj = Bars(chSymbol,enTF,iSize)
switch nargin
case 0
obj.chSymbol = 'EURUSD';
obj.iSize = 1000;
obj.enTimeframe = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
return
case 1
case 2
case 3
obj.chSymbol = chSymbol;
obj.iSize = iSize;
obj.enTimeframe = enTF;
otherwise
end
obj.mqlRates = NET.createArray('MtApi5.MqlRates', obj.iSize);
obj.sdOpen = NET.createArray('System.Double', obj.iSize);
obj.sdHigh = NET.createArray('System.Double', obj.iSize);
obj.sdLow = NET.createArray('System.Double', obj.iSize);
obj.sdClose = NET.createArray('System.Double', obj.iSize);
obj.sdtTime = NET.createArray('System.DateTime', obj.iSize);
obj.si32Spread = NET.createArray('System.Int32', obj.iSize);
obj.si64TickVolume = NET.createArray('System.Int64', obj.iSize);
obj.si64RealVolume = NET.createArray('System.Int64', obj.iSize);
obj.sdtStart = System.DateTime.Now;
obj.sdtEnd = System.DateTime.Now;
obj.sStart = char(obj.sdtStart.ToString);
obj.sEnd = char(obj.sdtStart.ToString);
obj.enTimeframe = enTF;
obj.dOpen = zeros(obj.iSize,1,'double') ;
obj.dHigh = zeros(obj.iSize,1,'double') ;
obj.dLow = zeros(obj.iSize,1,'double') ;
obj.dClose = zeros(obj.iSize,1,'double') ;
obj.i32Spread = zeros(obj.iSize,1,'int32') ;
obj.i64TickVol = zeros(obj.iSize,1,'int64') ;
obj.i64RealVol = zeros(obj.iSize,1,'int64') ;
obj.i64RealVolH = zeros(obj.iSize,1,'int64') ;
obj.i64RealVolL = zeros(obj.iSize,1,'int64') ;
obj.i64MTtime = zeros(obj.iSize,1,'int64') ;
obj.dtTime(iSize,1) = datetime;
obj.dtTime.Format = 'default';
end
function setMqlRates(self,MqlRates)
self.MqlRates = MqlRates;
end
function saveDataAsByteStream(self,filename)
mc = ?DataStore.Bars;
propList = mc.PropertyList;
propCnt = length(propList);
for i=1:1:propCnt
bytestream.(propList(i).Name) = [];
end
formatter = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter;
for idx=1:1:propCnt
if isa(propList(idx).DefaultValue,'System.Object')
stream = System.IO.MemoryStream;
formatter.Serialize(stream,self.(propList(idx).Name));
data = uint8(stream.ToArray);
bytestream.(propList(idx).Name) = data;
else
% stream = System.IO.MemoryStream;
% formatter.Serialize(stream,self.(propList(idx).Name));
% data = uint8(stream.ToArray);
bytestream.(propList(idx).Name) = self.(propList(idx).Name);
end
end
save(filename,'bytestream');
end
function ok = loadDataAsByteStream(self,filename)
ok = false;
load(filename);
mc = ?DataStore.Bars;
propList = mc.PropertyList;
propCnt = length(propList);
formatter = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter;
for idx=1:1:propCnt
if isa(propList(idx).DefaultValue,'System.Object')
data = bytestream.(propList(idx).Name);
stream = System.IO.MemoryStream(data);
self.(propList(idx).Name) = formatter.Deserialize(stream);
else
data = bytestream.(propList(idx).Name);
self.(propList(idx).Name) = data;
end
end
ok = true;
end
function saveableData = Get_Saveable_MATfileData(self,varargin)
switch nargin
case 1 % no options
first = 1;
last = self.iLast;
case 2 % first = 1 , last = input
first = 1;
last = varargin{2};
case 3
first = varargin{1};
last = varargin{2};
end
if last > self.iLast
last = self.iLast;
warn('Index is out of array')
warn('Using iLast for last')
end
saveableData.chSymbol = self.chSymbol;
saveableData.iSize = self.iLast;
saveableData.iLast = self.iLast;
saveableData.sStart = self.sStart;
saveableData.sEnd = self.sEnd;
saveableData.dOpen = self.dOpen(first:last,1);
saveableData.dHigh = self.dHigh(first:last,1);
saveableData.dLow = self.dLow(first:last,1);
saveableData.dClose = self.dClose(first:last,1);
saveableData.dtTime = self.dtTime(first:last,1);
saveableData.i64MTtime = self.i64MTtime(first:last,1);
saveableData.i32Spread = self.i32Spread(first:last,1);
saveableData.i64TickVol = self.i64TickVol(first:last,1);
saveableData.i64RealVol = self.i64RealVol(first:last,1);
end
function tt= Get_TimeTable(self,varargin)
switch nargin
case 1 % no options
first = 1;
last = self.iLast;
case 2 % first = 1 , last = input
first = 1;
last = varargin{2};
case 3
first = varargin{1};
last = varargin{2};
end
if last > self.iLast
last = self.iLast;
warn('Index is out of array')
warn('Using iLast for last')
end
Open = self.dOpen(first:last,1);
High = self.dHigh(first:last,1);
Low = self.dLow(first:last,1);
Close = self.dClose(first:last,1);
Time = self.dtTime(first:last,1);
TicklVol = self.i64TickVol(first:last,1);
tt = timetable(Time,Open,High,Low,Close,TicklVol);
tt.Properties.VariableNames = {'Open','High','Low','Close','TickVol'};
end
end
end
@@ -0,0 +1,46 @@
classdef Deal < handle
%DEAL Summary of this class goes here
% Detailed explanation goes here
properties
% Integer
DEAL_TICKET = int32([]); % Das Ticket des Trades. Das ist eine einmalige Nummer, die jedem Trade zugewiesen wird.
DEAL_ORDER = int32([]); % Order, auf deren Grund der Deal abgeschlossen wurde
DEAL_TIME = datetime([],[],[]); % Zeit des Dealabschlusses
DEAL_TIME_MSC = int32([]) % Zeitpunkt der Transaktion in Millisekunden seit 01.01.1970
DEAL_TYPE = MtApi5.ENUM_DEAL_TYPE; % Typ des Deals
DEAL_ENTRY = MtApi5.ENUM_DEAL_ENTRY; % Dealsrichtung - Markteingang, Marktausgang oder Kehrwendung
DEAL_MAGIC = int32([]) % Magic number für Deal (sehen Sie ORDER_MAGIC)
DEAL_REASON = MtApi5.ENUM_DEAL_REASON; % Grund oder Ursprung der Ausführung eines Abschlusses
DEAL_POSITION_ID = int32([]) % Indetifikator der Position, an deren Öffnung, Veränderung oder Schliessung sich der Deal teilnahm. Jede Position hat ihren unikalen Identifikator, der allen Deals zugeordnet wird, die im Instrument innerhalb des ganzen Lebens der Position abgeschlossen wurde.
% Double
DEAL_VOLUME = double([]); % Dealvolumen
DEAL_PRICE = double([]); % Dealpreis
DEAL_COMMISSION = double([]); % Dealkommission
DEAL_SWAP = double([]); % Gesamtswap beim Schliessen
DEAL_PROFIT = double([]); % finanzielles Ergebnis des Deals
% String
DEAL_SYMBOL = char([]); % Dealssymbol
DEAL_COMMENT = char([]); % Kommentar zum Deal
DEAL_EXTERNAL_ID = char([]); % Identifikator des Deals im Außenhandelssystem (an der Börse)
end
methods
function obj = Deal()
% DEAL Construct an instance of this class
% Detailed explanation goes here
% Create an empty Deal Object
end
function outputArg = method1(obj,inputArg)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
outputArg = obj.Property1 + inputArg;
end
end
end
@@ -0,0 +1,38 @@
classdef Position < handle
%POSITION Summary of this class goes here
% Detailed explanation goes here
properties
POSITION_TIME = datetime([],[],[]);
POSITION_TICKET = int64([]);
POSITION_TIME_MSC = int64([]);
POSITION_TIME_UPDATE = int64([]);
POSITION_TIME_UPDATE_MSC = int64([]);
POSITION_TYPE = MtApi5.ENUM_POSITION_TYPE;
POSITION_MAGIC = int64([]);
POSITION_IDENTIFIER = int64([]);
POSITION_REASON = MtApi5.ENUM_POSITION_REASON;
POSITION_VOLUME = double([]);
POSITION_PRICE_OPEN = double([]);
POSITION_SL = double([]);
POSITION_TP = double([]);
POSITION_PRICE_CURRENT = double([]);
POSITION_SWAP = double([]);
POSITION_PROFIT = double([]);
POSITION_SYMBOL = char([]);
POSITION_COMMENT = char([]);
end
methods
function obj = Position()
%POSITION Construct an instance of this class
% Detailed explanation goes here
end
end
end
@@ -0,0 +1,29 @@
classdef Tick < handle
% Tick Summary of this class goes here
% Detailed explanation goes here
properties
sdt_Time; % Zeit des letzten Updates der Preise
d_Bid; % Laufender Preis Bid
d_Ask; % Laufender Preis Ask
d_Last; % Laufender Preis des letzten Deals (Last)
uI_Volume; % Volumen für laufenden Preis Last
I_Time_msc; % Zeit der letzten Aktualisierung der Preise in Millisekunden
I_MtTime; % Zeit der letzten Aktualisierung der Preise
ui_Flags % Tick-Flags
end
methods
function obj = Tick()
end
end
end
@@ -0,0 +1,86 @@
classdef Ticks < handle
% Ticks Summary of this class goes here
% Detailed explanation goes here
properties
mqlTicks; % DataStore.Tick Handles
I_Size = 0; % Anzahl der Ticks
end
methods
function obj = Ticks()
end
function ok = createMqlTicks(self,i_Count)
if isinteger(i_Count)
newticks(i_Count) = DataStore.Tick();
self.mqlTicks = newticks;
% self.I_Size = i_Count;
ok = true;
else
warning('Count must be Integer');
ok = false;
end
end
function ok = fillMqlTicks(self, I_Count, MqlTicks)
if self.I_Size == 0
ok = true;
else
warning('mqlTicks object size must be 0')
ok = false;
end
end
function ok = storeNewMqlTick(self,MqlTick)
I_newsize = self.I_Size+1;
self.mqlTicks(I_newsize).d_Bid = MqlTick.bid;
self.mqlTicks(I_newsize).d_Ask = MqlTick.ask;
self.mqlTicks(I_newsize).I_MtTime = MqlTick.MtTime;
self.mqlTicks(I_newsize).sdt_Time = MqlTick.time;
self.I_Size = I_newsize;
ok = true;
end
function ok = storeNewQuoteEvent(self,Event)
I_newsize = self.I_Size+1;
self.mqlTicks(I_newsize).d_Bid = Event.Quote.Bid;
self.mqlTicks(I_newsize).d_Ask = Event.Quote.Ask;
% self.mqlTicks(I_newsize).I_MtTime = MqlTick.MtTime;
% self.mqlTicks(I_newsize).sdt_Time = MqlTick.time;
self.I_Size = I_newsize;
% fprintf('%d Ticks stored \n',self.I_Size);
% fprintf('Bid: %d Ask: %d \n',Event.Quote.Bid , Event.Quote.Ask);
ok = true;
end
end
end
@@ -0,0 +1,79 @@
classdef TradingData < handle
%TRADINGDATA Summary of this class goes here
% Detailed explanation goes here
properties
core_trades
net_signal
net_class
net_score
net_input
end
properties (SetAccess=protected)
size
cnt
end
methods
function obj = TradingData()
%TRADINGDATA Construct an instance of this class
% Create datastore for logging all data
end
function ok = setup(self,size,sizeTrades)
%SETUP Summary of this method goes here
% Setup Object
% args:
% 1 = Array Size (Bars)
% 2 = Array Size Trades (default 1000)
self.size = size;
self.core_trades = zeros(sizeTrades,4);
self.net_signal = zeros(size,1);
self.net_signal = zeros(size,1);
self.net_score = zeros(size,4,'single');
a = repmat([0],3,500);
self.net_input = repmat({a},size,1);
classArray(size,1) = categorical(0);
self.net_class = classArray;
ok = true;
end
function set_Count(self,cnt)
self.cnt = cnt;
end
function store_NetInput(self,data)
self.net_input{self.cnt,1} = data{1,1};
end
function store_NetOutSignal(self,data)
self.net_signal(self.cnt) = data;
end
function store_NetOutClass(self,data)
self.net_class(self.cnt,1) = data;
end
function store_NetOutScore(self,data)
size = length(data);
self.net_score(self.cnt,1:size) = data(:);
end
function reorganizeData(self)
end
% Getters
function data = get_Data(self)
end
end
end
@@ -0,0 +1,507 @@
classdef Mt5Api < handle
%CONNECTMT5 Connects to the MtApi Client via .NET
properties
MTApi5_dll_Location = 'dll\MtApi5.dll'
% MTApi5_dll_Location = 'E:\GitHub-RePos\MtApi\build\products\Release\MtApi5.dll';% 1.021
% MTApi5_dll_Location = ' E:\GitHub-RePos\MtApi\MtApi5\bin\x64\Release\MtApi5.dll' ;% 1.021
% MTApi5_dll_Location = 'd:\Git-Extern\mtapi\build\products\Debug\MtApi5.dll';% 1.019
% MTApi5_dll_Location = 'D:\GitHub-RePos\MtApi\build\products\Release\MtApi5.dll'; % 1.0191
vVersion = 1.021;
h;
asm;
cAccount;
cCommon;
cCheckup;
cDateTime;
cEvents;
cMarketInfo;
cObject;
cProp;
cTeIndicator;
cTimeSeries;
cTrade;
cLogger;
fDeleteLogger;
hQuoteAddedListener;
hQuoteListener;
hConnectionListener;
hOnTradeTransactionListener;
hOnTesterDeInitListener % Listener for Tester DeInit Event
charConnectionState = 'StartUp';
bStatusDeInit = false; % Status Flag of DeInit Tester
end
methods
%% constructor
function obj = Mt5Api(MTApi5_dll_Location)
if nargin > 1
if isempty(MTApi5_dll_Location)
disp('No Path for API dll using standard');
end
end
obj.MTApi5_dll_Location = strcat(pwd(),'\',MTApi5_dll_Location);
[obj.cLogger, obj.fDeleteLogger] = logging.getLogger('ApiLogMain');
MtApi_asm = NET.addAssembly(obj.MTApi5_dll_Location);
obj.cLogger.debug('Net Assembly loaded',0);
obj.cLogger.debug(char(MtApi_asm.AssemblyHandle.CodeBase),0);
obj.cLogger.debug(char(MtApi_asm.AssemblyHandle.ToString),0);
obj.h = MtApi5.MtApi5Client();
obj.asm = MtApi_asm;
obj.cAccount = cntMt5Api_account(obj);
obj.cCommon = cntMt5Api_common(obj);
obj.cCheckup = cntMt5Api_checkup(obj);
obj.cDateTime = cntMt5Api_datetime(obj);
obj.cEvents = cntMt5Api_events(obj);
obj.cMarketInfo = cntMt5Api_marketinfo(obj);
obj.cTeIndicator = cntMt5Api_teindicator(obj);
obj.cTimeSeries = cntMt5Api_timeseries(obj);
obj.cTimeSeries.mSymbol = 'EURUSD';
obj.cTrade = cntMt5Api_trade(obj);
% obj.cEnum = cntMtApi_enums(obj);
end
%% destructor
function delete(self)
self.asm.delete;
% delete(self.hOnTesterDeInitListener);
end
%% class functions
function ok = startMT5 (self,addr,port)
%% Handle to the .NET client
self.cLogger.info(sprintf('Connecting to %s:%d ...',addr,port));
ok = false;
t = timer('TimerFcn', @errorWhileNoConnection, 'StartDelay',60);
start(t);
status=true;
while (status==true)
try
self.h.BeginConnect(addr,port);
catch ME
end
pause(1);
if self.h.ConnectionState == MtApi5.Mt5ConnectionState.Connected
stop(t);
delete(t);
ok = true;
self.cLogger.info(sprintf('Conneced to %s:%d ',addr,port));
return;
end
end
ok = false;
self.cLogger.error('Connection Timer Out!');
function errorWhileNoConnection(self,event)
status=false;
stop(t);
delete(t);
end
end
function stopMT5(self)
self.cLogger.info('Close Connection...');
self.h.BeginDisconnect();
end
function init_Loggers(self,cmdLineLevel,logLevel,WebHook,Instance)
% cmdLineLevel,logLevel -> ALL,TRACE,DEBUG,INFO,WARNING,ERROR,CRITICAL,OFF
self.cLogger.setSlackWebHook(WebHook);
self.cLogger.setSlackInstance(Instance)
% self.cLogger = logging.getLogger('ApiLog');
self.cLogger.setFilename('C:\Work\NeuronalTrader_matlab\Log\Api.log');
switch logLevel
case 'ALL'
self.cLogger.setLogLevel(logging.logging.ALL);
case 'TRACE'
self.cLogger.setLogLevel(logging.logging.TRACE);
case 'DEBUG'
self.cLogger.setLogLevel(logging.logging.DEBUG);
case 'INFO'
self.cLogger.setLogLevel(logging.logging.INFO);
case 'WARNING'
self.cLogger.setLogLevel(logging.logging.WARNING);
case 'ERROR'
self.cLogger.setLogLevel(logging.logging.ERROR);
case 'CRITICAL'
self.cLogger.setLogLevel(logging.logging.CRITICAL);
case 'OFF'
self.cLogger.setLogLevel(logging.logging.OFF);
otherwise
error('cLogger Init');
end
switch cmdLineLevel
case 'ALL'
self.cLogger.setCommandWindowLevel(logging.logging.ALL);
case 'TRACE'
self.cLogger.setCommandWindowLevel(logging.logging.TRACE);
case 'DEBUG'
self.cLogger.setCommandWindowLevel(logging.logging.DEBUG);
case 'INFO'
self.cLogger.setCommandWindowLevel(logging.logging.INFO);
case 'WARNING'
self.cLogger.setCommandWindowLevel(logging.logging.WARNING);
case 'ERROR'
self.cLogger.setCommandWindowLevel(logging.logging.ERROR);
case 'CRITICAL'
self.cLogger.setCommandWindowLevel(logging.logging.CRITICAL);
case 'OFF'
self.cLogger.setCommandWindowLevel(logging.logging.OFF);
otherwise
error('cLogger Init');
end
self.cLogger.info(' ********* Parameter: LogLevel = ALL **************** ');
self.cLogger.trace('Trace Line Test');
self.cLogger.debug('Debug Line Test');
self.cLogger.info('Info Line Test');
self.cLogger.warn('Warning Line Test');
self.cLogger.error('Error Line Test');
self.cLogger.critical('Critical Line Test');
self.cLogger.info('Api Logger is started');
end
function result = isApiConnected(self)
% Check if Api is Connected
if self.h.ConnectionState == MtApi5.Mt5ConnectionState.Connected
result = true;
else
result = false;
end
end
function result = isMarketOpen(self)
% Check if Market is Open
end
function res = isTesterMode(self)
% Checks if the Expert Advisor runs in the testing mode..
res = self.h.IsTesting();
end
function res = send_TesterStop(self)
% Checks if the Expert Advisor runs in the testing mode..
res = self.cCommon.TimeGMT();
end
function res = GetQuotes(self)
% Load quotes connected into MetaTrader API.
res = self.h.GetQuotes();
end
%% ASM Functions
function version = getVersion(self)
version = char(self.asm.AssemblyHandle.ToString());
self.cLogger.info(version),0;
end
function path = getBasePath(self)
path = char(self.asm.AssemblyHandle.CodeBase);
self.cLogger.info(path),0;
end
%% develop function
function ticks = readTicks(self)
end
function eurusd = runOnX7Live(self)
self.InitLogger;
self.cLogger.info('Develop on X7 live started');
self.setConnectionListener;
self.setOnTradeTransactionListener;
if self.startMT5('192.168.178.15',8228) % Connnect to Live
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
self.setQuoteListener(eurusd);
end
end
function stopX7Live(self)
self.cLogger.trace('Cleanup Listener ,Objects');
self.hConnectionListener.delete;
self.hOnTradeTransactionListener.delete;
self.stopMT5;
while self.isApiConnected()
pause(0.1);
end
logging.clearLogger('ApiLogMain')
end
function [connected ,eurusd] = runOn(self,mode)
self.cLogger.info('Setup Connection');
self.setConnectionListener();
self.setOnTradeTransactionListener();
switch mode
case 'AA'
self.startMT5('192.168.178.15',8301); % Connnect to Pool Tester AA
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'AB'
self.startMT5('192.168.178.15',8302); % Connnect to Pool Tester AB
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'AC'
self.startMT5('192.168.178.15',8303); % Connnect to Pool Tester AC
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
case 'AD'
self.startMT5('192.168.178.15',8304); % Connnect to Pool Tester AD
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
case 'X7T'
self.startMT5('192.168.178.15',8230); % Connnect to Tester
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X7L'
self.startMT5('192.168.178.15',8228); % Connnect to Live
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X3CommandPoolAA'
self.startMT5('127.0.0.1',8231); % Connnect to Pool Tester AA
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X3T'
self.startMT5('192.168.178.25',8231); % Connnect to Tester
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X3L'
self.startMT5('192.168.178.25',8228); % Connnect to Live
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X2T'
self.startMT5('192.168.178.11',8211); % Connnect to Tester
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'X2L'
self.startMT5('192.168.178.11',8228); % Connnect to Live
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
% self.setQuoteListener(eurusd);
case 'default'
self.startMT5('127.0.0.1',8300); % Connnect to default PC
eurusd = DataStore.Ticks();
eurusd.createMqlTicks(int32(100));
self.setQuoteListener(eurusd);
end
if ~self.isApiConnected()
connected = false;
return;
end
connected = true;
end
function stopX7Tester(self)
self.cLogger.trace('Cleanup Listener ,Objects');
self.hConnectionListener.delete;
self.stopMT5;
while self.isApiConnected()
pause(0.1);
end
logging.clearLogger('ApiLogMain')
end
%% Event Listener
function r = setQuoteListener(self,tickHandle)
r = addlistener(self.h, 'QuoteUpdate', @(src,event)self.quoteListener(src,event,tickHandle));
self.hQuoteListener = r;
end
function r = setQuoteAddedListener(self)
r = addlistener(self.h, 'QuoteAdded', @self.quoteAddedListener);
self.hQuoteAddListener = r;
end
function r = setConnectionListener(self)
r = addlistener(self.h, 'ConnectionStateChanged', @(src,event)self.connectionListener(src,event,self.cLogger));
self.hConnectionListener = r;
end
function r = setDeInitListener(self)
r = addlistener(self.h, 'OnTesterDeInit', @(src,event)self.OnDeInitListener(src,event,self.cLogger));
self.hTesterDeInitListener = r;
end
function r = setOnTradeTransactionListener(self)
r = addlistener(self.h, 'OnTradeTransaction', @self.OnTradeTransactionListener);
self.hOnTradeTransactionListener= r;
end
function setupDeInitListener(self)
self.hOnTesterDeInitListener = addlistener(self.h, 'OnTesterDeInit', @(src,event)self.processOnDeInitEvent(src,event));
self.cLogger.trace('DeInit Listener set');
end
function quoteAddedListener(event)
askString = num2str(event.Quote.Ask,'%01.5f');
% askString = sprintf(event.Quote.Ask,'%01.5f');
bidString = num2str(event.Quote.Bid,'%01.5f');
% bidString = num2str(event.Quote.Bid,'%01.5f');
transmitString = strcat(askString,',',bidString);
fprintf('%s: %s\n',char(event.Quote.Instrument),transmitString);
end
function quoteListener(~,~,event,tickHandle)
% askString = num2str(event.Quote.Ask,'%01.5f');
% bidString = num2str(event.Quote.Bid,'%01.5f');
% transmitString = strcat(askString,',',bidString);
% fprintf('%s: %s\n',char(event.Quote.Instrument),transmitString);
if ~feature('IsDebugMode')
tickHandle.storeNewQuoteEvent(event);
end
% tickHandle.bid.push(event.Quote.Bid);
end
function OnTradeTransactionListener(~,~,event)
% askString = num2str(event.Quote.Ask,'%01.5f');
% askString = sprintf(event.Quote.Ask,'%01.5f');
% bidString = num2str(event.Quote.Bid,'%01.5f');
% bidString = num2str(event.Quote.Bid,'%01.5f');
% transmitString = strcat(askString,',',bidString);
% fprintf('%s: %s\n',char(event.Deal),transmitString);
end
function connectionListener(obj,~, event,logger)
connectState = event.Status.ToString();
obj.charConnectionState = connectState.char;
logger.trace('New Connection State:');
logger.info(char(connectState));
switch connectState.char
case 'Connecting'
case 'Connected'
case 'Disconnected'
logger.error('case Disconnected !!!');
case 'Failed'
logger.warn('Connection failed');
logger.warn(sprintf('Reason: %s',char(event.ConnectionMessage)));
end
end
function [ok] = processOnDeInitEvent(self,~,event)
self.cLogger.trace('DeInit Event: Code 0');
% disp(event)
self.bStatusDeInit = true;
ok=true;
end
end
end
@@ -0,0 +1,675 @@
classdef (Sealed) Mt5Enums
% properties
% cMt5Api;
% end
% function obj = cntMtApi_enums(api)
% obj.cMt5Api = api;
% end
% %% Constructor
properties (Constant)
%% ENUM_TIMEFRAMES
% ok
TF_CURRENT = MtApi5.ENUM_TIMEFRAMES.PERIOD_CURRENT;
TF_M1 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
TF_M2 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M2;
TF_M3 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M3;
TF_M4 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M4;
TF_M5 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M5;
TF_M6 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M6;
TF_M10 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M10;
TF_M12 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M12;
TF_M15 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M15;
TF_M20 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M20;
TF_M30 = MtApi5.ENUM_TIMEFRAMES.PERIOD_M30;
TF_H1 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H1;
TF_H2 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H2;
TF_H3 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H3;
TF_H4 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H4;
TF_H6 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H6;
TF_H8 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H8;
TF_H12 = MtApi5.ENUM_TIMEFRAMES.PERIOD_H12;
TF_D1 = MtApi5.ENUM_TIMEFRAMES.PERIOD_D1;
TF_W1 = MtApi5.ENUM_TIMEFRAMES.PERIOD_W1;
TF_MN1 = MtApi5.ENUM_TIMEFRAMES.PERIOD_MN1;
%% ENUM_TERMINAL_INFO_INTEGER
TER_BUILD = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_BUILD;
TER_COMMUNITY_ACCOUNT = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_COMMUNITY_ACCOUNT;
TER_COMMUNITY_CONNECTION = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_COMMUNITY_CONNECTION;
TER_CONNECTED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_CONNECTED;
TER_DLLS_ALLOWED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_DLLS_ALLOWED;
TER_TRADE_ALLOWED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_TRADE_ALLOWED;
TER_EMAIL_ENABLED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_EMAIL_ENABLED;
TER_FTP_ENABLED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_FTP_ENABLED;
TER_NOTIFICATIONS_ENABLED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_NOTIFICATIONS_ENABLED;
TER_MAXBARS = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MAXBARS;
TER_MQID = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MQID;
TER_CODEPAGE = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_CODEPAGE;
TER_CPU_CORES = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_CPU_CORES;
TER_DISK_SPACE = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_DISK_SPACE;
TER_MEMORY_PHYSICAL = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MEMORY_PHYSICAL
TER_MEMORY_TOTAL = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MEMORY_TOTAL
TER_MEMORY_AVAILABLE = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MEMORY_AVAILABLE
TER_MEMORY_USED = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_MEMORY_USED
TER_X64 = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_X64
TER_OPENCL_SUPPORT = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_OPENCL_SUPPORT
TER_SCREEN_DPI = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_SCREEN_DPI
TER_PING_LAST = MtApi5.ENUM_TERMINAL_INFO_INTEGER.TERMINAL_PING_LAST
%% ENUM_TERMINAL_INFO_DOUBLE
TER_COMMUNITY_BALANCE = MtApi5.ENUM_TERMINAL_INFO_DOUBLE.TERMINAL_COMMUNITY_BALANCE;
%% ENUM_TERMINAL_INFO_STRING
TER_LANGUAGE = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_LANGUAGE;
TER_COMPANY = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_COMPANY;
TER_NAME = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_NAME;
TER_PATH = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_PATH;
TER_DATA_PATH = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_DATA_PATH;
TER_COMMONDATA_PATH = MtApi5.ENUM_TERMINAL_INFO_STRING.TERMINAL_COMMONDATA_PATH;
%% ENUM_SYMBOL_INFO_INTEGER
SYMBOL_CUSTOM = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_CUSTOM;
SYMBOL_BACKGROUND_COLOR = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_BACKGROUND_COLOR;
SYMBOL_CHART_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_CHART_MODE;
SYMBOL_SELECT = 0,
% FIXME: SYMBOL_VISIBLE not found in MQL5 environment!
% SYMBOL_VISIBLE = ?
SYMBOL_SESSION_DEALS = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SESSION_DEALS;
SYMBOL_SESSION_BUY_ORDERS = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SESSION_BUY_ORDERS;
SYMBOL_SESSION_SELL_ORDERS = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SESSION_SELL_ORDERS;
SYMBOL_VOLUME = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_VOLUME;
SYMBOL_VOLUMEHIGH = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_VOLUMEHIGH;
SYMBOL_VOLUMELOW = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_VOLUMELOW;
SYMBOL_TIME = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TIME;
SYMBOL_DIGITS = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_DIGITS;
SYMBOL_SPREAD_FLOAT = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SPREAD_FLOAT;
SYMBOL_SPREAD = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SPREAD;
SYMBOL_TICKS_BOOKDEPTH = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TICKS_BOOKDEPTH;
SYMBOL_TRADE_CALC_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TRADE_CALC_MODE;
SYMBOL_TRADE_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TRADE_MODE;
SYMBOL_START_TIME = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_START_TIME;
SYMBOL_EXPIRATION_TIME = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_EXPIRATION_TIME;
SYMBOL_TRADE_STOPS_LEVEL = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TRADE_STOPS_LEVEL;
SYMBOL_TRADE_FREEZE_LEVEL = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TRADE_FREEZE_LEVEL;
SYMBOL_TRADE_EXEMODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_TRADE_EXEMODE;
SYMBOL_SWAP_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SWAP_MODE;
SYMBOL_SWAP_ROLLOVER3DAYS = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SWAP_ROLLOVER3DAYS
SYMBOL_MARGIN_HEDGED_USE_LEG = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_MARGIN_HEDGED_USE_LEG;
SYMBOL_EXPIRATION_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_EXPIRATION_MODE;
SYMBOL_FILLING_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_FILLING_MODE;
SYMBOL_ORDER_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_ORDER_MODE;
SYMBOL_ORDER_GTC_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_ORDER_GTC_MODE;
SYMBOL_ORDER_CLOSEBY = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_ORDER_CLOSEBY;
SYMBOL_OPTION_MODE = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_OPTION_MODE;
SYMBOL_OPTION_RIGHT = MtApi5.ENUM_SYMBOL_INFO_INTEGER.SYMBOL_OPTION_RIGHT;
%% ENUM_SYMBOL_INFO_DOUBLE
SYM_BID = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BID
SYM_BIDHIGH = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BIDHIGH
SYM_BIDLOW = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BIDLOW
SYM_ASK = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_ASK
SYM_ASKHIGH = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_ASKHIGH
SYM_ASKLOW = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_ASKLOW
SYM_LAST = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_LAST
SYM_LASTHIGH = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_LASTHIGH
SYM_LASTLOW = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_LASTLOW
SYM_OPTION_STRIKE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_OPTION_STRIKE
SYM_POINT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_POINT
SYM_TRADE_TICK_VALUE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_TICK_VALUE
SYM_TRADE_TICK_VALUE_PROFIT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_TICK_VALUE_PROFIT
SYM_TRADE_TICK_VALUE_LOSS = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_TICK_VALUE_LOSS
SYM_TRADE_TICK_SIZE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_TICK_SIZE
SYM_TRADE_CONTRACT_SIZE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_CONTRACT_SIZE
SYM_TRADE_ACCRUED_INTEREST = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_ACCRUED_INTEREST
SYM_TRADE_FACE_VALUE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_FACE_VALUE
SYM_TRADE_LIQUIDITY_RATE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_LIQUIDITY_RATE
SYM_VOLUME_MIN = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_MIN
SYM_VOLUME_MAX = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_MAX
SYM_VOLUME_STEP = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_STEP
SYM_VOLUME_LIMIT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_VOLUME_LIMIT
SYM_SWAP_LONG = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SWAP_LONG
SYM_SWAP_SHORT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SWAP_SHORT
SYM_MARGIN_INITIAL = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_INITIAL
SYM_MARGIN_MAINTENANCE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_MAINTENANCE
SYM_MARGIN_LONG = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_LONG % FIXME: Undocumented!
SYM_MARGIN_SHORT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_SHORT % FIXME: Undocumented!
SYM_MARGIN_LIMIT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_LIMIT % FIXME: Undocumented!
SYM_MARGIN_STOP = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_STOP % FIXME: Undocumented!
SYM_MARGIN_STOPLIMIT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_STOPLIMIT % FIXME: Undocumented!
SYM_SESSION_VOLUME = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_VOLUME
SYM_SESSION_TURNOVER = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_TURNOVER
SYM_SESSION_INTEREST = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_INTEREST
SYM_SESSION_BUY_ORDERS_VOLUME = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_BUY_ORDERS_VOLUME
SYM_SESSION_SELL_ORDERS_VOLUME = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_SELL_ORDERS_VOLUME
SYM_SESSION_OPEN = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_OPEN
SYM_SESSION_CLOSE = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_CLOSE
SYM_SESSION_AW = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_AW
SYM_SESSION_PRICE_SETTLEMENT = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_PRICE_SETTLEMENT
SYM_SESSION_PRICE_LIMIT_MIN = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_PRICE_LIMIT_MIN
SYM_SESSION_PRICE_LIMIT_MAX = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_SESSION_PRICE_LIMIT_MAX
SYM_MARGIN_HEDGED = MtApi5.ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_MARGIN_HEDGED
%% ENUM_SYMBOL_INFO_STRING
SYM_BASIS = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_BASIS
SYM_CURRENCY_BASE = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_CURRENCY_BASE
SYM_CURRENCY_PROFIT = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_CURRENCY_PROFIT
SYM_CURRENCY_MARGIN = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_CURRENCY_MARGIN
SYM_BANK = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_BANK
SYM_DESCRIPTION = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_DESCRIPTION
SYM_FORMULA = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_FORMULA
SYM_PAGE = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_PAGE
SYM_ISIN = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_ISIN
SYM_PATH = MtApi5.ENUM_SYMBOL_INFO_STRING.SYMBOL_PATH
%% ENUM_SYMBOL_CHART_MODE
SYM_CHART_MODE_BID = MtApi5.ENUM_SYMBOL_CHART_MODE.SYMBOL_CHART_MODE_BID
SYM_CHART_MODE_LAST = MtApi5.ENUM_SYMBOL_CHART_MODE.SYMBOL_CHART_MODE_LAST
%% ENUM_SYMBOL_ORDER_GTC_MODE
SYM_ORDERS_GTC = MtApi5.ENUM_SYMBOL_ORDER_GTC_MODE.SYMBOL_ORDERS_GTC
SYM_ORDERS_DAILY = MtApi5.ENUM_SYMBOL_ORDER_GTC_MODE.SYMBOL_ORDERS_DAILY
SYM_ORDERS_DAILY_EXCLUDING_STOPS = MtApi5.ENUM_SYMBOL_ORDER_GTC_MODE.SYMBOL_ORDERS_DAILY_EXCLUDING_STOPS
%% ENUM_SYMBOL_OPTION_RIGHT
SYM_OPTION_RIGHT_CALL = MtApi5.ENUM_SYMBOL_OPTION_RIGHT.SYMBOL_OPTION_RIGHT_CALL
SYM_OPTION_RIGHT_PUT = MtApi5.ENUM_SYMBOL_OPTION_RIGHT.SYMBOL_OPTION_RIGHT_PUT
%% ENUM_SYMBOL_OPTION_MODE
SYM_OPTION_MODE_EUROPEAN = MtApi5.ENUM_SYMBOL_OPTION_MODE.SYMBOL_OPTION_MODE_EUROPEAN
SYM_OPTION_MODE_AMERICAN = MtApi5.ENUM_SYMBOL_OPTION_MODE.SYMBOL_OPTION_MODE_AMERICAN
%% ENUM_SYMBOL_CALC_MODE
SYM_CALC_MODE_FOREX = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_FOREX
SYM_CALC_MODE_FUTURES = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_FUTURES
SYM_CALC_MODE_CFD = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_CFD
SYM_CALC_MODE_CFDINDEX = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_CFDINDEX
SYM_CALC_MODE_CFDLEVERAGE = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_CFDLEVERAGE
SYM_CALC_MODE_EXCH_STOCKS = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_EXCH_STOCKS
SYM_CALC_MODE_EXCH_FUTURES = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_EXCH_FUTURES
SYM_CALC_MODE_EXCH_FUTURES_FORTS = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS
SYM_CALC_MODE_SERV_COLLATERAL = MtApi5.ENUM_SYMBOL_CALC_MODE.SYMBOL_CALC_MODE_SERV_COLLATERAL
%% ENUM_SYMBOL_TRADE_MODE
SYM_TRADE_MODE_DISABLED = MtApi5.ENUM_SYMBOL_TRADE_MODE.SYMBOL_TRADE_MODE_DISABLED
SYM_TRADE_MODE_LONGONLY = MtApi5.ENUM_SYMBOL_TRADE_MODE.SYMBOL_TRADE_MODE_LONGONLY
SYM_TRADE_MODE_SHORTONLY = MtApi5.ENUM_SYMBOL_TRADE_MODE.SYMBOL_TRADE_MODE_SHORTONLY
SYM_TRADE_MODE_CLOSEONLY = MtApi5.ENUM_SYMBOL_TRADE_MODE.SYMBOL_TRADE_MODE_CLOSEONLY
SYM_TRADE_MODE_FULL = MtApi5.ENUM_SYMBOL_TRADE_MODE.SYMBOL_TRADE_MODE_FULL
%% ENUM_SYMBOL_TRADE_EXECUTION
SYM_TRADE_EXECUTION_REQUEST = MtApi5.ENUM_SYMBOL_TRADE_EXECUTION.SYMBOL_TRADE_EXECUTION_REQUEST
SYM_TRADE_EXECUTION_INSTANT = MtApi5.ENUM_SYMBOL_TRADE_EXECUTION.SYMBOL_TRADE_EXECUTION_INSTANT
SYM_TRADE_EXECUTION_MARKET = MtApi5.ENUM_SYMBOL_TRADE_EXECUTION.SYMBOL_TRADE_EXECUTION_MARKET
SYM_TRADE_EXECUTION_EXCHANGE = MtApi5.ENUM_SYMBOL_TRADE_EXECUTION.SYMBOL_TRADE_EXECUTION_EXCHANGE
%% ENUM_SYMBOL_SWAP_MODE
SYM_SWAP_MODE_DISABLED = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_DISABLED
SYM_SWAP_MODE_POINTS = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_POINTS
SYM_SWAP_MODE_CURRENCY_SYMBOL = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_CURRENCY_SYMBOL
SYM_SWAP_MODE_CURRENCY_MARGIN = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_CURRENCY_MARGIN
SYM_SWAP_MODE_CURRENCY_DEPOSIT = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT
SYM_SWAP_MODE_INTEREST_CURRENT = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_INTEREST_CURRENT
SYM_SWAP_MODE_INTEREST_OPEN = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_INTEREST_OPEN
SYM_SWAP_MODE_REOPEN_CURRENT = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_REOPEN_CURRENT
SYM_SWAP_MODE_REOPEN_BID = MtApi5.ENUM_SYMBOL_SWAP_MODE.SYMBOL_SWAP_MODE_REOPEN_BID
%% ENUM_DAY_OF_WEEK
DAY_SUNDAY = MtApi5.ENUM_DAY_OF_WEEK.SUNDAY
DAY_MONDAY = MtApi5.ENUM_DAY_OF_WEEK.MONDAY
DAY_TUESDAY = MtApi5.ENUM_DAY_OF_WEEK.TUESDAY
DAY_WEDNESDAY = MtApi5.ENUM_DAY_OF_WEEK.WEDNESDAY
DAY_THURSDAY = MtApi5.ENUM_DAY_OF_WEEK.THURSDAY
DAY_FRIDAY = MtApi5.ENUM_DAY_OF_WEEK.FRIDAY
DAY_SATURDAY = MtApi5.ENUM_DAY_OF_WEEK.SATURDAY
%% ENUM_ACCOUNT_INFO_INTEGER
ACC_LOGIN = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_LOGIN % Account number
ACC_TRADE_MODE = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_TRADE_MODE % Account trade mode
ACC_LEVERAGE = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_LEVERAGE % Account leverage
ACC_LIMIT_ORDERS = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_LIMIT_ORDERS % Maximum allowed number of active pending orders
ACC_MARGIN_SO_MODE = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_MARGIN_SO_MODE % Mode for setting the minimal allowed margin
ACC_TRADE_ALLOWED = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_TRADE_ALLOWED % Allowed trade for the current account
ACC_TRADE_EXPERT = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_TRADE_EXPERT % Allowed trade for an Expert Advisor
ACC_MARGIN_MODE = MtApi5.ENUM_ACCOUNT_INFO_INTEGER.ACCOUNT_MARGIN_MODE % Margin calculation mode
%% ENUM_ACCOUNT_INFO_DOUBLE
ACC_BALANCE = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_BALANCE % Account balance in the deposit currency
ACC_CREDIT = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_CREDIT % Account credit in the deposit currency
ACC_PROFIT = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_PROFIT % Current profit of an account in the deposit currency
ACC_EQUITY = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_EQUITY % Account equity in the deposit currency
ACC_MARGIN = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN % Account margin used in the deposit currency
ACC_MARGIN_FREE = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_FREE % Free margin of an account in the deposit currency
ACC_MARGIN_LEVEL = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_LEVEL % Account margin level in percents
ACC_MARGIN_SO_CALL = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_SO_CALL % Margin call level
ACC_MARGIN_SO_SO = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_SO_SO % Margin stop out level
ACC_MARGIN_INITIAL = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_INITIAL % Initial margin
ACC_MARGIN_MAINTENANCE = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_MARGIN_MAINTENANCE % Maintenance margin
ACC_ASSETS = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_ASSETS % The current assets of an account
ACC_LIABILITIES = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_LIABILITIES % The current liabilities on an account
ACC_COMMISSION_BLOCKED = MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_COMMISSION_BLOCKED % The current blocked commission amount on an account
%% ENUM_ACCOUNT_INFO_STRING
ACC_NAME = MtApi5.ENUM_ACCOUNT_INFO_STRING.ACCOUNT_NAME % Client name
ACC_SERVER = MtApi5.ENUM_ACCOUNT_INFO_STRING.ACCOUNT_SERVER % Trade server name
ACC_CURRENCY = MtApi5.ENUM_ACCOUNT_INFO_STRING.ACCOUNT_CURRENCY % Account currency
ACC_COMPANY = MtApi5.ENUM_ACCOUNT_INFO_STRING.ACCOUNT_COMPANY % Name of a company that serves the account
%% ENUM_ACCOUNT_TRADE_MODE
ACC_TRADE_MODE_DEMO = MtApi5.ENUM_ACCOUNT_TRADE_MODE.ACCOUNT_TRADE_MODE_DEMO % Demo account
ACC_TRADE_MODE_CONTEST = MtApi5.ENUM_ACCOUNT_TRADE_MODE.ACCOUNT_TRADE_MODE_CONTEST % Contest account
ACC_TRADE_MODE_REAL = MtApi5.ENUM_ACCOUNT_TRADE_MODE.ACCOUNT_TRADE_MODE_REAL % Real account
%% ENUM_ACCOUNT_STOPOUT_MODE
ACC_STOPOUT_MODE_PERCENT = MtApi5.ENUM_ACCOUNT_STOPOUT_MODE.ACCOUNT_STOPOUT_MODE_PERCENT % Account stop out mode in percents
ACC_STOPOUT_MODE_MONEY = MtApi5.ENUM_ACCOUNT_STOPOUT_MODE.ACCOUNT_STOPOUT_MODE_MONEY % Account stop out mode in money
%% ENUM_ACCOUNT_MARGIN_MODE
ACC_MARGIN_MODE_RETAIL_NETTING = MtApi5.ENUM_ACCOUNT_MARGIN_MODE.ACCOUNT_MARGIN_MODE_RETAIL_NETTING % Used for the OTC markets to interpret positions in the "netting" mode
ACC_MARGIN_MODE_EXCHANGE = MtApi5.ENUM_ACCOUNT_MARGIN_MODE.ACCOUNT_MARGIN_MODE_EXCHANGE % Used for the exchange markets
ACC_MARGIN_MODE_RETAIL_HEDGING = MtApi5.ENUM_ACCOUNT_MARGIN_MODE.ACCOUNT_MARGIN_MODE_RETAIL_HEDGING % Used for the exchange markets where individual positions are possible
%% ENUM_SERIES_INFO_INTEGER
SER_BARS_COUNT = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_BARS_COUNT % Bars count for the symbol-period for the current moment
SER_FIRSTDATE = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_FIRSTDATE % The very first date for the symbol-period for the current moment
SER_LASTBAR_DATE = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_LASTBAR_DATE % Open time of the last bar of the symbol-period
SER_SERVER_FIRSTDATE = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_SERVER_FIRSTDATE % The very first date in the history of the symbol on the server regardless of the timeframe
SER_TERMINAL_FIRSTDATE = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_TERMINAL_FIRSTDATE % The very first date in the history of the symbol in the client terminal, regardless of the timeframe
SER_SYNCHRONIZED = MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_SYNCHRONIZED % Symbol/period data synchronization flag for the current moment
%% ENUM_ORDER_PROPERTY_INTEGER
order_TICKET = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TICKET % Order ticket. Unique number assigned to each order
order_TIME_SETUP = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TIME_SETUP % Order setup time
order_TYPE = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TYPE % Order type
order_STATE = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_STATE % Order state
order_TIME_EXPIRATION = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TIME_EXPIRATION % Order expiration time
order_TIME_DONE = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TIME_DONE % Order execution or cancellation time
order_TIME_SETUP_MSC = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TIME_SETUP_MSC % The time of placing an order for execution in milliseconds since 01.01.1970
order_TIME_DONE_MSC = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TIME_DONE_MSC % Order execution/cancellation time in milliseconds since 01.01.1970
order_TYPE_FILLING = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TYPE_FILLING % Order filling type
order_TYPE_TIME = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_TYPE_TIME % Order lifetime
order_MAGIC = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_MAGIC % ID of an Expert Advisor that has placed the order (designed to ensure that each Expert Advisor places its own unique number)
order_REASON = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_REASON % The reason or source for placing an order
order_POSITION_ID = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_POSITION_ID % Position identifier that is set to an order as soon as it is executed. Each executed order results in a deal that opens or modifies an already existing position. The identifier of exactly this position is set to the executed order at this moment.
order_POSITION_BY_ID = MtApi5.ENUM_ORDER_PROPERTY_INTEGER.ORDER_POSITION_BY_ID % Identifier of an opposite position used for closing by order order_TYPE_CLOSE_BY
%% ENUM_ORDER_PROPERTY_DOUBLE
order_VOLUME_INITIAL = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_VOLUME_INITIAL % Order initial volume
order_VOLUME_CURRENT = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_VOLUME_CURRENT % Order current volume
order_PRICE_OPEN = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_PRICE_OPEN % Price specified in the order
order_SL = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_SL % Stop Loss value
order_TP = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_TP % Take Profit value
order_PRICE_CURRENT = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_PRICE_CURRENT % The current price of the order symbol
order_PRICE_STOPLIMIT = MtApi5.ENUM_ORDER_PROPERTY_DOUBLE.ORDER_PRICE_STOPLIMIT % The Limit order price for the StopLimit order
%% ENUM_ORDER_PROPERTY_STRING
order_SYMBOL = MtApi5.ENUM_ORDER_PROPERTY_STRING.ORDER_SYMBOL % Symbol of the order
order_COMMENT = MtApi5.ENUM_ORDER_PROPERTY_STRING.ORDER_COMMENT % Order comment
order_EXTERNAL_ID = MtApi5.ENUM_ORDER_PROPERTY_STRING.ORDER_EXTERNAL_ID % Order identifier in an external trading system (on the Exchange)
%% ENUM_ORDER_TYPE
order_TYPE_BUY = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_BUY % Market Buy order
order_TYPE_SELL = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_SELL % Market Sell order
order_TYPE_BUY_LIMIT = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_BUY_LIMIT % Buy Limit pending order
order_TYPE_SELL_LIMIT = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_SELL_LIMIT % Sell Limit pending order
order_TYPE_BUY_STOP = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_BUY_STOP % Buy Stop pending order
order_TYPE_SELL_STOP = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_SELL_STOP % Sell Stop pending order
order_TYPE_BUY_STOP_LIMIT = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_BUY_STOP_LIMIT % Upon reaching the order price, a pending Buy Limit order is places at the StopLimit price
order_TYPE_SELL_STOP_LIMIT = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_SELL_STOP_LIMIT % Upon reaching the order price, a pending Sell Limit order is places at the StopLimit price
order_TYPE_CLOSE_BY = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_CLOSE_BY % Order to close a position by an opposite one
%% ENUM_ORDER_STATE
order_STATE_STARTED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_STARTED % Order checked, but not yet accepted by broker
order_STATE_PLACED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_PLACED % Order accepted
order_STATE_CANCELED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_CANCELED % Order canceled by client
order_STATE_PARTIAL = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_PARTIAL % Order partially executed
order_STATE_FILLED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_FILLED % Order fully executed
order_STATE_REJECTED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_REJECTED % Order rejected
order_STATE_EXPIRED = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_EXPIRED % Order expired
order_STATE_REQUEST_ADD = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_REQUEST_ADD % Order is being registered (placing to the trading system)
order_STATE_REQUEST_MODIFY = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_REQUEST_MODIFY % Order is being modified (changing its parameters)
order_STATE_REQUEST_CANCEL = MtApi5.ENUM_ORDER_STATE.ORDER_STATE_REQUEST_CANCEL % Order is being deleted (deleting from the trading system)
%% ENUM_ORDER_TYPE_FILLING
order_FILLING_FOK = MtApi5.ENUM_ORDER_TYPE_FILLING.ORDER_FILLING_FOK
order_FILLING_IOC = MtApi5.ENUM_ORDER_TYPE_FILLING.ORDER_FILLING_IOC
order_FILLING_RETURN = MtApi5.ENUM_ORDER_TYPE_FILLING.ORDER_FILLING_RETURN
%% ENUM_ORDER_TYPE_TIME
order_TIME_GTC = MtApi5.ENUM_ORDER_TYPE_TIME.ORDER_TIME_GTC
order_TIME_DAY = MtApi5.ENUM_ORDER_TYPE_TIME.ORDER_TIME_DAY
order_TIME_SPECIFIED = MtApi5.ENUM_ORDER_TYPE_TIME.ORDER_TIME_SPECIFIED
order_TIME_SPECIFIED_DAY = MtApi5.ENUM_ORDER_TYPE_TIME.ORDER_TIME_SPECIFIED_DAY
%% ENUM_ORDER_REASON
order_REASON_CLIENT = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_CLIENT % The order was placed from a desktop terminal
order_REASON_MOBILE = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_MOBILE % The order was placed from a mobile application
order_REASON_WEB = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_WEB % The order was placed from a web platform
order_REASON_EXPERT = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_EXPERT % The order was placed from an MQL5-program, i.e. by an Expert Advisor or a script
order_REASON_SL = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_SL % The order was placed as a result of Stop Loss activation
order_REASON_TP = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_TP % The order was placed as a result of Take Profit activation
order_REASON_SO = MtApi5.ENUM_ORDER_REASON.ORDER_REASON_SO % The order was placed as a result of the Stop Out event
%% ENUM_POSITION_PROPERTY_INTEGER
POSITION_TICKET = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TICKET % Position ticket
POSITION_TIME = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TIME % Position open time
POSITION_TIME_MSC = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TIME_MSC % Position opening time in milliseconds since 01.01.1970
POSITION_TIME_UPDATE = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TIME_UPDATE % Position changing time in seconds since 01.01.1970
POSITION_TIME_UPDATE_MSC = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TIME_UPDATE_MSC % Position changing time in milliseconds since 01.01.1970
POSITION_TYPE = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_TYPE % Position type
POSITION_MAGIC = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_MAGIC % Position magic number
POSITION_IDENTIFIER = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_IDENTIFIER % Position identifier is a unique number that is assigned to every newly opened position and doesn't change during the entire lifetime of the position. Position turnover doesn't change its identifier.
POSITION_REASON = MtApi5.ENUM_POSITION_PROPERTY_INTEGER.POSITION_REASON % The reason for opening a position
%% ENUM_POSITION_PROPERTY_DOUBLE
POSITION_VOLUME = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_VOLUME % Position volume
POSITION_PRICE_OPEN = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_PRICE_OPEN % Position open price
POSITION_SL = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_SL % Stop Loss level of opened position
POSITION_TP = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_TP % Take Profit level of opened position
POSITION_PRICE_CURRENT = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_PRICE_CURRENT % Current price of the position symbol
POSITION_COMMISSION = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_COMMISSION % FIXME: Undocumented!
POSITION_SWAP = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_SWAP % Cumulative swap
POSITION_PROFIT = MtApi5.ENUM_POSITION_PROPERTY_DOUBLE.POSITION_PROFIT % Current profit
%% ENUM_POSITION_PROPERTY_STRING
POSITION_SYMBOL = MtApi5.ENUM_POSITION_PROPERTY_STRING.POSITION_SYMBOL % Symbol of the position
POSITION_COMMENT = MtApi5.ENUM_POSITION_PROPERTY_STRING.POSITION_COMMENT % Position comment
%% ENUM_POSITION_TYPE
POSITION_TYPE_BUY = MtApi5.ENUM_POSITION_TYPE.POSITION_TYPE_BUY % Buy
POSITION_TYPE_SELL = MtApi5.ENUM_POSITION_TYPE.POSITION_TYPE_SELL % Sell
%% ENUM_POSITION_REASON
POSITION_REASON_CLIENT = MtApi5.ENUM_POSITION_REASON.POSITION_REASON_CLIENT % The position was opened as a result of activation of an order placed from a desktop terminal
POSITION_REASON_MOBILE = MtApi5.ENUM_POSITION_REASON.POSITION_REASON_MOBILE % The position was opened as a result of activation of an order placed from a mobile application
POSITION_REASON_WEB = MtApi5.ENUM_POSITION_REASON.POSITION_REASON_WEB % The position was opened as a result of activation of an order placed from the web platform
POSITION_REASON_EXPERT = MtApi5.ENUM_POSITION_REASON.POSITION_REASON_EXPERT % The position was opened as a result of activation of an order placed from an MQL5 program
%% ENUM_DEAL_PROPERTY_INTEGER
DEAL_TICKET = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_TICKET % Deal ticket. Unique number assigned to each deal
DEAL_ORDER = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_ORDER % Deal order number
DEAL_TIME = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_TIME % Deal time
DEAL_TIME_MSC = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_TIME_MSC % The time of a deal execution in milliseconds since 01.01.1970
DEAL_TYPE = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_TYPE % Deal type
DEAL_ENTRY = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_ENTRY % Deal entry - entry in, entry out, reverse
DEAL_MAGIC = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_MAGIC % Deal magic number
DEAL_REASON = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_REASON % The reason or source for deal execution
DEAL_POSITION_ID = MtApi5.ENUM_DEAL_PROPERTY_INTEGER.DEAL_POSITION_ID % Identifier of a position
%% ENUM_DEAL_PROPERTY_DOUBLE
DEAL_VOLUME = MtApi5.ENUM_DEAL_PROPERTY_DOUBLE.DEAL_VOLUME % Deal volume
DEAL_PRICE = MtApi5.ENUM_DEAL_PROPERTY_DOUBLE.DEAL_PRICE % Deal price
DEAL_COMMISSION = MtApi5.ENUM_DEAL_PROPERTY_DOUBLE.DEAL_COMMISSION % Deal commission
DEAL_SWAP = MtApi5.ENUM_DEAL_PROPERTY_DOUBLE.DEAL_SWAP % Cumulative swap on close
DEAL_PROFIT = MtApi5.ENUM_DEAL_PROPERTY_DOUBLE.DEAL_PROFIT % Deal profit
%% ENUM_DEAL_PROPERTY_STRING
DEAL_SYMBOL = MtApi5.ENUM_DEAL_PROPERTY_STRING.DEAL_SYMBOL % Deal symbol
DEAL_COMMENT = MtApi5.ENUM_DEAL_PROPERTY_STRING.DEAL_COMMENT % Deal comment
DEAL_EXTERNAL_ID = MtApi5.ENUM_DEAL_PROPERTY_STRING.DEAL_EXTERNAL_ID % Deal identifier in an external trading system (on the Exchange)
%% ENUM_DEAL_TYPE
DEAL_TYPE_BUY = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_BUY % Buy
DEAL_TYPE_SELL = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_SELL % Sell
DEAL_TYPE_BALANCE = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_BALANCE % Balance
DEAL_TYPE_CREDIT = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_CREDIT % Credit
DEAL_TYPE_CHARGE = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_CHARGE % Additional charge
DEAL_TYPE_CORRECTION = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_CORRECTION % Correction
DEAL_TYPE_BONUS = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_BONUS % Bonus
DEAL_TYPE_COMMISSION = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_COMMISSION % Additional commission
DEAL_TYPE_COMMISSION_DAILY = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_COMMISSION_DAILY % Daily commission
DEAL_TYPE_COMMISSION_MONTHLY = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_COMMISSION_MONTHLY % Monthly commission
DEAL_TYPE_COMMISSION_AGENT_DAILY = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_COMMISSION_AGENT_DAILY % Daily agent commission
DEAL_TYPE_COMMISSION_AGENT_MONTHLY = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_COMMISSION_AGENT_MONTHLY % Monthly agent commission
DEAL_TYPE_INTEREST = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_INTEREST % Interest rate
DEAL_TYPE_BUY_CANCELED = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_BUY_CANCELED % Canceled buy deal
DEAL_TYPE_SELL_CANCELED = MtApi5.ENUM_DEAL_TYPE.DEAL_TYPE_SELL_CANCELED % Canceled sell deal
DEAL_DIVIDEND = MtApi5.ENUM_DEAL_TYPE.DEAL_DIVIDEND % Dividend operations
DEAL_DIVIDEND_FRANKED = MtApi5.ENUM_DEAL_TYPE.DEAL_DIVIDEND_FRANKED % Franked (non-taxable) dividend operations
DEAL_TAX = MtApi5.ENUM_DEAL_TYPE.DEAL_TAX % Tax charges
%% ENUM_DEAL_ENTRY
DEAL_ENTRY_IN = MtApi5.ENUM_DEAL_ENTRY.DEAL_ENTRY_IN % Entry in
DEAL_ENTRY_OUT = MtApi5.ENUM_DEAL_ENTRY.DEAL_ENTRY_OUT % Entry out
DEAL_ENTRY_INOUT = MtApi5.ENUM_DEAL_ENTRY.DEAL_ENTRY_INOUT % Reverse
DEAL_ENTRY_STATE = MtApi5.ENUM_DEAL_ENTRY.DEAL_ENTRY_STATE % Close a position by an opposite one
%% ENUM_DEAL_REASON
DEAL_REASON_CLIENT = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_CLIENT % The deal was executed as a result of activation of an order placed from a desktop terminal
DEAL_REASON_MOBILE = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_MOBILE % The deal was executed as a result of activation of an order placed from a mobile application
DEAL_REASON_WEB = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_WEB % The deal was executed as a result of activation of an order placed from the web platform
DEAL_REASON_EXPERT = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_EXPERT % The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script
DEAL_REASON_SL = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_SL % The deal was executed as a result of Stop Loss activation
DEAL_REASON_TP = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_TP % The deal was executed as a result of Take Profit activation
DEAL_REASON_SO = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_SO % The deal was executed as a result of the Stop Out event
DEAL_REASON_ROLLOVER = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_ROLLOVER % The deal was executed due to a rollover
DEAL_REASON_VMARGIN = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_VMARGIN % The deal was executed after charging the variation margin
DEAL_REASON_SPLIT = MtApi5.ENUM_DEAL_REASON.DEAL_REASON_SPLIT % The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement
%% ENUM_TRADE_REQUEST_ACTIONS
TRADE_ACTION_DEAL = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_DEAL % Place a trade order for an immediate execution with the specified parameters (market order)
TRADE_ACTION_PENDING = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_PENDING % Place a trade order for the execution under specified conditions (pending order)
TRADE_ACTION_SLTP = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_SLTP % Modify Stop Loss and Take Profit values of an opened position
TRADE_ACTION_MODIFY = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_MODIFY % Modify the parameters of the order placed previously
TRADE_ACTION_REMOVE = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_REMOVE % Delete the pending order placed previously
TRADE_ACTION_CLOSE_BY = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_CLOSE_BY % Close a position by an opposite one
%% ENUM_TRADE_TRANSACTION_TYPE
TRANSACTION_ORDER_ADD = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_ORDER_ADD % Adding a new open order
TRANSACTION_ORDER_UPDATE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_ORDER_UPDATE % Updating an open order. The updates include not only evident changes from the client terminal or a trade server sides but also changes of an order state when setting it (for example, transition from ORDER_STATE_STARTED to ORDER_STATE_PLACED or from ORDER_STATE_PLACED to ORDER_STATE_PARTIAL, etc.).
TRANSACTION_ORDER_DELETE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_ORDER_DELETE % Removing an order from the list of the open ones. An order can be deleted from the open ones as a result of setting an appropriate request or execution (filling) and moving to the history.
TRANSACTION_DEAL_ADD = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_DEAL_ADD % Adding a deal to the history. The action is performed as a result of an order execution or performing operations with an account balance.
TRANSACTION_DEAL_UPDATE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_DEAL_UPDATE % Updating a deal in the history. There may be cases when a previously executed deal is changed on a server. For example, a deal has been changed in an external trading system (exchange) where it was previously transferred by a broker.
TRANSACTION_DEAL_DELETE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_DEAL_DELETE % Deleting a deal from the history. There may be cases when a previously executed deal is deleted from a server. For example, a deal has been deleted in an external trading system (exchange) where it was previously transferred by a broker.
TRANSACTION_HISTORY_ADD = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_HISTORY_ADD % Adding an order to the history as a result of execution or cancellation.
TRANSACTION_HISTORY_UPDATE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_HISTORY_UPDATE % Changing an order located in the orders history. This type is provided for enhancing functionality on a trade server side.
TRANSACTION_HISTORY_DELETE = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_HISTORY_DELETE % Deleting an order from the orders history. This type is provided for enhancing functionality on a trade server side.
TRANSACTION_POSITION = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_POSITION % Changing a position not related to a deal execution. This type of transaction shows that a position has been changed on a trade server side. Position volume, open price, Stop Loss and Take Profit levels can be changed. Data on changes are submitted in MqlTradeTransaction structure via OnTradeTransaction handler. Position change (adding, changing or closing), as a result of a deal execution, does not lead to the occurrence of TRADE_TRANSACTION_POSITION transaction.
TRANSACTION_REQUEST = MtApi5.ENUM_TRADE_TRANSACTION_TYPE.TRADE_TRANSACTION_REQUEST % Notification of the fact that a trade request has been processed by a server and processing result has been received. Only type field (trade transaction type) must be analyzed for such transactions in MqlTradeTransaction structure. The second and third parameters of OnTradeTransaction (request and result) must be analyzed for additional data.
%% ENUM_BOOK_TYPE
BOOK_TYPE_SELL = MtApi5.ENUM_BOOK_TYPE.BOOK_TYPE_SELL % Sell order (Offer)
BOOK_TYPE_BUY = MtApi5.ENUM_BOOK_TYPE.BOOK_TYPE_BUY % Buy order (Bid)
BOOK_TYPE_SELL_MARKET = MtApi5.ENUM_BOOK_TYPE.BOOK_TYPE_SELL_MARKET % Sell order by Market
BOOK_TYPE_BUY_MARKET = MtApi5.ENUM_BOOK_TYPE.BOOK_TYPE_BUY_MARKET % Buy order by Market
%% ENUM_OBJECT
OBJ_VLINE = 0, % Vertical Line
OBJ_HLINE = 1, % Horizontal Line
OBJ_TREND = 2, % Trend Line
OBJ_TRENDBYANGLE = 3, % Trend Line By Angle
OBJ_CYCLES = 4, % Cycle Lines
OBJ_ARROWED_LINE = 108, % Arrowed Line
OBJ_CHANNEL = 5, % Equidistant Channel
OBJ_STDDEVCHANNEL = 6, % Standard Deviation Channel
OBJ_REGRESSION = 7, % Linear Regression Channel
OBJ_PITCHFORK = 8, % Andrews? Pitchfork
OBJ_GANNLINE = 9, % Gann Line
OBJ_GANNFAN = 10, % Gann Fan
OBJ_GANNGRID = 11, % Gann Grid
OBJ_FIBO = 12, % Fibonacci Retracement
OBJ_FIBOTIMES = 13, % Fibonacci Time Zones
OBJ_FIBOFAN = 14, % Fibonacci Fan
OBJ_FIBOARC = 15, % Fibonacci Arcs
OBJ_FIBOCHANNEL = 16, % Fibonacci Channel
OBJ_EXPANSION = 17, % Fibonacci Expansion
OBJ_ELLIOTWAVE5 = 18, % Elliott Motive Wave
OBJ_ELLIOTWAVE3 = 19, % Elliott Correction Wave
OBJ_RECTANGLE = 20, % Rectangle
OBJ_TRIANGLE = 21, % Triangle
OBJ_ELLIPSE = 22, % Ellipse
OBJ_ARROW_THUMB_UP = 23, % Thumbs Up
OBJ_ARROW_THUMB_DOWN = 24, % Thumbs Down
OBJ_ARROW_UP = 25, % Arrow Up
OBJ_ARROW_DOWN = 26, % Arrow Down
OBJ_ARROW_STOP = 27, % Stop Sign
OBJ_ARROW_CHECK = 28, % Check Sign
OBJ_ARROW_LEFT_PRICE = 29, % Left Price Label
OBJ_ARROW_RIGHT_PRICE = 30, % Right Price Label
OBJ_ARROW_BUY = 31, % Buy Sign
OBJ_ARROW_SELL = 32, % Sell Sign
OBJ_ARROW = 100, % Arrow
OBJ_TEXT = 101, % Text
OBJ_LABEL = 102, % Label
OBJ_BUTTON = 103, % Button
OBJ_CHART = 104, % Chart
OBJ_BITMAP = 105, % Bitmap
OBJ_BITMAP_LABEL = 106, % Bitmap Label
OBJ_EDIT = 107, % Edit
OBJ_EVENT = 109, % The "Event" object corresponding to an event in the economic calendar
OBJ_RECTANGLE_LABEL = 110 % The "Rectangle label" object for creating and designing the custom graphical interface.
%% ENUM_OBJECT_PROPERTY_DOUBLE
OBJPROP_PRICE = 9, % Price coordinate
OBJPROP_LEVELVALUE = 204, % Level value
OBJPROP_SCALE = 1006, % Scale (properties of Gann objects and Fibonacci Arcs)
OBJPROP_ANGLE = 1007, % Angle. For the objects with no angle specified, created from a program, the value is equal to EMPTY_VALUE
OBJPROP_DEVIATION = 1010 % Deviation for the Standard Deviation Channel
%% ENUM_OBJECT_PROPERTY_INTEGER
OBJPROP_COLOR = 0, % Color
OBJPROP_STYLE = 1, % Style
OBJPROP_WIDTH = 2, % Line thickness
OBJPROP_BACK = 3, % Object in the background
OBJPROP_ZORDER = 207, % Priority of a graphical object for receiving events of clicking on a chart (CHARTEVENT_CLICK). The default zero value is set when creating an object; the priority can be increased if necessary. When objects are placed one atop another, only one of them with the highest priority will receive the CHARTEVENT_CLICK event.
OBJPROP_FILL = 1031, % Fill an object with color (for OBJ_RECTANGLE, OBJ_TRIANGLE, OBJ_ELLIPSE, OBJ_CHANNEL, OBJ_STDDEVCHANNEL, OBJ_REGRESSION)
OBJPROP_HIDDEN = 208, % Prohibit showing of the name of a graphical object in the list of objects from the terminal menu "Charts" - "Objects" - "List of objects". The true value allows to hide an object from the list. By default, true is set to the objects that display calendar events, trading history and to the objects created from MQL5 programs. To see such graphical objects and access their properties, click on the "All" button in the "List of objects" window.
OBJPROP_SELECTED = 4, % Object is selected
OBJPROP_READONLY = 1028, % Ability to edit text in the Edit object
OBJPROP_TYPE = 7, % Object type
OBJPROP_TIME = 8, % Time coordinate
OBJPROP_SELECTABLE = 10, % Object availability
OBJPROP_CREATETIME = 11, % Time of object creation
OBJPROP_LEVELS = 200, % Number of levels
OBJPROP_LEVELCOLOR = 201, % Color of the line-level
OBJPROP_LEVELSTYLE = 202, % Style of the line-level
OBJPROP_LEVELWIDTH = 203, % Thickness of the line-level
OBJPROP_ALIGN = 1036, % Horizontal text alignment in the "Edit" object (OBJ_EDIT)
OBJPROP_FONTSIZE = 1002, % Font size
OBJPROP_RAY_LEFT = 1003, % Ray goes to the left
OBJPROP_RAY_RIGHT = 1004, % Ray goes to the right
OBJPROP_RAY = 1032, % A vertical line goes through all the windows of a chart
OBJPROP_ELLIPSE = 1005, % Showing the full ellipse of the Fibonacci Arc object (OBJ_FIBOARC)
OBJPROP_ARROWCODE = 1008, % Arrow code for the Arrow object
OBJPROP_TIMEFRAMES = 12, % Visibility of an object at timeframes
OBJPROP_ANCHOR = 1011, % Location of the anchor point of a graphical object
OBJPROP_XDISTANCE = 1012, % The distance in pixels along the X axis from the binding corner
OBJPROP_YDISTANCE = 1013, % The distance in pixels along the Y axis from the binding corner
OBJPROP_DIRECTION = 1014, % Trend of the Gann object
OBJPROP_DEGREE = 1015, % Level of the Elliott Wave Marking
OBJPROP_DRAWLINES = 1016, % Displaying lines for marking the Elliott Wave
OBJPROP_STATE = 1018, % Button state (pressed / depressed)
OBJPROP_CHART_ID = 1030, % ID of the "Chart" object (OBJ_CHART). It allows working with the properties of this object like with a normal chart using the functions described in Chart Operations, but there some exceptions.
OBJPROP_XSIZE = 1019, % The object's width along the X axis in pixels. Specified for OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT, OBJ_RECTANGLE_LABEL objects.
OBJPROP_YSIZE = 1020, % The object's height along the Y axis in pixels. Specified for OBJ_LABEL (read only), OBJ_BUTTON, OBJ_CHART, OBJ_BITMAP, OBJ_BITMAP_LABEL, OBJ_EDIT, OBJ_RECTANGLE_LABEL objects.
OBJPROP_XOFFSET = 1033, % The X coordinate of the upper left corner of the rectangular visible area in the graphical objects "Bitmap Label" and "Bitmap" (OBJ_BITMAP_LABEL and OBJ_BITMAP). The value is set in pixels relative to the upper left corner of the original image.
OBJPROP_YOFFSET = 1034, % The Y coordinate of the upper left corner of the rectangular visible area in the graphical objects "Bitmap Label" and "Bitmap" (OBJ_BITMAP_LABEL and OBJ_BITMAP). The value is set in pixels relative to the upper left corner of the original image.
OBJPROP_PERIOD = 1022, % Timeframe for the Chart object
OBJPROP_DATE_SCALE = 1023, % Displaying the time scale for the Chart object
OBJPROP_PRICE_SCALE = 1024, % Displaying the price scale for the Chart object
OBJPROP_CHART_SCALE = 1027, % The scale for the Chart object
OBJPROP_BGCOLOR = 1025, % The background color for OBJ_EDIT, OBJ_BUTTON, OBJ_RECTANGLE_LABEL
OBJPROP_CORNER = 1026, % The corner of the chart to link a graphical object
OBJPROP_BORDER_TYPE = 1029, % Border type for the "Rectangle label" object
OBJPROP_BORDER_COLOR = 1035 % Border color for the OBJ_EDIT and OBJ_BUTTON objects
%% ENUM_OBJECT_PROPERTY_STRING
OBJPROP_NAME = 5, % Object name
OBJPROP_TEXT = 6, % Description of the object (the text contained in the object)
OBJPROP_TOOLTIP = 206, % The text of a tooltip. If the property is not set, then the tooltip generated automatically by the terminal is shown. A tooltip can be disabled by setting the "\n" (line feed) value to it
OBJPROP_LEVELTEXT = 205, % Level description
OBJPROP_FONT = 1001, % Font
OBJPROP_BMPFILE = 1017, % The name of BMP-file for Bitmap Label.
OBJPROP_SYMBOL = 1021 % Symbol for the Chart object
%% ENUM_BORDER_TYPE
BORDER_FLAT = 0, % Flat form
BORDER_RAISED = 1, % Prominent form
BORDER_SUNKEN = 2 % Concave form
%% ENUM_ALIGN_MODE
ALIGN_LEFT = 1, % Left alignment
ALIGN_CENTER = 2, % Centered (only for the Edit object)
ALIGN_RIGHT = 0, % Right alignment
%% ENUM_APPLIED_PRICE
PRICE_CLOSE = MtApi5.ENUM_APPLIED_PRICE.PRICE_CLOSE % Close price
PRICE_OPEN = MtApi5.ENUM_APPLIED_PRICE.PRICE_OPEN % Open price
PRICE_HIGH = MtApi5.ENUM_APPLIED_PRICE.PRICE_HIGH % The maximum price for the period
PRICE_LOW = MtApi5.ENUM_APPLIED_PRICE.PRICE_LOW % The minimum price for the period
PRICE_MEDIAN = MtApi5.ENUM_APPLIED_PRICE.PRICE_MEDIAN % Median price, (high + low)/2
PRICE_TYPICAL = MtApi5.ENUM_APPLIED_PRICE.PRICE_TYPICAL % Typical price, (high + low + close)/3
PRICE_WEIGHTED = MtApi5.ENUM_APPLIED_PRICE.PRICE_WEIGHTED % Average price, (high + low + close + close)/4
%% ENUM_APPLIED_VOLUME
VOLUME_TICK = MtApi5.ENUM_APPLIED_VOLUME.VOLUME_TICK % Tick volume
VOLUME_REAL = MtApi5.ENUM_APPLIED_VOLUME.VOLUME_REAL % Trade volume
%% ENUM_STO_PRICE
STO_LOWHIGH = MtApi5.ENUM_STO_PRICE.STO_LOWHIGH % Calculation is based on Low/High prices
STO_CLOSECLOSE = MtApi5.ENUM_STO_PRICE.STO_CLOSECLOSE % Calculation is based on Close/Close prices
%% ENUM_MA_METHOD
MODE_SMA = 0, % Simple averaging
MODE_EMA = 1, % Exponential averaging
MODE_SMMA = 2, % Smoothed averaging
MODE_LWMA = 3 % Linear-weighted averaging
%% ENUM_INDICATOR
IND_AC = 5, % Accelerator Oscillator
IND_AD = 6, % Accumulation/Distribution
IND_ADX = 8, % Average Directional Index
IND_ADXW = 9, % ADX by Welles Wilder
IND_ALLIGATOR = 7, % Alligator
IND_AMA = 40, % Adaptive Moving Average
IND_AO = 11, % Awesome Oscillator
IND_ATR = 10, % Average True Range
IND_BANDS = 13, % Bollinger Bands®
IND_BEARS = 12, % Bears Power
IND_BULLS = 14, % Bulls Power
IND_BWMFI = 22, % Market Facilitation Index
IND_CCI = 15, % Commodity Channel Index
IND_CHAIKIN = 41, % Chaikin Oscillator
IND_CUSTOM = 43, % Custom indicator
IND_DEMA = 36, % Double Exponential Moving Average
IND_DEMARKER = 16, % DeMarker
IND_ENVELOPES = 17, % Envelopes
IND_FORCE = 18, % Force Index
IND_FRACTALS = 19, % Fractals
IND_FRAMA = 39, % Fractal Adaptive Moving Average
IND_GATOR = 20, % Gator Oscillator
IND_ICHIMOKU = 21, % Ichimoku Kinko Hyo
IND_MA = 26, % Moving Average
IND_MACD = 23, % MACD
IND_MFI = 25, % Money Flow Index
IND_MOMENTUM = 24, % Momentum
IND_OBV = 28, % On Balance Volume
IND_OSMA = 27, % OsMA
IND_RSI = 30, % Relative Strength Index
IND_RVI = 31, % Relative Vigor Index
IND_SAR = 29, % Parabolic SAR
IND_STDDEV = 32, % Standard Deviation
IND_STOCHASTIC = 33, % Stochastic Oscillator
IND_TEMA = 37, % Triple Exponential Moving Average
IND_TRIX = 38, % Triple Exponential Moving Averages Oscillator
IND_VIDYA = 42, % Variable Index Dynamic Average
IND_VOLUMES = 34, % Volumes
IND_WPR = 35 % Williams' Percent Ranges
%% ENUM_DATATYPE
TYPE_BOOL = MtApi5.ENUM_DATATYPE.TYPE_BOOL
TYPE_CHAR = MtApi5.ENUM_DATATYPE.TYPE_CHAR
TYPE_UCHAR = MtApi5.ENUM_DATATYPE.TYPE_UCHAR
TYPE_SHORT = MtApi5.ENUM_DATATYPE.TYPE_SHORT
TYPE_USHORT = MtApi5.ENUM_DATATYPE.TYPE_USHORT
TYPE_COLOR = MtApi5.ENUM_DATATYPE.TYPE_COLOR
TYPE_INT = MtApi5.ENUM_DATATYPE.TYPE_INT
TYPE_UINT = MtApi5.ENUM_DATATYPE.TYPE_UINT
TYPE_DATETIME = MtApi5.ENUM_DATATYPE.TYPE_DATETIME
TYPE_LONG = MtApi5.ENUM_DATATYPE.TYPE_LONG
TYPE_ULONG = MtApi5.ENUM_DATATYPE.TYPE_ULONG
TYPE_FLOAT = MtApi5.ENUM_DATATYPE.TYPE_FLOAT
TYPE_DOUBLE = MtApi5.ENUM_DATATYPE.TYPE_DOUBLE
TYPE_STRING = MtApi5.ENUM_DATATYPE.TYPE_STRING
end
end
@@ -0,0 +1,115 @@
classdef cntMt5Api_apiResult < handle
%% stores and manage date result from Mt5Api
properties
cLogger; % logger
Status = false; % bool
Bool = []; % bool
Double = []; % double
sDoubles = []; % System.Double
Int32 = []; % int32
UInt32 = []; % uint32
sInts = []; % System.Int
Int64 = []; % int64
sLongs = []; % System.Long
String = []; % System.String
errString = []; % string
lastError = uint32(0); % int32 1=No Connection / 2=Error MT5
lastErrorString = ""; % string
sDateTime = System.DateTime; % System.DateTime
sDTfrom = System.DateTime; % System.DateTime
sDTto = System.DateTime; % System.DateTime
sDateTimes = [];
sListMqlTick = []; % System.List*MqlTick
MqlTick = MtApi5.MqlTick;
MqlBook = MtApi5.MqlBookInfo(MtApi5.ENUM_BOOK_TYPE.BOOK_TYPE_BUY,0,0);
MqlTradeCheckResult = MtApi5.MqlTradeCheckResult(0,0,0,0,0,0,0,'emty')
MqlTradeRequest = MtApi5.MqlTradeRequest;
MqlTradeResult = MtApi5.MqlTradeResult(0,0,0,0,0,0,0,'emty',0);
MqlRates = NET.createArray('MtApi5.MqlBookInfo',1);
end
methods
%% constructor
function obj = cntMt5Api_apiResult()
obj.errString = 'No Error';
end
%% set functions
function setSuccess(obj)
obj.Status = true;
end
function setError(obj,varargin)
obj.Status = false;
if nargin > 1
if isnumerictype(varargin{1})
obj.lastError = varargin{1};
end
end
if nargin > 2
if ischar(varargin{2})
obj.errString = varargin{2};
end
end
end
%% get functions
function result_ok = isSuccess(self)
result_ok = false;
if self.Status == true
result_ok = true;
end
end
function result_ok = isError(self)
result_ok = false;
if self.Status == false
result_ok = true;
end
end
function isError = getLastError(self,apiHandle)
isError = false;
cApiResult = apiHandle.cCheckup.GetLastError();
self.lastError = cApiResult.Int32;
if self.lastError == 0
self.lastErrorString = "No Error";
else
self.lastErrorString = sprintf("Unknown Error: %d ",self.lastError);
isError = true;
end
end
%% result convert functions
function charResult = MqlTradeResult_toChar(self)
charResult = char(self.MqlTradeResult.ToString);
end
function charResult = MqlTradeCheckResult_toChar(self)
charResult = char(self.MqlTradeCheckResult.ToString);
end
function charResult = MqlTradeRequest_toChar(self)
charResult = char(self.MqlTradeRequest.ToString);
end
function strResult = Int32_toString(self)
strResult = int2str(self.Int32);
end
function strResult = Int64_toString(self)
strResult = int2str(self.Int64);
end
function strResult = Double_toString(self)
% disp(self.Double);
strResult = num2str(self.Double,6);
end
end
end
@@ -0,0 +1,938 @@
classdef cntMt5Api_timeseries
%% Properties
properties
cMt5Api;
cApiResult;
cLogger;
hCharConnectionState;
mSymbol char;
mBars DataStore.Bars;
debugCounter = uint32(0);
hbDeInitStatus;
end
methods
%% Contructor
function obj = cntMt5Api_timeseries(api)
obj.cMt5Api = api;
obj.cLogger = api.cLogger;
obj.cLogger.trace('TimeSeries class created',0);
obj.cApiResult = cntMt5Api_apiResult;
% obj.hCharConnectionState = api.hConState;
% obj.hbDeInitStatus = api.hbDEINITSTATUS;
end
%% Helper Functions
function connection_ok = isConnected(obj)
if obj.cMt5Api.h.ConnectionState == MtApi5.Mt5ConnectionState.Connected
connection_ok = true;
else
connection_ok = false;
end
end
function deinit = isDeInitSet(obj)
deinit = obj.cMt5Api.bStatusDeInit;
if (deinit)
disp(deinit)
end
end
%% Api Functions
function cApiResult = SeriesInfoInteger(self,symbolName, enum_TF, enum_propID)
% int SeriesInfoInteger(string symbolName, ENUM_TIMEFRAMES timeframe, ENUM_SERIES_INFO_INTEGER propId)
%
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "propId" > Identifier of the requested property, value of the ENUM_SERIES_INFO_INTEGER enumeration
cApiResult = cntMt5Api_apiResult;
cApiResult.Int64 = self.cMt5Api.h.SeriesInfoInteger(symbolName, enum_TF, enum_propID);
if isinteger(cApiResult.Int64)
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = Bars(self,symbolName, enum_TF)
% int Bars(string symbolName, ENUM_TIMEFRAMES timeframe)
%
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
cApiResult = cntMt5Api_apiResult;
cApiResult.Int32 = self.cMt5Api.h.Bars(symbolName, enum_TF);
if isinteger(cApiResult.Int32)
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = Bars2(self,symbolName, enum_TF, sDTstartTime, sDTstopTime)
% int Bars(string symbolName, ENUM_TIMEFRAMES timeframe)
%
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
cApiResult = cntMt5Api_apiResult;
cApiResult.Int32 = self.cMt5Api.h.Bars(symbolName, enum_TF, sDTstartTime, sDTstopTime );
if isinteger(cApiResult.Int32)
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyRates(self,symbolName, timeframe, startPos, count)
%% int CopyRates(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out MqlRates[] ratesArray)
% Gets history data of MqlRates structure of a specified symbol-period in specified quantity into the ratesArray array.
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
%
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "startPos" > The start position for the first element to copy.
% "count" > Data count to copy.
% "ratesArray" > Array of MqlRates type
cApiResult = cntMt5Api_apiResult;
self.debugCounter = self.debugCounter+1;
if ~self.isDeInitSet()
try
% disp('start api access')
% disp('STATUS:');
% disp(self.cMt5Api.bStatusDeInit)
[cApiResult.Int32, cApiResult.MqlRates] = self.cMt5Api.h.CopyRates(symbolName, timeframe, startPos, count );
% disp('access end');
if isinteger(cApiResult.Int32) && cApiResult.Int32 == count && cApiResult.MqlRates.Length == count
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError(2,'Error from Mt5');
end
catch ME
cApiResult.setError(1,"Try Catch failed ,No Connection");
self.cLogger.error('Try Catch failed ,No Connection');
disp(ME.stack(1))
self.cLogger.error('.NET Execption');
end
else
cApiResult.setError(1,"No Connection");
self.cLogger.error('No Connection');
end
end % Test ok
function cApiResult = CopyRatesTimeCount(self,symbolName, timeframe, sDTstartTime, count)
%% int CopyRates(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out MqlRates[] ratesArray)
% Gets history data of MqlRates structure of a specified symbol-period in specified quantity into the ratesArray array.
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
%
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "startTime" > The start time for the first element to copy.
% "count" > Data count to copy.
% "ratesArray" > Array of MqlRates type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.MqlRates] = self.cMt5Api.h.CopyRates(symbolName, timeframe, sDTstartTime, count );
if isinteger(cApiResult.Int32) && cApiResult.Int32 == count && cApiResult.MqlRates.Length == count
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyRatesTwoTimes(self,symbolName, timeframe, sDTstartTime, sDTstopTime)
%% Gets history data of MqlRates structure of a specified symbol-period in specified quantity into the ratesArray array.
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "startTime" > The start time for the first element to copy.
% "stopTime" > Bar time, corresponding to the last element to copy.
% "ratesArray" > Array of MqlRates type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.MqlRates] = self.cMt5Api.h.CopyRates(symbolName, timeframe, sDTstartTime, sDTstopTime );
if isinteger(cApiResult.Int32)
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyTime(self,symbolName, timeframe, value1, value2)
%% int CopyTime(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out DateTime[] timeArray)
%% int CopyTime(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out DateTime[] timeArray)
%% int CopyTime(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out DateTime[] timeArray)
% The function gets to time_array history data of bar opening time for the specified symbol-period pair in the specified quantity.
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "timeArray" > Array of DatetTme type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sDateTimes] = self.cMt5Api.h.CopyTime(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32)
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyOpen(self,symbolName, timeframe, value1, value2)
%% int CopyOpen(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out out double[] openArray)
%% int CopyOpen(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out double[] openArray)
%% int CopyOpen(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out double[] openArray)
% The function gets into open_array the history data of bar open prices for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "openArray" > Array of double type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sDoubles] = self.cMt5Api.h.CopyOpen(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyHigh(self,symbolName, timeframe, value1, value2)
%% int CopyHigh(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out out double[] openArray)
%% int CopyHigh(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out double[] openArray)
%% int CopyHigh(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out double[] openArray)
% The function gets into high_array the history data of bar open prices for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "openArray" > Array of double type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sDoubles] = self.cMt5Api.h.CopyHigh(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyLow(self,symbolName, timeframe, value1, value2)
%% int CopyLow(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out out double[] openArray)
%% int CopyLow(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out double[] openArray)
%% int CopyLow(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out double[] openArray)
% The function gets into low_array the history data of bar open prices for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "openArray" > Array of double type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sDoubles] = self.cMt5Api.h.CopyLow(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyClose(self,symbolName, timeframe, value1, value2)
%% int CopyClose(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out out double[] openArray)
%% int CopyClose(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out double[] openArray)
%% int CopyClose(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out double[] openArray)
% The function gets into close_array the history data of bar open prices for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "openArray" > Array of double type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sDoubles] = self.cMt5Api.h.CopyClose(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyTickVolume(self,symbolName, timeframe, value1, value2)
%% int CopyTickVolume(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out long[] volumeArray)
%% int CopyTickVolume(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out long[] volumeArray)
%% int CopyTickVolume(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out long[] volumeArray)
% The function gets into volume_array the history data of tick volumes for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "volumeArray" > Array of long type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sLongs] = self.cMt5Api.h.CopyTickVolume(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyRealVolume(self,symbolName, timeframe, value1, value2)
%% int CopyRealVolume(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out long[] volumeArray)
%% int CopyRealVolume(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out long[] volumeArray)
%% int CopyRealVolume(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out long[] volumeArray)
% The function gets into volume_array the history data of trade volumes for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "volumeArray" > Array of long type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sLongs] = self.cMt5Api.h.CopyRealVolume(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopySpread(self,symbolName, timeframe, value1, value2)
%% int CopySpread(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count, out int[] spreadArray)
%% int CopySpread(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count, out int[] spreadArray)
%% int CopySpread(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime, out int[] spreadArray)
% The function gets into spread_array the history data of spread values for the selected symbol-period pair in the specified quantity
%
% The elements ordering of the copied data is from present to the past, i.e., starting position of 0 means the current bar.
% Returns information about the state of historical data.
% "symbolName" > Symbol name
% "timeframe" > Period
% "count" > Data count to copy
% "startPos" > The start position for the first element to copy
% "startTime" > The start time for the first element to copy
% "stopTime" > Bar time, corresponding to the last element to copy
% "spreadArray" > Array of int type
cApiResult = cntMt5Api_apiResult;
[cApiResult.Int32, cApiResult.sInts] = self.cMt5Api.h.CopySpread(symbolName, timeframe, value1, value2 );
if isinteger(cApiResult.Int32) && cApiResult.Int32 > 0
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
function cApiResult = CopyTicks(self,symbolName, flags, from, count)
%% List<MqlTick> CopyTicks(string symbolName, CopyTicksFlag flags = CopyTicksFlag.All, ulong from = 0, uint count = 0)
% The function receives ticks in the MqlTick format into ticks_array. In this case, ticks are indexed from the past to the present, i.e. the 0 indexed tick is the oldest one in the array
% For tick analysis, check the flags field, which shows what exactly has changed in the tick.
%
%
% "symbolName" > Symbol name
% "flags" > The flag that determines the type of received ticks.
% "from" > The date from which you want to request ticks. In milliseconds since 1970.01.01. If from=0, the last count ticks will be returned
% "count" > The number of ticks that you want to receive. If the 'from' and 'count' parameters are not specified, all available recent ticks (but not more than 2000) will be written to result
cApiResult = cntMt5Api_apiResult;
cApiResult.sListMqlTick = self.cMt5Api.h.CopyTicks(symbolName, flags, from, count );
if cApiResult.sListMqlTick.Count == count
cApiResult.setSuccess();
else
self.cLogger.error('Error from Mt5 ');
cApiResult.setError('Error from Mt5');
end
end % Test ok
%% class functions
% Event Listener
function r = setQuoteListener(self,hBars)
r = addlistener(self.cMt5Api.h, 'QuoteUpdate', @(src,event)self.quoteListener(src,event,hBars));
end
function quoteListener(self,~,event,hBars)
persistent errCount ;
if ~feature('IsDebugMode')
% disp('Quote Update ');
if isempty(errCount)
errCount = 0;
end
eTF = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
if self.mIsNewBar(eTF)
% self.cLogger.info('New Bar detected');
cApiResult = self.CopyRates(self.mSymbol,eTF, 0, 1);
if errCount < 5
if ~self.mUpdateBars(hBars,cApiResult.MqlRates(1))
errCount = errCount+1;
if errCount == 5
self.cLogger.error('Update Bars stopped while error count > 5');
end
end
end
end
else
% disp('Quote Update in Debug Mode');
end
end
% Data Management
function [ok, bars] = mCreateBars(self,enTimeframe,chSymbol,iSize)
% [ok, bars] = mCreateBars(MtApi5.ENUM_TIMEFRAMES ,char Symbol,int32 Size)
bars = DataStore.Bars(chSymbol, enTimeframe, iSize);
bars.chSymbol = chSymbol;
bars.iSize = iSize;
ok = true;
end
function ok = mUpdateBars(self,hBars,hMqlRate)
if hBars.iSize == hBars.iLast
self.cLogger.error('Can not store more mqlRates, Bars Size Limit reached');
ok = false;
return
end
if ~isempty(hBars)
idx = hBars.iLast;
else
idx = 0;
end
if idx > 0
% hBars.mqlRates(idx+1) = hMqlRate;
hBars.dOpen(idx+1) = hMqlRate.open;
hBars.dHigh(idx+1) = hMqlRate.high;
hBars.dLow(idx+1) = hMqlRate.low;
hBars.dClose(idx+1) = hMqlRate.close;
hBars.i64TickVol(idx+1) = hMqlRate.tick_volume;
hBars.sdtTime(idx+1) = hMqlRate.time;
hBars.i64MTtime(idx+1) = hMqlRate.mt_time;
hBars.dtTime(idx+1) = datetime(hMqlRate.mt_time , 'ConvertFrom', 'posixtime');
hBars.iLast = idx+1;
else
hBars.sdOpen(1)= hMqlRate.open;
hBars.iLast = 1;
end
ok = true;
end
function ok = fn_UpdateBars_big(self,hBars,hMqlRate)
if hBars.eurusd.iSize == hBars.eurusd.iLast
self.cLogger.error('Can not store more mqlRates, Bars Size Limit reached');
ok = false;
return
end
if ~isempty(hBars)
idx = hBars.eurusd.iLast;
else
idx = 0;
end
if idx > 0
% hBars.mqlRates(idx+1) = hMqlRate;
hBars.dOpen(idx+1) = hMqlRate.open;
hBars.dHigh(idx+1) = hMqlRate.high;
hBars.dLow(idx+1) = hMqlRate.low;
hBars.dClose(idx+1) = hMqlRate.close;
hBars.i64TickVol(idx+1) = hMqlRate.tick_volume;
hBars.sdtTime(idx+1) = hMqlRate.time;
hBars.i64MTtime(idx+1) = hMqlRate.mt_time;
hBars.dtTime(idx+1) = datetime(hMqlRate.mt_time , 'ConvertFrom', 'posixtime');
hBars.iLast = idx+1;
else
hBars.sdOpen(1)= hMqlRate.open;
hBars.iLast = 1;
end
ok = true;
end
function [ok, bars] = mCreateFilledBars(self,chSymbol,enTimeframe,iStartPos,iCount,iSize)
self.cLogger.debug('Create empty Bars' );
bars = DataStore.Bars(chSymbol, enTimeframe, iSize);
self.cLogger.debug('Create ready' );
try
self.cLogger.debug('API: copyrates...' );
[copied, bars.mqlRates] = self.cMt5Api.h.CopyRates(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
self.cLogger.debug('API: ready' );
if copied > 0
self.cLogger.debug('Copy mqlRates to Bars System.Values...' );
for idx=1:1:copied
bars.i64MTtime(idx) = bars.mqlRates(idx).mt_time;
bars.dtTime(idx) = datetime(bars.i64MTtime(idx) , 'ConvertFrom', 'posixtime');
% bars.sdOpen(idx) = mqlRates(idx).open;
% bars.sdHigh(idx) = mqlRates(idx).high;
% bars.sdLow(idx) = mqlRates(idx).low;
% bars.sdClose(idx) = mqlRates(idx).close;
end
bars.iLast = copied;
self.cLogger.debug('Copy mqlRates ready' );
else
self.cLogger.error('CopyRates has 0 copied');
ok = false;
return;
end
self.cLogger.debug('API: copy open,high,low,close,time,volume' );
[copiedOpen, sdOpen] = self.cMt5Api.h.CopyOpen(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dOpen(1:iCount) = double(sdOpen);
[copiedHigh, sdHigh] = self.cMt5Api.h.CopyHigh(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dHigh(1:iCount) = double(sdHigh);
[copiedLow, sdLow] = self.cMt5Api.h.CopyLow(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dLow(1:iCount) = double(sdLow);
[copiedClose, sdClose] = self.cMt5Api.h.CopyClose(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dClose(1:iCount) = double(sdClose);
[copiedSpread, si32Spread] = self.cMt5Api.h.CopySpread(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i32Spread(1:iCount) = int32(si32Spread);
[copiedTickVol, si64TickVol] = self.cMt5Api.h.CopyTickVolume(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i64TickVol(1:iCount) = int64(si64TickVol);
[copiedRealVol, si64RealVol] = self.cMt5Api.h.CopyRealVolume(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i64RealVol(1:iCount) = int64(si64RealVol);
[copiedTime, sdtTime] = self.cMt5Api.h.CopyTime(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
sdtTime.CopyTo(bars.sdtTime,0);
self.cLogger.debug('API: Copy OHLC ready' );
catch ME
if(isa(ME, 'NET.NetException'))
BE = ME.ExceptionObject.GetBaseException;
self.cLogger.error(sprintf('Matlab Execption: %s',char(ME.message)));
self.cLogger.error(sprintf('Base Execption: %s',char(BE.StackTrace)));
elseif(isa(ME, 'MException'))
disp(ME.message);
else
error('Unknown Exeption Type');
end
ok = false;
return;
end
if bars.iLast == iCount &&...
copiedOpen == iCount &&...
copiedHigh == iCount &&...
copiedLow == iCount &&...
copiedClose == iCount &&...
copiedTime == iCount &&...
copiedSpread == iCount &&...
copiedTickVol == iCount &&...
copiedRealVol == iCount
bars.sdtStart = bars.mqlRates(1).time;
bars.sdtEnd = bars.mqlRates(bars.iLast).time;
bars.sStart = char(bars.sdtStart.ToString);
bars.sEnd = char(bars.sdtEnd.ToString);
self.cLogger.debug(sprintf('%s Bars object created',bars.chSymbol));
self.cLogger.debug(sprintf('Size: %d Elements',bars.iSize));
self.cLogger.debug(sprintf('Last: %d Element',bars.iLast));
self.cLogger.debug(sprintf('Start: %s ',char(bars.sdtStart.ToString)));
self.cLogger.debug(sprintf('End : %s ',char(bars.sdtEnd.ToString)));
ok = true;
else
self.cLogger.error(sprintf('Creating Bars Object :%s ',"Error"));
ok = false;
end
end % Test ok
function [ok, bars] = mCreateFilledBarsPARALEL(self,chSymbol,enTimeframe,iStartPos,iCount,iSize)
self.cLogger.debug('Parfor Mode' );
self.cLogger.debug('Create empty Bars' );
bars = DataStore.Bars(chSymbol, enTimeframe, iSize);
self.cLogger.debug('Create ready' );
try
self.cLogger.debug('API: copyrates...' );
[copied, bars.mqlRates] = self.cMt5Api.h.CopyRates(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
self.cLogger.debug('API: ready' );
if copied > 0
self.cLogger.debug('Copy mqlRates to Bars System.Values...' );
parRes1 = zeros(1,copied);
parRes2 = zeros(1,copied);
parfor idx=1:1:copied
parRes1(idx) = bars.mqlRates(idx).mt_time;
parRes2(idx) = datetime(parRes1(idx) , 'ConvertFrom', 'posixtime');
% bars.sdOpen(idx) = mqlRates(idx).open;
% bars.sdHigh(idx) = mqlRates(idx).high;
% bars.sdLow(idx) = mqlRates(idx).low;
% bars.sdClose(idx) = mqlRates(idx).close;
end
% bars.i64MTtime(idx)
% bars.dtTime(idx)
bars.iLast = copied;
self.cLogger.debug('Copy mqlRates ready' );
else
self.cLogger.error('CopyRates has 0 copied');
ok = false;
return;
end
self.cLogger.debug('API: copy open,high,low,close,time,volume' );
[copiedOpen, sdOpen] = self.cMt5Api.h.CopyOpen(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dOpen(1:iCount) = double(sdOpen);
[copiedHigh, sdHigh] = self.cMt5Api.h.CopyHigh(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dHigh(1:iCount) = double(sdHigh);
[copiedLow, sdLow] = self.cMt5Api.h.CopyLow(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dLow(1:iCount) = double(sdLow);
[copiedClose, sdClose] = self.cMt5Api.h.CopyClose(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.dClose(1:iCount) = double(sdClose);
[copiedSpread, si32Spread] = self.cMt5Api.h.CopySpread(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i32Spread(1:iCount) = int32(si32Spread);
[copiedTickVol, si64TickVol] = self.cMt5Api.h.CopyTickVolume(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i64TickVol(1:iCount) = int64(si64TickVol);
[copiedRealVol, si64RealVol] = self.cMt5Api.h.CopyRealVolume(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
bars.i64RealVol(1:iCount) = int64(si64RealVol);
[copiedTime, sdtTime] = self.cMt5Api.h.CopyTime(bars.chSymbol, bars.enTimeframe, iStartPos, iCount);
sdtTime.CopyTo(bars.sdtTime,0);
self.cLogger.debug('Copy OHLC ready' );
catch ME
if(isa(ME, 'NET.NetException'))
BE = ME.ExceptionObject.GetBaseException;
self.cLogger.error(sprintf('Matlab Execption: %s',char(ME.message)));
self.cLogger.error(sprintf('Base Execption: %s',char(BE.StackTrace)));
elseif(isa(ME, 'MException'))
disp(ME.message);
else
error('Unknown Exeption Type');
end
ok = false;
return;
end
if bars.iLast == iCount &&...
copiedOpen == iCount &&...
copiedHigh == iCount &&...
copiedLow == iCount &&...
copiedClose == iCount &&...
copiedTime == iCount &&...
copiedSpread == iCount &&...
copiedTickVol == iCount &&...
copiedRealVol == iCount
bars.sdtStart = bars.mqlRates(1).time;
bars.sdtEnd = bars.mqlRates(bars.iLast).time;
bars.sStart = char(bars.sdtStart.ToString);
bars.sEnd = char(bars.sdtEnd.ToString);
self.cLogger.debug(sprintf('%s Bars object created',bars.chSymbol));
self.cLogger.debug(sprintf('Size: %d Elements',bars.iSize));
self.cLogger.debug(sprintf('Last: %d Element',bars.iLast));
self.cLogger.debug(sprintf('Start: %s ',char(bars.sdtStart.ToString)));
self.cLogger.debug(sprintf('End : %s ',char(bars.sdtEnd.ToString)));
ok = true;
else
self.cLogger.error(sprintf('Creating Bars Object :%s ',"Error"));
ok = false;
end
end
function ok = mGetAndStoreNewBar(self,hBars)
ok = false;
eTF = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
cApiResult = self.CopyRates(self.mSymbol,eTF, 0, 1);
if cApiResult.isSuccess()
if self.mUpdateBars(hBars,cApiResult.MqlRates(1))
% self.cLogger.trace('New Bar added to Bars Object');
ok = true;
else
self.cLogger.error('Can`t add new Bar to Bars Object');
ok = false;
end
end
end
function ok = fn_GetAndStoreNewBar_multisymbols(self,hBars,opts)
ok = false;
eTF = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
max = opts.symbols.num ;
for idx=1:1:max
cApiResult = self.CopyRates((upper(opts.symbols.Chars{idx})),eTF, 0, 1);
if cApiResult.isSuccess()
if self.mUpdateBars(hBars.(opts.symbols.Chars{idx}),cApiResult.MqlRates(1))
% self.cLogger.trace('New Bar added to Bars Object');
ok = true;
else
self.cLogger.error('Can`t add new Bar to Bars Object');
ok = false;
end
end
end
end
function ok = mIsNewBar(self,enum_TF)
ok = false;
persistent I_LastBarTime;
I_CurrentBarTime = self.cMt5Api.h.SeriesInfoInteger(self.mSymbol, enum_TF, MtApi5.ENUM_SERIES_INFO_INTEGER.SERIES_LASTBAR_DATE);
if isempty(I_LastBarTime)
I_LastBarTime = I_CurrentBarTime;
% disp('First Init of LastBarTime');
return
end
if I_CurrentBarTime > I_LastBarTime
I_LastBarTime = I_CurrentBarTime;
ok = true;
return
else
I_LastBarTime = I_CurrentBarTime;
end
end % Test ok
end
end
Binary file not shown.
@@ -0,0 +1,84 @@
function sAttachment = MakeSlackAttachment(strFallback, strText, strPreText, strColor, varargin)
% MakeSlackAttachment - FUNCTION Construct an attachment to add to a Slack notification
%
% Usage: sAttachment = MakeSlackAttachment(strFallback, <strText>, <strPreText>, strColor, ...)
% Usage: sAttachment = MakeSlackAttachment(..., {strField1Title, strField1Value, <bField1Short>}, {strField2Title, strField2Value, <bField2Short>}, ...)
%
% Creates an attachment structure, to send along with a Slack notification
% using 'SendSlackNotification'. See <https://api.slack.com/docs/attachments>
% and <https://api.slack.com/docs/formatting> for information.
%
% 'strFallback' is a text string, which is displayed when the notification
% cannot be displayed in full.
%
% 'strText' (optional) is a text string containing the text of the notification.
%
% 'strPreText' (optional) is a text string that will be displayed before
% the notification text.
%
% 'strColor' (optional) is a hex color string (e.g. '#ff3300'), or one of
% 'good', 'warning', 'danger'.
%
% These parameters can be followed by a list of cell arrays, each array
% containing a "field" to be added to the attachment. Each field array must
% be in the format {strTitle, strValue <, bShort>}. 'strTitle' is a text
% string containing the title of the field. 'strValue' is a text string
% containing the value to be shown for that field.
%
% If present, these fields will be shown below the attachment in a
% notificaition.
% Author: Dylan Muir <dylan.muir@unibas.ch>
% Created: 19th September, 2014
% -- Check arguments
if (nargin < 1)
help MakeSlackAttachment;
error('*** MakeSlackAttachment: Incorrect usage');
end
% - Include fallback text
sAttachment.fallback = strFallback;
% - Include extended text
if (exist('strText', 'var') && ~isempty(strText))
sAttachment.text = strText;
end
% - Include pre-text
if (exist('strPreText', 'var') && ~isempty(strPreText))
sAttachment.pretext = strPreText;
end
% - Include extended text
if (exist('strColor', 'var') && ~isempty(strColor))
sAttachment.color = strColor;
end
% - Include list of fields
for (nFieldIndex = numel(varargin):-1:1)
sThisField = [];
sThisField.title = varargin{nFieldIndex}{1};
sThisField.value = varargin{nFieldIndex}{2};
% - Add "short"
if ((numel(varargin{nFieldIndex}) > 2) && varargin{nFieldIndex}{3})
sThisField.short = 'true';
else
sThisField.short = 'false';
end
sAttachment.fields{nFieldIndex} = sThisField;
end
% - Add a dummy field if necessary (to ensure proper JSON formatting)
if (numel(varargin) == 1)
sThisField = [];
sThisField.title = '';
sAttachment.fields{end+1} = sThisField;
end
% --- END of MakeSlackAttachment.m ---
@@ -0,0 +1,41 @@
# README #
This repository contains ```Matlab``` functions to send notifications to a Slack channel or user, via the Slack [Incoming Webhooks](https://slack.com/services/new/incoming-webhook) API.
## Usage ##
```SendSlackNotification``` is used to send a notification to a URL provided by Slack, for a configured [Incoming Webhooks](https://slack.com/services/new/incoming-webhook) integration. See the documentation for this function for information on options.
```MakeSlackAttachments``` can be used to generate Slack [message attachments](https://api.slack.com/docs/attachments), which can then be sent as notifications using ```SendSlackNotification```. See the documentation for this function for more information.
## Set up ##
1. Configure an [Incoming Webhooks](https://slack.com/services/new/incoming-webhook) integration for your team, from your team's [services](https://slack.com/services) page.
2. Copy the Webhook URL once the service is configured, and store it in a ```Matlab``` string.
3. Clone the [SlackMatlab repository](https://github.com/DylanMuir/SlackMatlab), and add the root directory to the ```Matlab``` path using ```pathtool```.
4. Call ```SendSlackNotification```, passing the Webhook URL as an argument.
### Example ###
```matlab
% - Create a message attachment to send with a notification
% (optional; several message attachments can be sent with a single notification)
sA = MakeSlackAttachment('New open task [urgent]: <link.to.website>', 'Text of the notification message', ...
'Text that will be displayed before the message', '#0000ff', ...
{'Field 1 title', 'This is a field that will be shown in a table'}, ...
{'Field 2 title', 'This is another field that will be shown in a table'});
% - Send the notification, with the attached message
SendSlackNotification('https://hooks.slack.com/services/this/is/your/webhook/url', ...
'I sent this notification from matlab, on behalf of @username.', '#target-channel', ...
'Name to post under', 'http://www.icon.com/url/to/icon/image.png', [], sA);
```
## Emojis ##
A list of Emojis supported by Slack is available from http://www.emoji-cheat-sheet.com.
## Acknowledgements ##
Contains code from [URLREAD2](http://www.mathworks.com/matlabcentral/fileexchange/35693-urlread2) and [JSONLAB](http://www.mathworks.com/matlabcentral/fileexchange/33381-jsonlab--a-toolbox-to-encode-decode-json-files-in-matlab-octave).
@@ -0,0 +1,110 @@
function [strHTTPOutput, sHTTPExtra] = SendSlackNotification(strHookURL, strText, strTarget, strUsername, strIconURL, strIconEmoji, csAttachments)
% SendSlackNotification - FUNCTION Send a customisable notification via a Slack webhook integration
%
% Usage: [strHTTPOutput, sHTTPExtra] = SendSlackNotification(strHookURL, strText, <strTarget, strUsername, strIconURL, strIconEmoji>, ...)
% SendSlackNotification(..., sAttachment)
% SendSlackNotification(..., {sAttachment1 sAttachment2})
%
% Use the Slack webhooks API to send a notification to a Slack channel or
% user. See See <https://slack.com/services/new/incoming-webhook>,
% <https://api.slack.com/docs/attachments> and
% <https://api.slack.com/docs/formatting> for further information.
%
% 'strHookURL' is the full URL configured for webhook integration from
% Slack.
%
% 'strText' is a string containing (possibly marked-up) text, which will be
% sent as the notification.
%
% Optional arguments:
% strTarget: A channel name ('#channel') or a user name ('@username') to
% send the notification to. By default, the channel
% configured within Slack for the provided webhook URL will
% be used.
% strUsername: A text string defining the name under which the
% notification will be posted. By default, Slack uses
% 'incoming-webhook'.
% strIconURL: A URL referencing an image file to use as the icon for the
% notification. By default, Slack uses a webhook icon.
% strIconEmoji: A text string containing an Emoji reference (e.g.
% ':bear:'), that Slack will use as the icon for the
% notification. Note that strIconURL and strIconEmoji
% should not both be provided.
%
% sAttachment: A Slack attachment structure, created by
% 'MakeSlackAttachment'. Multiple attachments can be
% provided in a cell array.
%
% Uses components of:
% URLREAD2: http://www.mathworks.com/matlabcentral/fileexchange/35693-urlread2
% JSONLAB: http://www.mathworks.com/matlabcentral/fileexchange/33381-jsonlab--a-toolbox-to-encode-decode-json-files-in-matlab-octave
%
% With thanks to Jim Hokanson and Qianqian Fang.
% Author: Dylan Muir <dylan.muir@unibas.ch>
% Created: 19th November, 2014
% -- Check arguments
if (nargin < 2)
help SendSlackNotification;
error('*** SendSlackNotification: Incorrect usage.');
end
% -- Create JSON payload structure
% - Set up payload
sPayload.text = strText;
% - Add target channel or user
if (exist('strTarget', 'var') && ~isempty(strTarget))
sPayload.channel = strTarget;
end
% - Define custom source user name
if (exist('strUsername', 'var') && ~isempty(strUsername))
sPayload.username = strUsername;
end
% - Define custom icon (URL)
if (exist('strIconURL', 'var') && ~isempty(strIconURL))
sPayload.icon_url = strIconURL;
end
% - Define custom icon (emoji)
if (exist('strIconEmoji', 'var') && ~isempty(strIconEmoji))
sPayload.icon_emoji = strIconEmoji;
end
% - Add attachments
if (exist('csAttachments', 'var') && ~isempty(csAttachments))
% - Accept a single attachment as a simple structure
if (~iscell(csAttachments))
csAttachments = {csAttachments};
end
% - Add a dummy attachment, if necessary (to ensure proper JSON
% formatting)
if (numel(csAttachments) == 1)
csAttachments = [csAttachments MakeSlackAttachment('')];
end
% - Include the attachments
sPayload.attachments = csAttachments;
end
% -- Translate to JSON
opt.NoRowBracket = 1;
strJSON = savejson('', sPayload, opt);
% -- Send to Slack using POST to the hook URL
[strHTTPOutput, sHTTPExtra] = urlread2(strHookURL, 'POST', strJSON);
% --- END of SendSlackNotification.m ---
@@ -0,0 +1,6 @@
# List of to-do items #
- [ ] Add support for ```multipart/form``` uploads via ```urlread2```.
- [ ] Add support for token-based authentication. Caching of auth token?
- [ ] Add support for posting files via [```files.upload```](https://api.slack.com/methods/files.upload) API.
- [ ] Add support for OAuth2 authentication.
@@ -0,0 +1,336 @@
===============================================================================
= JSONlab =
= An open-source MATLAB/Octave JSON encoder and decoder =
===============================================================================
*Copyright (c) 2011-2014 Qianqian Fang <fangq at nmr.mgh.harvard.edu>
*License: Simplified BSD License
*Version: 1.0.0-RC1 (Optimus - RC1)
-------------------------------------------------------------------------------
Table of Content:
I. Introduction
II. Installation
III.Using JSONlab
IV. Known Issues and TODOs
V. Contribution and feedback
-------------------------------------------------------------------------------
I. Introduction
JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable,
human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format
to represent complex and hierarchical data. It is as powerful as
[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely
used for data-exchange in applications, and is essential for the wild success
of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and
[http://en.wikipedia.org/wiki/Web_2.0 Web2.0].
UBJSON (Universal Binary JSON) is a binary JSON format, specifically
optimized for compact file size and better performance while keeping
the semantics as simple as the text-based JSON format. Using the UBJSON
format allows to wrap complex binary data in a flexible and extensible
structure, making it possible to process complex and large dataset
without accuracy loss due to text conversions.
We envision that both JSON and its binary version will serve as part of
the mainstream data-exchange formats for scientific research in the future.
It will provide the flexibility and generality achieved by other popular
general-purpose file specifications, such as
[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly
reduced complexity and enhanced performance.
JSONlab is a free and open-source implementation of a JSON/UBJSON encoder
and a decoder in the native MATLAB language. It can be used to convert a MATLAB
data structure (array, struct, cell, struct array and cell array) into
JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB
data structure. JSONlab supports both MATLAB and
[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
-------------------------------------------------------------------------------
II. Installation
The installation of JSONlab is no different than any other simple
MATLAB toolbox. You only need to download/unzip the JSONlab package
to a folder, and add the folder's path to MATLAB/Octave's path list
by using the following command:
addpath('/path/to/jsonlab');
If you want to add this path permanently, you need to type "pathtool",
browse to the jsonlab root folder and add to the list, then click "Save".
Then, run "rehash" in MATLAB, and type "which loadjson", if you see an
output, that means JSONlab is installed for MATLAB/Octave.
-------------------------------------------------------------------------------
III.Using JSONlab
JSONlab provides two functions, loadjson.m -- a MATLAB->JSON decoder,
and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and
two equivallent functions -- loadubjson and saveubjson for the binary
JSON. The detailed help info for the four functions can be found below:
=== loadjson.m ===
<pre>
data=loadjson(fname,opt)
or
data=loadjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
date: 2011/09/09
Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
date: 2009/11/02
François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
date: 2009/03/22
Joel Feenstra:
http://www.mathworks.com/matlabcentral/fileexchange/20565
date: 2008/07/03
$Id: loadjson.m 437 2014-09-15 18:59:36Z fangq $
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a JSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs. The param string is equivallent
to a field in opt.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
</pre>
=== savejson.m ===
<pre>
json=savejson(rootname,obj,filename)
or
json=savejson(rootname,obj,opt)
json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
Object Notation) string
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2011/09/09
$Id: savejson.m 439 2014-09-17 05:31:08Z fangq $
input:
rootname: name of the root-object, if set to '', will use variable name
obj: a MATLAB object (array, cell, cell array, struct, struct array)
filename: a string for the file name to save the output JSON data
opt: a struct for additional options, use [] if all use default
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.FloatFormat ['%.10g'|string]: format to show each numeric element
of a 1D/2D array;
opt.ArrayIndent [1|0]: if 1, output explicit data array with
precedent indentation; if 0, no indentation
opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
array in JSON array format; if sets to 1, an
array will be shown as a struct with fields
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
sparse arrays, the non-zero elements will be
saved to _ArrayData_ field in triplet-format i.e.
(ix,iy,val) and "_ArrayIsSparse_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [0|1]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
numerical element will be shown without a square
bracket, unless it is the root object; if 0, square
brackets are forced for any numerical arrays.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
will use the name of the passed obj variable as the
root object name; if obj is an expression and
does not have a name, 'root' will be used; if this
is set to 0 and rootname is empty, the root level
will be merged down to the lower level.
opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
to represent +/-Inf. The matched pattern is '([-+]*)Inf'
and $1 represents the sign. For those who want to use
1e999 to represent Inf, they can set opt.Inf to '$11e999'
opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
to represent NaN
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSON='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
opt can be replaced by a list of ('param',value) pairs. The param
string is equivallent to a field in opt.
output:
json: a string in the JSON format (see http://json.org)
examples:
a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
savejson('mesh',a)
savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
</pre>
=== loadubjson.m ===
<pre>
data=loadubjson(fname,opt)
or
data=loadubjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
date: 2013/08/01
$Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a UBJSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs. The param string is equivallent
to a field in opt.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
</pre>
=== saveubjson.m ===
<pre>
json=saveubjson(rootname,obj,filename)
or
json=saveubjson(rootname,obj,opt)
json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a Universal
Binary JSON (UBJSON) binary string
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2013/08/17
$Id: saveubjson.m 439 2014-09-17 05:31:08Z fangq $
input:
rootname: name of the root-object, if set to '', will use variable name
obj: a MATLAB object (array, cell, cell array, struct, struct array)
filename: a string for the file name to save the output JSON data
opt: a struct for additional options, use [] if all use default
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
array in JSON array format; if sets to 1, an
array will be shown as a struct with fields
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
sparse arrays, the non-zero elements will be
saved to _ArrayData_ field in triplet-format i.e.
(ix,iy,val) and "_ArrayIsSparse_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [1|0]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
numerical element will be shown without a square
bracket, unless it is the root object; if 0, square
brackets are forced for any numerical arrays.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
will use the name of the passed obj variable as the
root object name; if obj is an expression and
does not have a name, 'root' will be used; if this
is set to 0 and rootname is empty, the root level
will be merged down to the lower level.
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSON='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt can be replaced by a list of ('param',value) pairs. The param
string is equivallent to a field in opt.
output:
json: a string in the JSON format (see http://json.org)
examples:
a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
saveubjson('mesh',a)
saveubjson('mesh',a,'meshdata.ubj')
</pre>
=== examples ===
Under the "examples" folder, you can find several scripts to demonstrate the
basic utilities of JSONlab. Running the "demo_jsonlab_basic.m" script, you
will see the conversions from MATLAB data structure to JSON text and backward.
In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
and validate the loadjson/savejson functions for regression testing purposes.
Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
and loadubjson pairs for various matlab data structures.
Please run these examples and understand how JSONlab works before you use
it to process your data.
-------------------------------------------------------------------------------
IV. Known Issues and TODOs
JSONlab has several known limitations. We are striving to make it more general
and robust. Hopefully in a few future releases, the limitations become less.
Here are the known issues:
# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
# When processing names containing multi-byte characters, Octave and MATLAB \
can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
in MATLAB to get consistant results
# Can not handle classes.
# saveubjson has not yet supported arbitrary data ([H] in the UBJSON specification)
# saveubjson now converts a logical array into a uint8 ([U]) array for now
# an unofficial N-D array count syntax is implemented in saveubjson. We are \
actively communicating with the UBJSON spec maintainer to investigate the \
possibility of making it upstream
-------------------------------------------------------------------------------
V. Contribution and feedback
JSONlab is an open-source project. This means you can not only use it and modify
it as you wish, but also you can contribute your changes back to JSONlab so
that everyone else can enjoy the improvement. For anyone who want to contribute,
please download JSONlab source code from it's subversion repository by using the
following command:
svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
You can make changes to the files as needed. Once you are satisfied with your
changes, and ready to share it with others, please cd the root directory of
JSONlab, and type
svn diff > yourname_featurename.patch
You then email the .patch file to JSONlab's maintainer, Qianqian Fang, at
the email address shown in the beginning of this file. Qianqian will review
the changes and commit it to the subversion if they are satisfactory.
We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
mailing list to report any questions you may have with JSONlab:
http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
(Subscription to the mailing list is needed in order to post messages).
@@ -0,0 +1,11 @@
function header = http_createHeader(name,value)
%http_createHeader Simple function for creating input header to urlread2
%
% header = http_createHeader(name,value)
%
% CODE: header = struct('name',name,'value',value);
%
% See Also:
% urlread2
header = struct('name',name,'value',value);
@@ -0,0 +1,62 @@
function [str,header] = http_paramsToString(params,encodeOption)
%http_paramsToString Creates string for a POST or GET requests
%
% [queryString,header] = http_paramsToString(params, *encodeOption)
%
% INPUTS
% =======================================================================
% params: cell array of property/value pairs
% NOTE: If the input is in a 2 column matrix, then first column
% entries are properties and the second column entries are
% values, however this is NOT necessary (generally linear)
% encodeOption: (default 1)
% 1 - the typical URL encoding scheme (Java call)
%
% OUTPUTS
% =======================================================================
% queryString: querystring to add onto URL (LACKS "?", see example)
% header : the header that should be attached for post requests when
% using urlread2
%
% EXAMPLE:
% ==============================================================
% params = {'cmd' 'search' 'db' 'pubmed' 'term' 'wtf batman'};
% queryString = http_paramsToString(params);
% queryString => cmd=search&db=pubmed&term=wtf+batman
%
% IMPORTANT: This function does not filter parameters, sort them,
% or remove empty inputs (if necessary), this must be done before hand
if ~exist('encodeOption','var')
encodeOption = 1;
end
if size(params,2) == 2 && size(params,1) > 1
params = params';
params = params(:);
end
str = '';
for i=1:2:length(params)
if (i == 1), separator = ''; else separator = '&'; end
switch encodeOption
case 1
param = urlencode(params{i});
value = urlencode(params{i+1});
% case 2
% param = oauth.percentEncodeString(params{i});
% value = oauth.percentEncodeString(params{i+1});
% header = http_getContentTypeHeader(1);
otherwise
error('Case not used')
end
str = [str separator param '=' value]; %#ok<AGROW>
end
switch encodeOption
case 1
header = http_createHeader('Content-Type','application/x-www-form-urlencoded');
end
end
@@ -0,0 +1,32 @@
function val=jsonopt(key,default,varargin)
%
% val=jsonopt(key,default,optstruct)
%
% setting options based on a struct. The struct can be produced
% by varargin2struct from a list of 'param','value' pairs
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
%
% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
%
% input:
% key: a string with which one look up a value from a struct
% default: if the key does not exist, return default
% optstruct: a struct where each sub-field is a key
%
% output:
% val: if key exists, val=optstruct.key; otherwise val=default
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
val=default;
if(nargin<=2) return; end
opt=varargin{1};
if(isstruct(opt) && isfield(opt,key))
val=getfield(opt,key);
end
@@ -0,0 +1,515 @@
function data = loadjson(fname,varargin)
%
% data=loadjson(fname,opt)
% or
% data=loadjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2011/09/09
% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
% date: 2009/11/02
% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
% date: 2009/03/22
% Joel Feenstra:
% http://www.mathworks.com/matlabcentral/fileexchange/20565
% date: 2008/07/03
%
% $Id: loadjson.m 437 2014-09-15 18:59:36Z fangq $
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a JSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs. The param string is equivallent
% to a field in opt.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
global pos inStr len esc index_esc len_esc isoct arraytoken
if(regexp(fname,'[\{\}\]\[]','once'))
string=fname;
elseif(exist(fname,'file'))
fid = fopen(fname,'rb');
string = fread(fid,inf,'uint8=>char')';
fclose(fid);
else
error('input file does not exist');
end
pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
opt=varargin2struct(varargin{:});
jsoncount=1;
while pos <= len
switch(next_char)
case '{'
data{jsoncount} = parse_object(opt);
case '['
data{jsoncount} = parse_array(opt);
otherwise
error_pos('Outer level structure must be an object or an array');
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
if(~isempty(data))
if(isstruct(data)) % data can be a struct array
data=jstruct2array(data);
elseif(iscell(data))
data=jcell2array(data);
end
end
%%
function newdata=jcell2array(data)
len=length(data);
newdata=data;
for i=1:len
if(isstruct(data{i}))
newdata{i}=jstruct2array(data{i});
elseif(iscell(data{i}))
newdata{i}=jcell2array(data{i});
end
end
%%-------------------------------------------------------------------------
function newdata=jstruct2array(data)
fn=fieldnames(data);
newdata=data;
len=length(data);
for i=1:length(fn) % depth-first
for j=1:len
if(isstruct(getfield(data(j),fn{i})))
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
end
end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
newdata=cell(len,1);
for j=1:len
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
iscpx=0;
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
if(data(j).x0x5F_ArrayIsComplex_)
iscpx=1;
end
end
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
if(data(j).x0x5F_ArrayIsSparse_)
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
dim=data(j).x0x5F_ArraySize_;
if(iscpx && size(ndata,2)==4-any(dim==1))
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
end
if isempty(ndata)
% All-zeros sparse
ndata=sparse(dim(1),prod(dim(2:end)));
elseif dim(1)==1
% Sparse row vector
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
elseif dim(2)==1
% Sparse column vector
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
else
% Generic sparse array.
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
end
else
if(iscpx && size(ndata,2)==4)
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
end
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
end
end
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
if(iscpx && size(ndata,2)==2)
ndata=complex(ndata(:,1),ndata(:,2));
end
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
end
newdata{j}=ndata;
end
if(len==1)
newdata=newdata{1};
end
end
%%-------------------------------------------------------------------------
function object = parse_object(varargin)
parse_char('{');
object = [];
if next_char ~= '}'
while 1
str = parseStr(varargin{:});
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
parse_char(':');
val = parse_value(varargin{:});
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
if next_char == '}'
break;
end
parse_char(',');
end
end
parse_char('}');
%%-------------------------------------------------------------------------
function object = parse_array(varargin) % JSON array is written in row-major order
global pos inStr isoct
parse_char('[');
object = cell(0, 1);
dim2=[];
if next_char ~= ']'
[endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
arraystr=['[' inStr(pos:endpos)];
arraystr=regexprep(arraystr,'"_NaN_"','NaN');
arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
arraystr(arraystr==sprintf('\n'))=[];
arraystr(arraystr==sprintf('\r'))=[];
%arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
astr=inStr((e1l+1):(e1r-1));
astr=regexprep(astr,'"_NaN_"','NaN');
astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
astr(astr==sprintf('\n'))=[];
astr(astr==sprintf('\r'))=[];
astr(astr==' ')='';
if(isempty(find(astr=='[', 1))) % array is 2D
dim2=length(sscanf(astr,'%f,',[1 inf]));
end
else % array is 1D
astr=arraystr(2:end-1);
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
if(nextidx>=length(astr)-1)
object=obj;
pos=endpos;
parse_char(']');
return;
end
end
if(~isempty(dim2))
astr=arraystr;
astr(astr=='[')='';
astr(astr==']')='';
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
if(nextidx>=length(astr)-1)
object=reshape(obj,dim2,numel(obj)/dim2)';
pos=endpos;
parse_char(']');
return;
end
end
arraystr=regexprep(arraystr,'\]\s*,','];');
try
if(isoct && regexp(arraystr,'"','once'))
error('Octave eval can produce empty cells for JSON-like input');
end
object=eval(arraystr);
pos=endpos;
catch
while 1
val = parse_value(varargin{:});
object{end+1} = val;
if next_char == ']'
break;
end
parse_char(',');
end
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ndims(object)==2)
object=object';
end
catch
end
end
parse_char(']');
%%-------------------------------------------------------------------------
function parse_char(c)
global pos inStr len
skip_whitespace;
if pos > len || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
%%-------------------------------------------------------------------------
function c = next_char
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function skip_whitespace
global pos inStr len
while pos <= len && isspace(inStr(pos))
pos = pos + 1;
end
%%-------------------------------------------------------------------------
function str = parseStr(varargin)
global pos inStr len esc index_esc len_esc
% len, ns = length(inStr), keyboard
if inStr(pos) ~= '"'
error_pos('String starting with " expected at position %d');
else
pos = pos + 1;
end
str = '';
while pos <= len
while index_esc <= len_esc && esc(index_esc) < pos
index_esc = index_esc + 1;
end
if index_esc > len_esc
str = [str inStr(pos:len)];
pos = len + 1;
break;
else
str = [str inStr(pos:esc(index_esc)-1)];
pos = esc(index_esc);
end
nstr = length(str); switch inStr(pos)
case '"'
pos = pos + 1;
if(~isempty(str))
if(strcmp(str,'_Inf_'))
str=Inf;
elseif(strcmp(str,'-_Inf_'))
str=-Inf;
elseif(strcmp(str,'_NaN_'))
str=NaN;
end
end
return;
case '\'
if pos+1 > len
error_pos('End of file reached right after escape character');
end
pos = pos + 1;
switch inStr(pos)
case {'"' '\' '/'}
str(nstr+1) = inStr(pos);
pos = pos + 1;
case {'b' 'f' 'n' 'r' 't'}
str(nstr+1) = sprintf(['\' inStr(pos)]);
pos = pos + 1;
case 'u'
if pos+4 > len
error_pos('End of file reached in escaped unicode character');
end
str(nstr+(1:6)) = inStr(pos-1:pos+4);
pos = pos + 5;
end
otherwise % should never happen
str(nstr+1) = inStr(pos), keyboard
pos = pos + 1;
end
end
error_pos('End of file while expecting end of inStr');
%%-------------------------------------------------------------------------
function num = parse_number(varargin)
global pos inStr len isoct
currstr=inStr(pos:end);
numstr=0;
if(isoct~=0)
numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
[num, one] = sscanf(currstr, '%f', 1);
delta=numstr+1;
else
[num, one, err, delta] = sscanf(currstr, '%f', 1);
if ~isempty(err)
error_pos('Error reading number at position %d');
end
end
pos = pos + delta-1;
%%-------------------------------------------------------------------------
function val = parse_value(varargin)
global pos inStr len
true = 1; false = 0;
switch(inStr(pos))
case '"'
val = parseStr(varargin{:});
return;
case '['
val = parse_array(varargin{:});
return;
case '{'
val = parse_object(varargin{:});
if isstruct(val)
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
val=jstruct2array(val);
end
elseif isempty(val)
val = struct;
end
return;
case {'-','0','1','2','3','4','5','6','7','8','9'}
val = parse_number(varargin{:});
return;
case 't'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
val = true;
pos = pos + 4;
return;
end
case 'f'
if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
val = false;
pos = pos + 5;
return;
end
case 'n'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
val = [];
pos = pos + 4;
return;
end
end
error_pos('Value expected at position %d');
%%-------------------------------------------------------------------------
function error_pos(msg)
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos)) return; end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r)) e1r=bpos(pos); end
if(level==0)
endpos=bpos(pos);
return
end
end
if(c=='[')
if(isempty(e1l)) e1l=bpos(pos); end
level=level+1;
maxlevel=max(maxlevel,level);
end
if(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end
@@ -0,0 +1,512 @@
function data = loadubjson(fname,varargin)
%
% data=loadubjson(fname,opt)
% or
% data=loadubjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2013/08/01
%
% $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a UBJSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs. The param string is equivallent
% to a field in opt.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian
if(regexp(fname,'[\{\}\]\[]','once'))
string=fname;
elseif(exist(fname,'file'))
fid = fopen(fname,'rb');
string = fread(fid,inf,'uint8=>char')';
fclose(fid);
else
error('input file does not exist');
end
pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
opt=varargin2struct(varargin{:});
fileendian=upper(jsonopt('IntEndian','B',opt));
[os,maxelem,systemendian]=computer;
jsoncount=1;
while pos <= len
switch(next_char)
case '{'
data{jsoncount} = parse_object(opt);
case '['
data{jsoncount} = parse_array(opt);
otherwise
error_pos('Outer level structure must be an object or an array');
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
if(~isempty(data))
if(isstruct(data)) % data can be a struct array
data=jstruct2array(data);
elseif(iscell(data))
data=jcell2array(data);
end
end
%%
function newdata=parse_collection(id,data,obj)
if(jsoncount>0 && exist('data','var'))
if(~iscell(data))
newdata=cell(1);
newdata{1}=data;
data=newdata;
end
end
%%
function newdata=jcell2array(data)
len=length(data);
newdata=data;
for i=1:len
if(isstruct(data{i}))
newdata{i}=jstruct2array(data{i});
elseif(iscell(data{i}))
newdata{i}=jcell2array(data{i});
end
end
%%-------------------------------------------------------------------------
function newdata=jstruct2array(data)
fn=fieldnames(data);
newdata=data;
len=length(data);
for i=1:length(fn) % depth-first
for j=1:len
if(isstruct(getfield(data(j),fn{i})))
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
end
end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
newdata=cell(len,1);
for j=1:len
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
iscpx=0;
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
if(data(j).x0x5F_ArrayIsComplex_)
iscpx=1;
end
end
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
if(data(j).x0x5F_ArrayIsSparse_)
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
dim=double(data(j).x0x5F_ArraySize_);
if(iscpx && size(ndata,2)==4-any(dim==1))
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
end
if isempty(ndata)
% All-zeros sparse
ndata=sparse(dim(1),prod(dim(2:end)));
elseif dim(1)==1
% Sparse row vector
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
elseif dim(2)==1
% Sparse column vector
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
else
% Generic sparse array.
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
end
else
if(iscpx && size(ndata,2)==4)
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
end
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
end
end
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
if(iscpx && size(ndata,2)==2)
ndata=complex(ndata(:,1),ndata(:,2));
end
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
end
newdata{j}=ndata;
end
if(len==1)
newdata=newdata{1};
end
end
%%-------------------------------------------------------------------------
function object = parse_object(varargin)
parse_char('{');
object = [];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1); % TODO
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
count=double(parse_number());
end
if next_char ~= '}'
num=0;
while 1
str = parseStr(varargin{:});
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
%parse_char(':');
val = parse_value(varargin{:});
num=num+1;
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
if next_char == '}' || (count>=0 && num>=count)
break;
end
%parse_char(',');
end
end
if(count==-1)
parse_char('}');
end
%%-------------------------------------------------------------------------
function [cid,len]=elem_info(type)
id=strfind('iUIlLdD',type);
dataclass={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
if(id>0)
cid=dataclass{id};
len=bytelen(id);
else
error_pos('unsupported type at position %d');
end
%%-------------------------------------------------------------------------
function [data adv]=parse_block(type,count,varargin)
global pos inStr isoct fileendian systemendian
[cid,len]=elem_info(type);
datastr=inStr(pos:pos+len*count-1);
if(isoct)
newdata=int8(datastr);
else
newdata=uint8(datastr);
end
id=strfind('iUIlLdD',type);
if(id<=5 && fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,cid));
end
data=typecast(newdata,cid);
adv=double(len*count);
%%-------------------------------------------------------------------------
function object = parse_array(varargin) % JSON array is written in row-major order
global pos inStr isoct
parse_char('[');
object = cell(0, 1);
dim=[];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1);
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
if(next_char=='[')
dim=parse_array(varargin{:});
count=prod(double(dim));
else
count=double(parse_number());
end
end
if(~isempty(type))
if(count>=0)
[object adv]=parse_block(type,count,varargin{:});
if(~isempty(dim))
object=reshape(object,dim);
end
pos=pos+adv;
return;
else
endpos=matching_bracket(inStr,pos);
[cid,len]=elem_info(type);
count=(endpos-pos)/len;
[object adv]=parse_block(type,count,varargin{:});
pos=pos+adv;
parse_char(']');
return;
end
end
if next_char ~= ']'
while 1
val = parse_value(varargin{:});
object{end+1} = val;
if next_char == ']'
break;
end
%parse_char(',');
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ndims(object)==2)
object=object';
end
catch
end
end
if(count==-1)
parse_char(']');
end
%%-------------------------------------------------------------------------
function parse_char(c)
global pos inStr len
skip_whitespace;
if pos > len || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
%%-------------------------------------------------------------------------
function c = next_char
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function skip_whitespace
global pos inStr len
while pos <= len && isspace(inStr(pos))
pos = pos + 1;
end
%%-------------------------------------------------------------------------
function str = parseStr(varargin)
global pos inStr esc index_esc len_esc
% len, ns = length(inStr), keyboard
type=inStr(pos);
if type ~= 'S' && type ~= 'C' && type ~= 'H'
error_pos('String starting with S expected at position %d');
else
pos = pos + 1;
end
if(type == 'C')
str=inStr(pos);
pos=pos+1;
return;
end
bytelen=double(parse_number());
if(length(inStr)>=pos+bytelen-1)
str=inStr(pos:pos+bytelen-1);
pos=pos+bytelen;
else
error_pos('End of file while expecting end of inStr');
end
%%-------------------------------------------------------------------------
function num = parse_number(varargin)
global pos inStr len isoct fileendian systemendian
id=strfind('iUIlLdD',inStr(pos));
if(isempty(id))
error_pos('expecting a number at position %d');
end
type={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
datastr=inStr(pos+1:pos+bytelen(id));
if(isoct)
newdata=int8(datastr);
else
newdata=uint8(datastr);
end
if(id<=5 && fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,type{id}));
end
num=typecast(newdata,type{id});
pos = pos + bytelen(id)+1;
%%-------------------------------------------------------------------------
function val = parse_value(varargin)
global pos inStr len
true = 1; false = 0;
switch(inStr(pos))
case {'S','C','H'}
val = parseStr(varargin{:});
return;
case '['
val = parse_array(varargin{:});
return;
case '{'
val = parse_object(varargin{:});
if isstruct(val)
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
val=jstruct2array(val);
end
elseif isempty(val)
val = struct;
end
return;
case {'i','U','I','l','L','d','D'}
val = parse_number(varargin{:});
return;
case 'T'
val = true;
pos = pos + 1;
return;
case 'F'
val = false;
pos = pos + 1;
return;
case {'Z','N'}
val = [];
pos = pos + 1;
return;
end
error_pos('Value expected at position %d');
%%-------------------------------------------------------------------------
function error_pos(msg)
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos)) return; end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r)) e1r=bpos(pos); end
if(level==0)
endpos=bpos(pos);
return
end
end
if(c=='[')
if(isempty(e1l)) e1l=bpos(pos); end
level=level+1;
maxlevel=max(maxlevel,level);
end
if(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end
@@ -0,0 +1,33 @@
function s=mergestruct(s1,s2)
%
% s=mergestruct(s1,s2)
%
% merge two struct objects into one
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2012/12/22
%
% input:
% s1,s2: a struct object, s1 and s2 can not be arrays
%
% output:
% s: the merged struct object. fields in s1 and s2 will be combined in s.
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(~isstruct(s1) || ~isstruct(s2))
error('input parameters contain non-struct');
end
if(length(s1)>1 || length(s2)>1)
error('can not merge struct arrays');
end
fn=fieldnames(s2);
s=s1;
for i=1:length(fn)
s=setfield(s,fn{i},getfield(s2,fn{i}));
end
@@ -0,0 +1,433 @@
function json=savejson(rootname,obj,varargin)
%
% json=savejson(rootname,obj,filename)
% or
% json=savejson(rootname,obj,opt)
% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
% Object Notation) string
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2011/09/09
%
% $Id: savejson.m 439 2014-09-17 05:31:08Z fangq $
%
% input:
% rootname: name of the root-object, if set to '', will use variable name
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
% filename: a string for the file name to save the output JSON data
% opt: a struct for additional options, use [] if all use default
% opt can have the following fields (first in [.|.] is the default)
%
% opt.FileName [''|string]: a file name to save the output JSON data
% opt.FloatFormat ['%.10g'|string]: format to show each numeric element
% of a 1D/2D array;
% opt.ArrayIndent [1|0]: if 1, output explicit data array with
% precedent indentation; if 0, no indentation
% opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
% array in JSON array format; if sets to 1, an
% array will be shown as a struct with fields
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
% sparse arrays, the non-zero elements will be
% saved to _ArrayData_ field in triplet-format i.e.
% (ix,iy,val) and "_ArrayIsSparse_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [0|1]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
% numerical element will be shown without a square
% bracket, unless it is the root object; if 0, square
% brackets are forced for any numerical arrays.
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
% will use the name of the passed obj variable as the
% root object name; if obj is an expression and
% does not have a name, 'root' will be used; if this
% is set to 0 and rootname is empty, the root level
% will be merged down to the lower level.
% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
% to represent +/-Inf. The matched pattern is '([-+]*)Inf'
% and $1 represents the sign. For those who want to use
% 1e999 to represent Inf, they can set opt.Inf to '$11e999'
% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
% to represent NaN
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
% for example, if opt.JSON='foo', the JSON data is
% wrapped inside a function call as 'foo(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
% opt can be replaced by a list of ('param',value) pairs. The param
% string is equivallent to a field in opt.
% output:
% json: a string in the JSON format (see http://json.org)
%
% examples:
% a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
% 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
% savejson('mesh',a)
% savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(nargin==1)
varname=inputname(1);
obj=rootname;
if(isempty(varname))
varname='root';
end
rootname=varname;
else
varname=inputname(2);
end
if(length(varargin)==1 && ischar(varargin{1}))
opt=struct('FileName',varargin{1});
else
opt=varargin2struct(varargin{:});
end
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
rootisarray=0;
rootlevel=1;
forceroot=jsonopt('ForceRootName',0,opt);
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
rootisarray=1;
rootlevel=0;
else
if(isempty(rootname))
rootname=varname;
end
end
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
rootname='root';
end
json=obj2json(rootname,obj,rootlevel,opt);
if(rootisarray)
json=sprintf('%s\n',json);
else
json=sprintf('{\n%s\n}\n',json);
end
jsonp=jsonopt('JSONP','',opt);
if(~isempty(jsonp))
json=sprintf('%s(%s);\n',jsonp,json);
end
% save to a file if FileName is set, suggested by Patrick Rapin
if(~isempty(jsonopt('FileName','',opt)))
if(jsonopt('SaveBinary',0,opt)==1)
fid = fopen(opt.FileName, 'wb');
fwrite(fid,json);
else
fid = fopen(opt.FileName, 'wt');
fwrite(fid,json,'char');
end
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2json(name,item,level,varargin)
if(iscell(item))
txt=cell2json(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2json(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2json(name,item,level,varargin{:});
else
txt=mat2json(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2json(name,item,level,varargin)
txt='';
if(~iscell(item))
error('input is not a cell');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
padding0=repmat(sprintf('\t'),1,level);
padding2=repmat(sprintf('\t'),1,level+1);
if(len>1)
if(~isempty(name))
txt=sprintf('%s"%s": [\n',padding0, checkname(name,varargin{:})); name='';
else
txt=sprintf('%s[\n',padding0);
end
elseif(len==0)
if(~isempty(name))
txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name='';
else
txt=sprintf('%s[]',padding0);
end
end
for j=1:dim(2)
if(dim(1)>1) txt=sprintf('%s%s[\n',txt,padding2); end
for i=1:dim(1)
txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
end
if(dim(1)>1) txt=sprintf('%s\n%s]',txt,padding2); end
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
%if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
end
if(len>1) txt=sprintf('%s\n%s]',txt,padding0); end
%%-------------------------------------------------------------------------
function txt=struct2json(name,item,level,varargin)
txt='';
if(~isstruct(item))
error('input is not a struct');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
padding0=repmat(sprintf('\t'),1,level);
padding2=repmat(sprintf('\t'),1,level+1);
if(~isempty(name))
if(len>1) txt=sprintf('%s"%s": [\n',padding0,checkname(name,varargin{:})); end
else
if(len>1) txt=sprintf('%s[\n',padding0); end
end
for j=1:dim(2)
if(dim(1)>1) txt=sprintf('%s%s[\n',txt,padding2); end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1)
txt=sprintf('%s%s"%s": {\n',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)), checkname(name,varargin{:}));
else
txt=sprintf('%s%s{\n',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)));
end
if(~isempty(names))
for e=1:length(names)
txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
if(e<length(names)) txt=sprintf('%s%s',txt,','); end
txt=sprintf('%s%s',txt,sprintf('\n'));
end
end
txt=sprintf('%s%s}',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)));
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
end
if(dim(1)>1) txt=sprintf('%s\n%s]',txt,padding2); end
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
end
if(len>1) txt=sprintf('%s\n%s]',txt,padding0); end
%%-------------------------------------------------------------------------
function txt=str2json(name,item,level,varargin)
txt='';
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
sep=sprintf(',\n');
padding1=repmat(sprintf('\t'),1,level);
padding0=repmat(sprintf('\t'),1,level+1);
if(~isempty(name))
if(len>1) txt=sprintf('%s"%s": [\n',padding1,checkname(name,varargin{:})); end
else
if(len>1) txt=sprintf('%s[\n',padding1); end
end
isoct=jsonopt('IsOctave',0,varargin{:});
for e=1:len
if(isoct)
val=regexprep(item(e,:),'\\','\\');
val=regexprep(val,'"','\"');
val=regexprep(val,'^"','\"');
else
val=regexprep(item(e,:),'\\','\\\\');
val=regexprep(val,'"','\\"');
val=regexprep(val,'^"','\\"');
end
val=escapejsonstring(val);
if(len==1)
obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
if(isempty(name)) obj=['"',val,'"']; end
txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level),obj);
else
txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level+1),['"',val,'"']);
end
if(e==len) sep=''; end
txt=sprintf('%s%s',txt,sep);
end
if(len>1) txt=sprintf('%s\n%s%s',txt,padding1,']'); end
%%-------------------------------------------------------------------------
function txt=mat2json(name,item,level,varargin)
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
padding1=repmat(sprintf('\t'),1,level);
padding0=repmat(sprintf('\t'),1,level+1);
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
if(isempty(name))
txt=sprintf('%s{\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',...
padding1,padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') );
else
txt=sprintf('%s"%s": {\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',...
padding1,checkname(name,varargin{:}),padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') );
end
else
if(isempty(name))
txt=sprintf('%s%s',padding1,matdata2json(item,level+1,varargin{:}));
else
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
else
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),matdata2json(item,level+1,varargin{:}));
end
end
return;
end
dataformat='%s%s%s%s%s';
if(issparse(item))
[ix,iy]=find(item);
data=full(item(find(item)));
if(~isreal(item))
data=[real(data(:)),imag(data(:))];
if(size(item,1)==1)
% Kludge to have data's 'transposedness' match item's.
% (Necessary for complex row vector handling below.)
data=data';
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n'));
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sprintf(',\n'));
if(size(item,1)==1)
% Row vector, store only column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([iy(:),data'],level+2,varargin{:}), sprintf('\n'));
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,data],level+2,varargin{:}), sprintf('\n'));
else
% General case, store row and column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,iy,data],level+2,varargin{:}), sprintf('\n'));
end
else
if(isreal(item))
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json(item(:)',level+2,varargin{:}), sprintf('\n'));
else
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n'));
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), sprintf('\n'));
end
end
txt=sprintf('%s%s%s',txt,padding1,'}');
%%-------------------------------------------------------------------------
function txt=matdata2json(mat,level,varargin)
if(size(mat,1)==1)
pre='';
post='';
level=level-1;
else
pre=sprintf('[\n');
post=sprintf('\n%s]',repmat(sprintf('\t'),1,level-1));
end
if(isempty(mat))
txt='null';
return;
end
floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
%if(numel(mat)>1)
formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],\n')]];
%else
% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
%end
if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
formatstr=[repmat(sprintf('\t'),1,level) formatstr];
end
txt=sprintf(formatstr,mat');
txt(end-1:end)=[];
if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
txt=regexprep(txt,'1','true');
txt=regexprep(txt,'0','false');
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],\n['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
txt=[pre txt post];
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos)) return; end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function newstr=escapejsonstring(str)
newstr=str;
isoct=exist('OCTAVE_VERSION','builtin');
if(isoct)
vv=sscanf(OCTAVE_VERSION,'%f');
if(vv(1)>=3.8) isoct=0; end
end
if(isoct)
escapechars={'\a','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},escapechars{i});
end
else
escapechars={'\a','\b','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
end
end
@@ -0,0 +1,497 @@
function json=saveubjson(rootname,obj,varargin)
%
% json=saveubjson(rootname,obj,filename)
% or
% json=saveubjson(rootname,obj,opt)
% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a Universal
% Binary JSON (UBJSON) binary string
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2013/08/17
%
% $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
%
% input:
% rootname: name of the root-object, if set to '', will use variable name
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
% filename: a string for the file name to save the output JSON data
% opt: a struct for additional options, use [] if all use default
% opt can have the following fields (first in [.|.] is the default)
%
% opt.FileName [''|string]: a file name to save the output JSON data
% opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
% array in JSON array format; if sets to 1, an
% array will be shown as a struct with fields
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
% sparse arrays, the non-zero elements will be
% saved to _ArrayData_ field in triplet-format i.e.
% (ix,iy,val) and "_ArrayIsSparse_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [1|0]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
% numerical element will be shown without a square
% bracket, unless it is the root object; if 0, square
% brackets are forced for any numerical arrays.
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
% will use the name of the passed obj variable as the
% root object name; if obj is an expression and
% does not have a name, 'root' will be used; if this
% is set to 0 and rootname is empty, the root level
% will be merged down to the lower level.
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
% for example, if opt.JSON='foo', the JSON data is
% wrapped inside a function call as 'foo(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
% opt can be replaced by a list of ('param',value) pairs. The param
% string is equivallent to a field in opt.
% output:
% json: a string in the JSON format (see http://json.org)
%
% examples:
% a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
% 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
% saveubjson('mesh',a)
% saveubjson('mesh',a,'meshdata.ubj')
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(nargin==1)
varname=inputname(1);
obj=rootname;
if(isempty(varname))
varname='root';
end
rootname=varname;
else
varname=inputname(2);
end
if(length(varargin)==1 && ischar(varargin{1}))
opt=struct('FileName',varargin{1});
else
opt=varargin2struct(varargin{:});
end
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
rootisarray=0;
rootlevel=1;
forceroot=jsonopt('ForceRootName',0,opt);
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
rootisarray=1;
rootlevel=0;
else
if(isempty(rootname))
rootname=varname;
end
end
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
rootname='root';
end
json=obj2ubjson(rootname,obj,rootlevel,opt);
if(~rootisarray)
json=['{' json '}'];
end
jsonp=jsonopt('JSONP','',opt);
if(~isempty(jsonp))
json=[jsonp '(' json ')'];
end
% save to a file if FileName is set, suggested by Patrick Rapin
if(~isempty(jsonopt('FileName','',opt)))
fid = fopen(opt.FileName, 'wb');
fwrite(fid,json);
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2ubjson(name,item,level,varargin)
if(iscell(item))
txt=cell2ubjson(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2ubjson(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2ubjson(name,item,level,varargin{:});
else
txt=mat2ubjson(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2ubjson(name,item,level,varargin)
txt='';
if(~iscell(item))
error('input is not a cell');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item); % let's handle 1D cell first
if(len>1)
if(~isempty(name))
txt=[S_(checkname(name,varargin{:})) '[']; name='';
else
txt='[';
end
elseif(len==0)
if(~isempty(name))
txt=[S_(checkname(name,varargin{:})) 'Z']; name='';
else
txt='Z';
end
end
for j=1:dim(2)
if(dim(1)>1) txt=[txt '[']; end
for i=1:dim(1)
txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
end
if(dim(1)>1) txt=[txt ']']; end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=struct2ubjson(name,item,level,varargin)
txt='';
if(~isstruct(item))
error('input is not a struct');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
if(~isempty(name))
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
else
if(len>1) txt='['; end
end
for j=1:dim(2)
if(dim(1)>1) txt=[txt '[']; end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1)
txt=[txt S_(checkname(name,varargin{:})) '{'];
else
txt=[txt '{'];
end
if(~isempty(names))
for e=1:length(names)
txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
end
end
txt=[txt '}'];
end
if(dim(1)>1) txt=[txt ']']; end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=str2ubjson(name,item,level,varargin)
txt='';
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
if(~isempty(name))
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
else
if(len>1) txt='['; end
end
isoct=jsonopt('IsOctave',0,varargin{:});
for e=1:len
val=item(e,:);
if(len==1)
obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
if(isempty(name)) obj=['',S_(val),'']; end
txt=[txt,'',obj];
else
txt=[txt,'',['',S_(val),'']];
end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=mat2ubjson(name,item,level,varargin)
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
cid=I_(uint32(max(size(item))));
if(isempty(name))
txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
else
if(isempty(item))
txt=[S_(checkname(name,varargin{:})),'Z'];
return;
else
txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
end
end
else
if(isempty(name))
txt=matdata2ubjson(item,level+1,varargin{:});
else
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
txt=[S_(checkname(name,varargin{:})) numtxt];
else
txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
end
end
return;
end
if(issparse(item))
[ix,iy]=find(item);
data=full(item(find(item)));
if(~isreal(item))
data=[real(data(:)),imag(data(:))];
if(size(item,1)==1)
% Kludge to have data's 'transposedness' match item's.
% (Necessary for complex row vector handling below.)
data=data';
end
txt=[txt,S_('_ArrayIsComplex_'),'T'];
end
txt=[txt,S_('_ArrayIsSparse_'),'T'];
if(size(item,1)==1)
% Row vector, store only column indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([iy(:),data'],level+2,varargin{:})];
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([ix,data],level+2,varargin{:})];
else
% General case, store row and column indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([ix,iy,data],level+2,varargin{:})];
end
else
if(isreal(item))
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson(item(:)',level+2,varargin{:})];
else
txt=[txt,S_('_ArrayIsComplex_'),'T'];
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
end
end
txt=[txt,'}'];
%%-------------------------------------------------------------------------
function txt=matdata2ubjson(mat,level,varargin)
if(isempty(mat))
txt='Z';
return;
end
if(size(mat,1)==1)
level=level-1;
end
type='';
hasnegtive=(mat<0);
if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
if(isempty(hasnegtive))
if(max(mat(:))<=2^8)
type='U';
end
end
if(isempty(type))
% todo - need to consider negative ones separately
id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
if(isempty(find(id)))
error('high-precision data is not yet supported');
end
key='iIlL';
type=key(find(id));
end
txt=[I_a(mat(:),type,size(mat))];
elseif(islogical(mat))
logicalval='FT';
if(numel(mat)==1)
txt=logicalval(mat+1);
else
txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
end
else
if(numel(mat)==1)
txt=['[' D_(mat) ']'];
else
txt=D_a(mat(:),'D',size(mat));
end
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos)) return; end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function val=S_(str)
if(length(str)==1)
val=['C' str];
else
val=['S' I_(int32(length(str))) str];
end
%%-------------------------------------------------------------------------
function val=I_(num)
if(~isinteger(num))
error('input is not an integer');
end
if(num>=0 && num<255)
val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
return;
end
key='iIlL';
cid={'int8','int16','int32','int64'};
for i=1:4
if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
return;
end
end
error('unsupported integer');
%%-------------------------------------------------------------------------
function val=D_(num)
if(~isfloat(num))
error('input is not a float');
end
if(isa(num,'single'))
val=['d' data2byte(num,'uint8')];
else
val=['D' data2byte(num,'uint8')];
end
%%-------------------------------------------------------------------------
function data=I_a(num,type,dim,format)
id=find(ismember('iUIlL',type));
if(id==0)
error('unsupported integer array');
end
% based on UBJSON specs, all integer types are stored in big endian format
if(id==1)
data=data2byte(swapbytes(int8(num)),'uint8');
blen=1;
elseif(id==2)
data=data2byte(swapbytes(uint8(num)),'uint8');
blen=1;
elseif(id==3)
data=data2byte(swapbytes(int16(num)),'uint8');
blen=2;
elseif(id==4)
data=data2byte(swapbytes(int32(num)),'uint8');
blen=4;
elseif(id==5)
data=data2byte(swapbytes(int64(num)),'uint8');
blen=8;
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
end
data=['[' data(:)'];
else
data=reshape(data,blen,numel(data)/blen);
data(2:blen+1,:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function data=D_a(num,type,dim,format)
id=find(ismember('dD',type));
if(id==0)
error('unsupported float array');
end
if(id==1)
data=data2byte(single(num),'uint8');
elseif(id==2)
data=data2byte(double(num),'uint8');
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
end
data=['[' data];
else
data=reshape(data,(id*4),length(data)/(id*4));
data(2:(id*4+1),:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function bytes=data2byte(varargin)
bytes=typecast(varargin{:});
bytes=bytes(:)';
@@ -0,0 +1,371 @@
function [output,extras] = urlread2(urlChar,method,body,headersIn,varargin)
%urlread2 Makes HTTP requests and processes response
%
% [output,extras] = urlread2(urlChar, *method, *body, *headersIn, varargin)
%
% * indicates optional inputs that must be entered in place
%
% UNDOCUMENTED MATLAB VERSION
%
% EXAMPLE CALLING FORMS
% ... = urlread2(urlChar)
% ... = urlread2(urlChar,'GET','',[],prop1,value1,prop2,value2,etc)
% ... = urlread2(urlChar,'POST',body,headers)
%
% FEATURES
% =======================================================================
% 1) Allows specification of any HTTP method
% 2) Allows specification of any header. Very little is hard-coded
% in for header handling.
% 3) Returns response status and headers
% 4) Should handle unicode properly ...
%
% OUTPUTS
% =======================================================================
% output : body of the response, either text or binary depending upon
% CAST_OUTPUT property
% extras : (structure)
% .allHeaders - stucture, fields have cellstr values, HTTP headers may
% may be repeated but will have a single field entry, with each
% repeat's value another being another entry in the cellstr, for
% example:
% .Set_Cookie = {'first_value' 'second_value'}
% .firstHeaders - (structure), variable fields, contains the first
% string entry for each field in allHeaders, this
% structure can be used to avoid dereferencing a cell
% for fields you expect not to be repeated ...
% EXAMPLE:
% .Response : 'HTTP/1.1 200 OK'}
% .Server : 'nginx'
% .Date : 'Tue, 29 Nov 2011 02:23:16 GMT'
% .Content_Type : 'text/html; charset=UTF-8'
% .Content_Length : '109155'
% .Connection : 'keep-alive'
% .Vary : 'Accept-Encoding, User-Agent'
% .Cache_Control : 'max-age=60, private'
% .Set_Cookie : 'first_value'
% .status - (structure)
% .value : numeric value of status, ex. 200
% .msg : message that goes along with status, ex. 'OK'
% .url - eventual url that led to output, this can change from
% the input with redirects, see FOLLOW_REDIRECTS
% .isGood - (logical) I believe this is an indicator of the presence of 400
% or 500 status codes (see status.value) but more
% testing is needed. In other words, true if status.value < 400.
% In code, set true if the response was obtainable without
% resorting to checking the error stream.
%
% INPUTS
% =======================================================================
% urlChar : The full url, must include scheme (http, https)
% method : examples: 'GET' 'POST' etc
% body : (vector)(char, uint8 or int8) body to write, generally used
% with POST or PUT, use of uint8 or int8 ensures that the
% body input is not manipulated before sending, char is sent
% via unicode2native function with ENCODING input (see below)
% headersIn : (structure array), use empty [] or '' if no headers are needed
% but varargin property/value pairs are, multiple headers
% may be passed in as a structure array
% .name - (string), name of the header, a name property is used
% instead of a field because the name must match a valid
% header
% .value - (string), value to use
%
% OPTIONAL INPUTS (varargin, property/value pairs)
% =======================================================================
% CAST_OUTPUT : (default true) output is uint8, useful if the body
% of the response is not text
% ENCODING : (default ''), ENCODING input to function unicode2native
% FOLLOW_REDIRECTS : (default true), if false 3xx status codes will
% be returned and need to be handled by the user,
% note this does not handle javascript or meta tag
% redirects, just server based ones
% READ_TIMEOUT : (default 0), 0 means no timeout, value is in
% milliseconds
%
% EXAMPLES
% =======================================================================
% GET:
% --------------------------------------------
% url = 'http://www.mathworks.com/matlabcentral/fileexchange/';
% query = 'urlread2';
% params = {'term' query};
% queryString = http_paramsToString(params,1);
% url = [url '?' queryString];
% [output,extras] = urlread2(url);
%
% POST:
% --------------------------------------------
% url = 'http://posttestserver.com/post.php';
% params = {'testChars' char([2500 30000]) 'new code' '?'};
% [paramString,header] = http_paramsToString(params,1);
% [output,extras] = urlread2(url,'POST',paramString,header);
%
% From behind a firewall, use the Preferences to set your proxy server.
%
% See Also:
% http_paramsToString
% unicode2native
% native2unicode
%
% Subfunctions:
% fixHeaderCasing - small subfunction to fix case errors encountered in real
% world, requires updating when casing doesn't match expected form, like
% if someone sent the header content-Encoding instead of
% Content-Encoding
%
% Based on original urlread code by Matthew J. Simoneau
%
% VERSION = 1.1
in.CAST_OUTPUT = true;
in.FOLLOW_REDIRECTS = true;
in.READ_TIMEOUT = 0;
in.ENCODING = '';
%Input handling
%---------------------------------------
if ~isempty(varargin)
for i = 1:2:numel(varargin)
prop = upper(varargin{i});
value = varargin{i+1};
if isfield(in,prop)
in.(prop) = value;
else
error('Unrecognized input to function: %s',prop)
end
end
end
if ~exist('method','var') || isempty(method), method = 'GET'; end
if ~exist('body','var'), body = ''; end
if ~exist('headersIn','var'), headersIn = []; end
assert(usejava('jvm'),'Function requires Java')
import com.mathworks.mlwidgets.io.InterruptibleStreamCopier;
com.mathworks.mlwidgets.html.HTMLPrefs.setProxySettings %Proxy settings need to be set
%Create a urlConnection.
%-----------------------------------
urlConnection = getURLConnection(urlChar);
%For HTTP uses sun.net.www.protocol.http.HttpURLConnection
%Might use ice.net.HttpURLConnection but this has more overhead
%SETTING PROPERTIES
%-------------------------------------------------------
urlConnection.setRequestMethod(upper(method));
urlConnection.setFollowRedirects(in.FOLLOW_REDIRECTS);
urlConnection.setReadTimeout(in.READ_TIMEOUT);
for iHeader = 1:length(headersIn)
curHeader = headersIn(iHeader);
urlConnection.setRequestProperty(curHeader.name,curHeader.value);
end
if ~isempty(body)
%Ensure vector?
if size(body,1) > 1
if size(body,2) > 1
error('Input parameter to function: body, must be a vector')
else
body = body';
end
end
if ischar(body)
%NOTE: '' defaults to Matlab's default encoding scheme
body = unicode2native(body,in.ENCODING);
elseif ~(strcmp(class(body),'uint8') || strcmp(class(body),'int8'))
error('Function input: body, should be of class char, uint8, or int8, detected: %s',class(body))
end
urlConnection.setRequestProperty('Content-Length',int2str(length(body)));
urlConnection.setDoOutput(true);
outputStream = urlConnection.getOutputStream;
outputStream.write(body);
outputStream.close;
else
urlConnection.setRequestProperty('Content-Length','0');
end
%==========================================================================
% Read the data from the connection.
%==========================================================================
%This should be done first because it tells us if things are ok or not
%NOTE: If there is an error, functions below using urlConnection, notably
%getResponseCode, will fail as well
try
inputStream = urlConnection.getInputStream;
isGood = true;
catch ME
isGood = false;
%NOTE: HTTP error codes will throw an error here, we'll allow those for now
%We might also get another error in which case the inputStream will be
%undefined, those we will throw here
inputStream = urlConnection.getErrorStream;
if isempty(inputStream)
msg = ME.message;
I = strfind(msg,char([13 10 9])); %see example by setting timeout to 1
%Should remove the barf of the stack, at ... at ... at ... etc
%Likely that this could be improved ... (generate link with full msg)
if ~isempty(I)
msg = msg(1:I(1)-1);
end
fprintf(2,'Response stream is undefined\n below is a Java Error dump (truncated):\n');
error(msg)
end
end
%POPULATING HEADERS
%--------------------------------------------------------------------------
allHeaders = struct;
allHeaders.Response = {char(urlConnection.getHeaderField(0))};
done = false;
headerIndex = 0;
while ~done
headerIndex = headerIndex + 1;
headerValue = char(urlConnection.getHeaderField(headerIndex));
if ~isempty(headerValue)
headerName = char(urlConnection.getHeaderFieldKey(headerIndex));
headerName = fixHeaderCasing(headerName); %NOT YET FINISHED
%Important, for name safety all hyphens are replace with underscores
headerName(headerName == '-') = '_';
if isfield(allHeaders,headerName)
allHeaders.(headerName) = [allHeaders.(headerName) headerValue];
else
allHeaders.(headerName) = {headerValue};
end
else
done = true;
end
end
firstHeaders = struct;
fn = fieldnames(allHeaders);
for iHeader = 1:length(fn)
curField = fn{iHeader};
firstHeaders.(curField) = allHeaders.(curField){1};
end
status = struct(...
'value', urlConnection.getResponseCode(),...
'msg', char(urlConnection.getResponseMessage));
%PROCESSING OF OUTPUT
%----------------------------------------------------------
byteArrayOutputStream = java.io.ByteArrayOutputStream;
% This StreamCopier is unsupported and may change at any time. OH GREAT :/
isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
isc.copyStream(inputStream,byteArrayOutputStream);
inputStream.close;
byteArrayOutputStream.close;
if in.CAST_OUTPUT
charset = '';
%Extraction of character set from Content-Type header if possible
if isfield(firstHeaders,'Content_Type')
text = firstHeaders.Content_Type;
%Always open to regexp improvements
charset = regexp(text,'(?<=charset=)[^\s]*','match','once');
end
if ~isempty(charset)
output = native2unicode(typecast(byteArrayOutputStream.toByteArray','uint8'),charset);
else
output = char(typecast(byteArrayOutputStream.toByteArray','uint8'));
end
else
%uint8 is more useful for later charecter conversions
%uint8 or int8 is somewhat arbitary at this point
output = typecast(byteArrayOutputStream.toByteArray','uint8');
end
extras = struct;
extras.allHeaders = allHeaders;
extras.firstHeaders = firstHeaders;
extras.status = status;
%Gets eventual url even with redirection
extras.url = char(urlConnection.getURL);
extras.isGood = isGood;
end
function headerNameOut = fixHeaderCasing(headerName)
%fixHeaderCasing Forces standard casing of headers
%
% headerNameOut = fixHeaderCasing(headerName)
%
% This is important for field access in a structure which
% is case sensitive
%
% Not yet finished.
% I've been adding to this function as problems come along
switch lower(headerName)
case 'location'
headerNameOut = 'Location';
case 'content_type'
headerNameOut = 'Content_Type';
otherwise
headerNameOut = headerName;
end
end
%==========================================================================
%==========================================================================
%==========================================================================
function urlConnection = getURLConnection(urlChar)
%getURLConnection
%
% urlConnection = getURLConnection(urlChar)
% Determine the protocol (before the ":").
protocol = urlChar(1:find(urlChar==':',1)-1);
% Try to use the native handler, not the ice.* classes.
try
switch protocol
case 'http'
%http://www.docjar.com/docs/api/sun/net/www/protocol/http/HttpURLConnection.html
handler = sun.net.www.protocol.http.Handler;
case 'https'
handler = sun.net.www.protocol.https.Handler;
end
catch ME
handler = [];
end
% Create the URL object.
try
if isempty(handler)
url = java.net.URL(urlChar);
else
url = java.net.URL([],urlChar,handler);
end
catch ME
error('Failure to parse URL or protocol not supported for:\nURL: %s',urlChar);
end
% Get the proxy information using MathWorks facilities for unified proxy
% preference settings.
mwtcp = com.mathworks.net.transport.MWTransportClientPropertiesFactory.create();
proxy = mwtcp.getProxy();
% Open a connection to the URL.
if isempty(proxy)
urlConnection = url.openConnection;
else
urlConnection = url.openConnection(proxy);
end
end
@@ -0,0 +1,86 @@
==========================================================================
Unicode & Matlab
==========================================================================
native2unicode - works with uint8, fails with char
Taking a unicode character and encoding as bytes:
unicode2native(char(1002),'UTF-8')
back to the character:
native2unicode(uint8([207 170]),'UTF-8')
this doesn't work:
native2unicode(char([207 170]),'UTF-8')
in documentation: If BYTES is a CHAR vector, it is returned unchanged.
Java - only supports int8
Matlab to Java -> uint8 or int8 to bytes
Java to Matlab -> bytes to int8
char - 16 bit
Maintenance of underlying bytes:
typecast(java.lang.String(uint8(250)).getBytes,'uint8') = 250
see documentation: Handling Data Returned from a Java Method
Command Window difficulty
--------------------------------------------------------------------
The typical font in the Matlab command window will often fail to render
unicode properly. I often can see unicode better in the variable editor
although this may be fixed if you change your font preferences ...
Copying unicode from the command window often results in the
generations of the value 26 (aka substitute)
More documentation on input/output to urlread2 to follow eventually ...
small notes to self:
for output
native2unicode(uint8(output),encoding)
==========================================================================
HTTP Headers
==========================================================================
Handling of repeated http readers is a bit of a tricky situation. Most
headers are not repeated although sometimes http clients will assume this
for too many headers which can result in a problem if you want to see
duplicated headers. I've passed the problem onto the user who can decide
to handle it how they wish instead of providing the right solution, which
after some brief searching, I am not sure exists.
==========================================================================
PROBLEMS
==========================================================================
1) Page requires following a redirect:
%-------------------------------------------
ref: http://www.mathworks.com/matlabcentral/newsreader/view_thread/302571
fix: FOLLOW_REDIRECTS is enabled by default, you're fine.
2) Basic authentication required:
%------------------------------------------
Create and pass in the following header:
user = 'test';
password = 'test';
encoder = sun.misc.BASE64Encoder();
str = java.lang.String([user ':' password]) %NOTE: format may be
%different for your server
header = http_createHeader('Authorization',char(encoder.encode(str.getBytes())))
NOTE: Ideally you would make this a function
3) The text returned doesn't make sense.
%-----------------------------------------
The text may not be encoded correctly. Requires native2unicode function.
See Unicode & Matlab section above.
4) I get a different result in my web browser than I do in Matlab
%-----------------------------------------
This is generally seen for two reasons.
1 - The easiest and silly reason is user agent filtering.
When you make a request you identify yourself
as being a particular "broswer" or "user agent". Setting a header
with the user agent of the browser may fix the problem.
See: http://en.wikipedia.org/wiki/User_agent
See: http://whatsmyuseragent.com
value = ''
header = http_createHeader('User-Agent',value);
2 - You are not processing cookies and the server is not sending
you information because you haven't sent it cookies (everyone likes em!)
I've implemented cookie support but it requires some extra files that
I need to clean up. Feel free to email me if you'd really like to have them.
@@ -0,0 +1,40 @@
function opt=varargin2struct(varargin)
%
% opt=varargin2struct('param1',value1,'param2',value2,...)
% or
% opt=varargin2struct(...,optstruct,...)
%
% convert a series of input parameters into a structure
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2012/12/22
%
% input:
% 'param', value: the input parameters should be pairs of a string and a value
% optstruct: if a parameter is a struct, the fields will be merged to the output struct
%
% output:
% opt: a struct where opt.param1=value1, opt.param2=value2 ...
%
% license:
% Simplified BSD License
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
len=length(varargin);
opt=struct;
if(len==0) return; end
i=1;
while(i<=len)
if(isstruct(varargin{i}))
opt=mergestruct(opt,varargin{i});
elseif(ischar(varargin{i}) && i<len)
opt=setfield(opt,varargin{i},varargin{i+1});
i=i+1;
else
error('input must be in the form of ...,''name'',value,... pairs or structs');
end
i=i+1;
end
@@ -0,0 +1,63 @@
function [ClientResult] = TestClient_basic()
% profile('-memory','on');
% profile('on');
ClientResult = 0;
Instance = 'default';
dbstop if error
tic
%% slack
WebHook = 'https://hooks.slack.com/services/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'; % Use your KEY HOOK
message = strcat(Instance,': Start TestClient_basic');
SendSlackNotification(WebHook,message);
% load api to mtclient
MtApi_Dlls(1).path = 'C:\Program Files\MtApi5\MtApi5.dll';
MtApi_Dlls(1).name = 'Default';
MtApi_Dlls(1).version = '';
MtApi_Dlls(2).path = 'dll\MtApi5.dll ' ; % 1.021.1
MtApi_Dlls(2).name = 'dev_64';
MtApi_Dlls(2).version = '21.1';
client = Mt5Api(MtApi_Dlls(2).path);
client.init_Loggers('DEBUG','DEBUG',WebHook,Instance);
eTF = MtApi5.ENUM_TIMEFRAMES.PERIOD_M1;
chSymbol = 'EURUSD';
[ApiConnected, ~] = client.runOn(Instance);
if ~ApiConnected
exitCode = 5;
disp(['ExitCode :',num2str(exitCode)])
return;
end
[ok,EurUsd_Bars] = client.cTimeSeries.mCreateFilledBars(chSymbol,eTF,0,10000,int32(400000));
filename = sprintf('bars_%s_bytestream.mat',chSymbol);
% filestring = strcat(filepath,filename);
EurUsd_Bars.saveDataAsByteStream(filename);
res = dir(filename);
client.cLogger.debug('Bars Saved ');
client.cLogger.debug(sprintf('File name: %s',res.name));
client.cLogger.debug(sprintf('File size %s = %.2f kb ', chSymbol,res.bytes/1024));
ClientResult = 1;
toc
end
@@ -0,0 +1 @@
*.asv
@@ -0,0 +1,5 @@
function clearLogger(name)
[~, destructor] = logging.getLogger(name);
destructor();
end
@@ -0,0 +1,590 @@
function count = cprintf(style,format,varargin)
% CPRINTF displays styled formatted text in the Command Window
%
% Syntax:
% count = cprintf(style,format,...)
%
% Description:
% CPRINTF processes the specified text using the exact same FORMAT
% arguments accepted by the built-in SPRINTF and FPRINTF functions.
%
% CPRINTF then displays the text in the Command Window using the
% specified STYLE argument. The accepted styles are those used for
% Matlab's syntax highlighting (see: File / Preferences / Colors /
% M-file Syntax Highlighting Colors), and also user-defined colors.
%
% The possible pre-defined STYLE names are:
%
% 'Text' - default: black
% 'Keywords' - default: blue
% 'Comments' - default: green
% 'Strings' - default: purple
% 'UnterminatedStrings' - default: dark red
% 'SystemCommands' - default: orange
% 'Errors' - default: light red
% 'Hyperlinks' - default: underlined blue
%
% 'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White'
%
% STYLE beginning with '-' or '_' will be underlined. For example:
% '-Blue' is underlined blue, like 'Hyperlinks';
% '_Comments' is underlined green etc.
%
% STYLE beginning with '*' will be bold (R2011b+ only). For example:
% '*Blue' is bold blue;
% '*Comments' is bold green etc.
% Note: Matlab does not currently support both bold and underline,
% only one of them can be used in a single cprintf command. But of
% course bold and underline can be mixed by using separate commands.
%
% STYLE also accepts a regular Matlab RGB vector, that can be underlined
% and bolded: -[0,1,1] means underlined cyan, '*[1,0,0]' is bold red.
%
% STYLE is case-insensitive and accepts unique partial strings just
% like handle property names.
%
% CPRINTF by itself, without any input parameters, displays a demo
%
% Example:
% cprintf; % displays the demo
% cprintf('text', 'regular black text');
% cprintf('hyper', 'followed %s','by');
% cprintf('key', '%d colored', 4);
% cprintf('-comment','& underlined');
% cprintf('err', 'elements\n');
% cprintf('cyan', 'cyan');
% cprintf('_green', 'underlined green');
% cprintf(-[1,0,1], 'underlined magenta');
% cprintf([1,0.5,0],'and multi-\nline orange\n');
% cprintf('*blue', 'and *bold* (R2011b+ only)\n');
% cprintf('string'); % same as fprintf('string') and cprintf('text','string')
%
% Bugs and suggestions:
% Please send to Yair Altman (altmany at gmail dot com)
%
% Warning:
% This code heavily relies on undocumented and unsupported Matlab
% functionality. It works on Matlab 7+, but use at your own risk!
%
% A technical description of the implementation can be found at:
% <a href="http://undocumentedmatlab.com/blog/cprintf/">http://UndocumentedMatlab.com/blog/cprintf/</a>
%
% Limitations:
% 1. In R2011a and earlier, a single space char is inserted at the
% beginning of each CPRINTF text segment (this is ok in R2011b+).
%
% 2. In R2011a and earlier, consecutive differently-colored multi-line
% CPRINTFs sometimes display incorrectly on the bottom line.
% As far as I could tell this is due to a Matlab bug. Examples:
% >> cprintf('-str','under\nline'); cprintf('err','red\n'); % hidden 'red', unhidden '_'
% >> cprintf('str','regu\nlar'); cprintf('err','red\n'); % underline red (not purple) 'lar'
%
% 3. Sometimes, non newline ('\n')-terminated segments display unstyled
% (black) when the command prompt chevron ('>>') regains focus on the
% continuation of that line (I can't pinpoint when this happens).
% To fix this, simply newline-terminate all command-prompt messages.
%
% 4. In R2011b and later, the above errors appear to be fixed. However,
% the last character of an underlined segment is not underlined for
% some unknown reason (add an extra space character to make it look better)
%
% 5. In old Matlab versions (e.g., Matlab 7.1 R14), multi-line styles
% only affect the first line. Single-line styles work as expected.
% R14 also appends a single space after underlined segments.
%
% 6. Bold style is only supported on R2011b+, and cannot also be underlined.
%
% Change log:
% 2015-06-24: Fixed a few discoloration issues (some other issues still remain)
% 2015-03-20: Fix: if command window isn't defined yet (startup) use standard fprintf as suggested by John Marozas
% 2012-08-09: Graceful degradation support for deployed (compiled) and non-desktop applications; minor bug fixes
% 2012-08-06: Fixes for R2012b; added bold style; accept RGB string (non-numeric) style
% 2011-11-27: Fixes for R2011b
% 2011-08-29: Fix by Danilo (FEX comment) for non-default text colors
% 2011-03-04: Performance improvement
% 2010-06-27: Fix for R2010a/b; fixed edge case reported by Sharron; CPRINTF with no args runs the demo
% 2009-09-28: Fixed edge-case problem reported by Swagat K
% 2009-05-28: corrected nargout behavior suggested by Andreas Gb
% 2009-05-13: First version posted on <a href="http://www.mathworks.com/matlabcentral/fileexchange/authors/27420">MathWorks File Exchange</a>
%
% See also:
% sprintf, fprintf
% License to use and modify this code is granted freely to all interested, as long as the original author is
% referenced and attributed as such. The original author maintains the right to be solely associated with this work.
% Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com
% $Revision: 1.10 $ $Date: 2015/06/24 01:29:18 $
persistent majorVersion minorVersion
if isempty(majorVersion)
%v = version; if str2double(v(1:3)) <= 7.1
%majorVersion = str2double(regexprep(version,'^(\d+).*','$1'));
%minorVersion = str2double(regexprep(version,'^\d+\.(\d+).*','$1'));
%[a,b,c,d,versionIdStrs]=regexp(version,'^(\d+)\.(\d+).*'); %#ok unused
v = sscanf(version, '%d.', 2);
majorVersion = v(1); %str2double(versionIdStrs{1}{1});
minorVersion = v(2); %str2double(versionIdStrs{1}{2});
end
% The following is for debug use only:
%global docElement txt el
if ~exist('el','var') || isempty(el), el=handle([]); end %#ok mlint short-circuit error ("used before defined")
if nargin<1, showDemo(majorVersion,minorVersion); return; end
if isempty(style), return; end
if all(ishandle(style)) && length(style)~=3
dumpElement(style);
return;
end
% Process the text string
if nargin<2, format = style; style='text'; end
%error(nargchk(2, inf, nargin, 'struct'));
%str = sprintf(format,varargin{:});
% In compiled mode
try useDesktop = usejava('desktop'); catch, useDesktop = false; end
if isdeployed | ~useDesktop %#ok<OR2> - for Matlab 6 compatibility
% do not display any formatting - use simple fprintf()
% See: http://undocumentedmatlab.com/blog/bold-color-text-in-the-command-window/#comment-103035
% Also see: https://mail.google.com/mail/u/0/?ui=2&shva=1#all/1390a26e7ef4aa4d
% Also see: https://mail.google.com/mail/u/0/?ui=2&shva=1#all/13a6ed3223333b21
count1 = fprintf(format,varargin{:});
else
% Else (Matlab desktop mode)
% Get the normalized style name and underlining flag
[underlineFlag, boldFlag, style, debugFlag] = processStyleInfo(style);
% Set hyperlinking, if so requested
if underlineFlag
format = ['<a href="">' format '</a>'];
% Matlab 7.1 R14 (possibly a few newer versions as well?)
% have a bug in rendering consecutive hyperlinks
% This is fixed by appending a single non-linked space
if majorVersion < 7 || (majorVersion==7 && minorVersion <= 1)
format(end+1) = ' ';
end
end
% Set bold, if requested and supported (R2011b+)
if boldFlag
if (majorVersion > 7 || minorVersion >= 13)
format = ['<strong>' format '</strong>'];
else
boldFlag = 0;
end
end
% Get the current CW position
cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
lastPos = cmdWinDoc.getLength;
% If not beginning of line
bolFlag = 0; %#ok
%if docElement.getEndOffset - docElement.getStartOffset > 1
% Display a hyperlink element in order to force element separation
% (otherwise adjacent elements on the same line will be merged)
if majorVersion<7 || (majorVersion==7 && minorVersion<13)
if ~underlineFlag
fprintf('<a href=""> </a>'); %fprintf('<a href=""> </a>\b');
elseif format(end)~=10 % if no newline at end
fprintf(' '); %fprintf(' \b');
end
end
%drawnow;
bolFlag = 1;
%end
% Get a handle to the Command Window component
mde = com.mathworks.mde.desk.MLDesktop.getInstance;
cw = mde.getClient('Command Window');
% Fix: if command window isn't defined yet (startup), use standard fprintf()
if (isempty(cw))
count1 = fprintf(format,varargin{:});
if nargout
count = count1;
end
return;
end
xCmdWndView = cw.getComponent(0).getViewport.getComponent(0);
% Store the CW background color as a special color pref
% This way, if the CW bg color changes (via File/Preferences),
% it will also affect existing rendered strs
com.mathworks.services.Prefs.setColorPref('CW_BG_Color',xCmdWndView.getBackground);
% Display the text in the Command Window
% Note: fprintf(2,...) is required in order to add formatting tokens, which
% ^^^^ can then be updated below (no such tokens when outputting to stdout)
count1 = fprintf(2,format,varargin{:});
% Repaint the command window
%awtinvoke(cmdWinDoc,'remove',lastPos,1); % TODO: find out how to remove the extra '_'
drawnow; % this is necessary for the following to work properly (refer to Evgeny Pr in FEX comment 16/1/2011)
xCmdWndView.repaint;
%hListeners = cmdWinDoc.getDocumentListeners; for idx=1:numel(hListeners), try hListeners(idx).repaint; catch, end, end
docElement = cmdWinDoc.getParagraphElement(lastPos+1);
if majorVersion<7 || (majorVersion==7 && minorVersion<13)
if bolFlag && ~underlineFlag
% Set the leading hyperlink space character ('_') to the bg color, effectively hiding it
% Note: old Matlab versions have a bug in hyperlinks that need to be accounted for...
%disp(' '); dumpElement(docElement)
setElementStyle(docElement,'CW_BG_Color',1+underlineFlag,majorVersion,minorVersion); %+getUrlsFix(docElement));
%disp(' '); dumpElement(docElement)
el(end+1) = handle(docElement); % #ok used in debug only
end
% Fix a problem with some hidden hyperlinks becoming unhidden...
fixHyperlink(docElement);
%dumpElement(docElement);
end
% Get the Document Element(s) corresponding to the latest fprintf operation
while docElement.getStartOffset < cmdWinDoc.getLength
% Set the element style according to the current style
if debugFlag, dumpElement(docElement); end
specialFlag = underlineFlag | boldFlag;
setElementStyle(docElement,style,specialFlag,majorVersion,minorVersion);
if debugFlag, dumpElement(docElement); end
docElement2 = cmdWinDoc.getParagraphElement(docElement.getEndOffset+1);
if isequal(docElement,docElement2), break; end
docElement = docElement2;
end
if debugFlag, dumpElement(docElement); end
% Force a Command-Window repaint
% Note: this is important in case the rendered str was not '\n'-terminated
xCmdWndView.repaint;
% The following is for debug use only:
el(end+1) = handle(docElement); %#ok used in debug only
%elementStart = docElement.getStartOffset;
%elementLength = docElement.getEndOffset - elementStart;
%txt = cmdWinDoc.getText(elementStart,elementLength);
end
if nargout
count = count1;
end
return; % debug breakpoint
% Process the requested style information
function [underlineFlag,boldFlag,style,debugFlag] = processStyleInfo(style)
underlineFlag = 0;
boldFlag = 0;
debugFlag = 0;
% First, strip out the underline/bold markers
if ischar(style)
% Styles containing '-' or '_' should be underlined (using a no-target hyperlink hack)
%if style(1)=='-'
underlineIdx = (style=='-') | (style=='_');
if any(underlineIdx)
underlineFlag = 1;
%style = style(2:end);
style = style(~underlineIdx);
end
% Check for bold style (only if not underlined)
boldIdx = (style=='*');
if any(boldIdx)
boldFlag = 1;
style = style(~boldIdx);
end
if underlineFlag && boldFlag
warning('YMA:cprintf:BoldUnderline','Matlab does not support both bold & underline')
end
% Check for debug mode (style contains '!')
debugIdx = (style=='!');
if any(debugIdx)
debugFlag = 1;
style = style(~debugIdx);
end
% Check if the remaining style sting is a numeric vector
%styleNum = str2num(style); %#ok<ST2NM> % not good because style='text' is evaled!
%if ~isempty(styleNum)
if any(style==' ' | style==',' | style==';')
style = str2num(style); %#ok<ST2NM>
end
end
% Style = valid matlab RGB vector
if isnumeric(style) && length(style)==3 && all(style<=1) && all(abs(style)>=0)
if any(style<0)
underlineFlag = 1;
style = abs(style);
end
style = getColorStyle(style);
elseif ~ischar(style)
error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
% Style name
else
% Try case-insensitive partial/full match with the accepted style names
matlabStyles = {'Text','Keywords','Comments','Strings','UnterminatedStrings','SystemCommands','Errors'};
validStyles = [matlabStyles, ...
'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White', ...
'Hyperlinks'];
matches = find(strncmpi(style,validStyles,length(style)));
% No match - error
if isempty(matches)
error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
% Too many matches (ambiguous) - error
elseif length(matches) > 1
error('YMA:cprintf:AmbigStyle','Ambiguous style name - supply extra characters for uniqueness')
% Regular text
elseif matches == 1
style = 'ColorsText'; % fixed by Danilo, 29/8/2011
% Highlight preference style name
elseif matches <= length(matlabStyles)
style = ['Colors_M_' validStyles{matches}];
% Color name
elseif matches < length(validStyles)
colors = [0,0,0; 0,1,1; 1,0,1; 0,0,1; 0,1,0; 1,0,0; 1,1,0; 1,1,1];
requestedColor = colors(matches-length(matlabStyles),:);
style = getColorStyle(requestedColor);
% Hyperlink
else
style = 'Colors_HTML_HTMLLinks'; % CWLink
underlineFlag = 1;
end
end
% Convert a Matlab RGB vector into a known style name (e.g., '[255,37,0]')
function styleName = getColorStyle(rgb)
intColor = int32(rgb*255);
javaColor = java.awt.Color(intColor(1), intColor(2), intColor(3));
styleName = sprintf('[%d,%d,%d]',intColor);
com.mathworks.services.Prefs.setColorPref(styleName,javaColor);
% Fix a bug in some Matlab versions, where the number of URL segments
% is larger than the number of style segments in a doc element
function delta = getUrlsFix(docElement) %#ok currently unused
tokens = docElement.getAttribute('SyntaxTokens');
links = docElement.getAttribute('LinkStartTokens');
if length(links) > length(tokens(1))
delta = length(links) > length(tokens(1));
else
delta = 0;
end
% fprintf(2,str) causes all previous '_'s in the line to become red - fix this
function fixHyperlink(docElement)
try
tokens = docElement.getAttribute('SyntaxTokens');
urls = docElement.getAttribute('HtmlLink');
urls = urls(2);
links = docElement.getAttribute('LinkStartTokens');
offsets = tokens(1);
styles = tokens(2);
doc = docElement.getDocument;
% Loop over all segments in this docElement
for idx = 1 : length(offsets)-1
% If this is a hyperlink with no URL target and starts with ' ' and is collored as an error (red)...
if strcmp(styles(idx).char,'Colors_M_Errors')
character = char(doc.getText(offsets(idx)+docElement.getStartOffset,1));
if strcmp(character,' ')
if isempty(urls(idx)) && links(idx)==0
% Revert the style color to the CW background color (i.e., hide it!)
styles(idx) = java.lang.String('CW_BG_Color');
end
end
end
end
catch
% never mind...
end
% Set an element to a particular style (color)
function setElementStyle(docElement,style,specialFlag, majorVersion,minorVersion)
%global tokens links urls urlTargets % for debug only
global oldStyles
if nargin<3, specialFlag=0; end
% Set the last Element token to the requested style:
% Colors:
tokens = docElement.getAttribute('SyntaxTokens');
try
styles = tokens(2);
oldStyles{end+1} = cell(styles);
% Correct edge case problem
extraInd = double(majorVersion>7 || (majorVersion==7 && minorVersion>=13)); % =0 for R2011a-, =1 for R2011b+
%{
if ~strcmp('CWLink',char(styles(end-hyperlinkFlag))) && ...
strcmp('CWLink',char(styles(end-hyperlinkFlag-1)))
extraInd = 0;%1;
end
hyperlinkFlag = ~isempty(strmatch('CWLink',tokens(2)));
hyperlinkFlag = 0 + any(cellfun(@(c)(~isempty(c)&&strcmp(c,'CWLink')),cell(tokens(2))));
%}
jStyle = java.lang.String(style);
if numel(styles)==4 && isempty(char(styles(2)))
% Attempt to fix discoloration issues - NOT SURE THAT THIS IS OK! - 24/6/2015
styles(1) = jStyle;
end
styles(end-extraInd) = java.lang.String('');
styles(end-extraInd-specialFlag) = jStyle; % #ok apparently unused but in reality used by Java
if extraInd
styles(end-specialFlag) = jStyle;
end
oldStyles{end} = [oldStyles{end} cell(styles)];
catch
% never mind for now
end
% Underlines (hyperlinks):
%{
links = docElement.getAttribute('LinkStartTokens');
if isempty(links)
%docElement.addAttribute('LinkStartTokens',repmat(int32(-1),length(tokens(2)),1));
else
%TODO: remove hyperlink by setting the value to -1
end
%}
% Correct empty URLs to be un-hyperlinkable (only underlined)
urls = docElement.getAttribute('HtmlLink');
if ~isempty(urls)
urlTargets = urls(2);
for urlIdx = 1 : length(urlTargets)
try
if urlTargets(urlIdx).length < 1
urlTargets(urlIdx) = []; % '' => []
end
catch
% never mind...
a=1; %#ok used for debug breakpoint...
end
end
end
% Bold: (currently unused because we cannot modify this immutable int32 numeric array)
%{
try
%hasBold = docElement.isDefined('BoldStartTokens');
bolds = docElement.getAttribute('BoldStartTokens');
if ~isempty(bolds)
%docElement.addAttribute('BoldStartTokens',repmat(int32(1),length(bolds),1));
end
catch
% never mind - ignore...
a=1; %#ok used for debug breakpoint...
end
%}
return; % debug breakpoint
% Display information about element(s)
function dumpElement(docElements)
%return;
disp(' ');
numElements = length(docElements);
cmdWinDoc = docElements(1).getDocument;
for elementIdx = 1 : numElements
if numElements > 1, fprintf('Element #%d:\n',elementIdx); end
docElement = docElements(elementIdx);
if ~isjava(docElement), docElement = docElement.java; end
%docElement.dump(java.lang.System.out,1)
disp(docElement)
tokens = docElement.getAttribute('SyntaxTokens');
if isempty(tokens), continue; end
links = docElement.getAttribute('LinkStartTokens');
urls = docElement.getAttribute('HtmlLink');
try bolds = docElement.getAttribute('BoldStartTokens'); catch, bolds = []; end
txt = {};
tokenLengths = tokens(1);
for tokenIdx = 1 : length(tokenLengths)-1
tokenLength = diff(tokenLengths(tokenIdx+[0,1]));
if (tokenLength < 0)
tokenLength = docElement.getEndOffset - docElement.getStartOffset - tokenLengths(tokenIdx);
end
txt{tokenIdx} = cmdWinDoc.getText(docElement.getStartOffset+tokenLengths(tokenIdx),tokenLength).char; %#ok
end
lastTokenStartOffset = docElement.getStartOffset + tokenLengths(end);
try
txt{end+1} = cmdWinDoc.getText(lastTokenStartOffset, docElement.getEndOffset-lastTokenStartOffset).char; %#ok
catch
txt{end+1} = ''; %#ok<AGROW>
end
%cmdWinDoc.uiinspect
%docElement.uiinspect
txt = strrep(txt',sprintf('\n'),'\n');
try
data = [cell(tokens(2)) m2c(tokens(1)) m2c(links) m2c(urls(1)) cell(urls(2)) m2c(bolds) txt];
if elementIdx==1
disp(' SyntaxTokens(2,1) - LinkStartTokens - HtmlLink(1,2) - BoldStartTokens - txt');
disp(' ==============================================================================');
end
catch
try
data = [cell(tokens(2)) m2c(tokens(1)) m2c(links) txt];
catch
disp([cell(tokens(2)) m2c(tokens(1)) txt]);
try
data = [m2c(links) m2c(urls(1)) cell(urls(2))];
catch
% Mtlab 7.1 only has urls(1)...
data = [m2c(links) cell(urls)];
end
end
end
disp(data)
end
% Utility function to convert matrix => cell
function cells = m2c(data)
%datasize = size(data); cells = mat2cell(data,ones(1,datasize(1)),ones(1,datasize(2)));
cells = num2cell(data);
% Display the help and demo
function showDemo(majorVersion,minorVersion)
fprintf('cprintf displays formatted text in the Command Window.\n\n');
fprintf('Syntax: count = cprintf(style,format,...); click <a href="matlab:help cprintf">here</a> for details.\n\n');
url = 'http://UndocumentedMatlab.com/blog/cprintf/';
fprintf(['Technical description: <a href="' url '">' url '</a>\n\n']);
fprintf('Demo:\n\n');
boldFlag = majorVersion>7 || (majorVersion==7 && minorVersion>=13);
s = ['cprintf(''text'', ''regular black text'');' 10 ...
'cprintf(''hyper'', ''followed %s'',''by'');' 10 ...
'cprintf(''key'', ''%d colored'',' num2str(4+boldFlag) ');' 10 ...
'cprintf(''-comment'',''& underlined'');' 10 ...
'cprintf(''err'', ''elements:\n'');' 10 ...
'cprintf(''cyan'', ''cyan'');' 10 ...
'cprintf(''_green'', ''underlined green'');' 10 ...
'cprintf(-[1,0,1], ''underlined magenta'');' 10 ...
'cprintf([1,0.5,0], ''and multi-\nline orange\n'');' 10];
if boldFlag
% In R2011b+ the internal bug that causes the need for an extra space
% is apparently fixed, so we must insert the sparator spaces manually...
% On the other hand, 2011b enables *bold* format
s = [s 'cprintf(''*blue'', ''and *bold* (R2011b+ only)\n'');' 10];
s = strrep(s, ''')',' '')');
s = strrep(s, ''',5)',' '',5)');
s = strrep(s, '\n ','\n');
end
disp(s);
eval(s);
%%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%%
% - Fix: Remove leading space char (hidden underline '_')
% - Fix: Find workaround for multi-line quirks/limitations
% - Fix: Non-\n-terminated segments are displayed as black
% - Fix: Check whether the hyperlink fix for 7.1 is also needed on 7.2 etc.
% - Enh: Add font support
@@ -0,0 +1,28 @@
function [obj, deleteLogger] = getLogger(name, varargin)
persistent loggers;
logger_found = false;
if ~isempty(loggers)
for logger = loggers
if strcmp(logger.name, name)
obj = logger;
logger_found = true;
break;
end
end
end
if ~logger_found
obj = logging.logging(name, varargin{:});
loggers = [loggers, obj];
end
deleteLogger = @() deleteLogInstance();
function deleteLogInstance()
if ~logger_found
error(['logger for file [ ' name ' ] not found'])
end
loggers = loggers(loggers ~= obj);
delete(obj);
clear('obj');
end
end
@@ -0,0 +1,320 @@
classdef logging < handle
%LOGGING Simple logging framework.
%
% Author:
% Dominique Orban <dominique.orban@gmail.com>
% Heavily modified version of 'log4m': http://goo.gl/qDUcvZ
%
properties (Constant)
ALL = int8(0);
TRACE = int8(1);
DEBUG = int8(2);
INFO = int8(3);
WARNING = int8(4);
ERROR = int8(5);
CRITICAL = int8(6);
OFF = int8(7);
colors_terminal = containers.Map(...
{'normal', 'red', 'green', 'yellow', 'blue', 'brightred'}, ...
{'%s', '\033[31m%s\033[0m', '\033[32m%s\033[0m', '\033[33m%s\033[0m', ...
'\033[34m%s\033[0m', '\033[1;31m%s\033[0m'});
level_colors = containers.Map(...
{logging.logging.INFO, logging.logging.ERROR, logging.logging.TRACE, ...
logging.logging.WARNING, logging.logging.DEBUG, logging.logging.CRITICAL}, ...
{'normal', 'red', 'green', 'yellow', 'blue', 'brightred'});
levels = containers.Map(...
{logging.logging.ALL, logging.logging.TRACE, logging.logging.DEBUG, ...
logging.logging.INFO, logging.logging.WARNING, logging.logging.ERROR, ...
logging.logging.CRITICAL, logging.logging.OFF}, ...
{'ALL', 'TRACE', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'OFF'});
end
properties (SetAccess=immutable)
level_numbers;
level_range;
end
properties (SetAccess=protected)
name;
fullpath = 'logging.log'; % Default log file
logfmt = '%-23s %-40s %-8s %s\n'; % Default LogFormat
logfid = -1;
logcolors = logging.logging.colors_terminal;
using_terminal;
webhook;
instance;
end
properties (Hidden,SetAccess=protected)
datefmt_ = 'yyyy-mm-dd HH:MM:SS,FFF';
logLevel_ = logging.logging.INFO;
commandWindowLevel_ = logging.logging.INFO;
end
properties (Dependent)
datefmt;
logLevel;
commandWindowLevel;
end
methods(Static)
function [name, line] = getCallerInfo(self)
if nargin > 0 && self.ignoreLogging()
name = [];
line = [];
return
end
[ST, ~] = dbstack();
offset = min(size(ST, 1), 3);
name = ST(offset).name;
line = ST(offset).line;
end
end
methods
function setFilename(self, logPath)
[self.logfid, message] = fopen(logPath, 'a');
if self.logfid < 0
warning(['Problem with supplied logfile path: ' message]);
self.logLevel_ = logging.logging.OFF;
end
self.fullpath = logPath;
end
function setCommandWindowLevel(self, level)
self.commandWindowLevel = level;
end
function setLogLevel(self, level)
self.logLevel = level;
end
function setSlackWebHook(self, WebHook)
self.webhook = WebHook;
end
function setSlackInstance(self, Instance)
self.instance = Instance;
end
function tf = ignoreLogging(self)
tf = self.commandWindowLevel_ == self.OFF && self.logLevel_ == self.OFF;
end
function trace(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.TRACE, caller_name, message,sendtoslack);
end
function debug(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.DEBUG, caller_name, message,sendtoslack);
end
function info(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.INFO, caller_name, message,sendtoslack);
end
function warn(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.WARNING, caller_name, message,sendtoslack);
end
function error(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.ERROR, caller_name, message,sendtoslack);
end
function critical(self, message,varargin)
sendtoslack = 0;
if (nargin == 3 )
if varargin{1,1} == 1
sendtoslack = 1;
end
end
[caller_name, ~] = self.getCallerInfo(self);
self.writeLog(self.CRITICAL, caller_name, message,sendtoslack);
end
function self = logging(name, varargin)
levelkeys = self.levels.keys;
self.level_numbers = containers.Map(self.levels.values, levelkeys);
levelkeys = cell2mat(self.levels.keys);
self.level_range = [min(levelkeys), max(levelkeys)];
p = inputParser();
p.addRequired('name', @ischar);
p.addParameter('path', '', @ischar);
p.addParameter('logLevel', self.logLevel);
p.addParameter('commandWindowLevel', self.commandWindowLevel);
p.addParameter('datefmt', self.datefmt_);
p.parse(name, varargin{:});
r = p.Results;
self.name = r.name;
self.commandWindowLevel = r.commandWindowLevel;
self.datefmt = r.datefmt;
if ~isempty(r.path)
self.setFilename(r.path); % Opens the log file.
self.logLevel = r.logLevel;
else
self.logLevel_ = logging.logging.OFF;
end
% Use terminal logging if swing is disabled in matlab environment.
swingError = javachk('swing');
self.using_terminal = (~ isempty(swingError) && strcmp(swingError.identifier, 'MATLAB:javachk:thisFeatureNotAvailable')) || ~desktop('-inuse');
end
function delete(self)
if self.logfid > -1
fclose(self.logfid);
end
end
function writeLog(self, level, caller, message, sendtoslack)
level = self.getLevelNumber(level);
if self.commandWindowLevel_ <= level || self.logLevel_ <= level
timestamp = datestr(now, self.datefmt_);
levelStr = logging.logging.levels(level);
logline = sprintf(self.logfmt, timestamp, caller, levelStr, self.getMessage(message));
end
if sendtoslack
level = self.getLevelNumber(level);
timestamp = datestr(now, self.datefmt_);
levelStr = logging.logging.levels(level);
slacklogline = sprintf(self.logfmt, timestamp, caller, levelStr, self.getMessage(message));
SendSlackNotification(self.webhook,strcat(self.instance,' : ', slacklogline));
end
if self.commandWindowLevel_ <= level
if self.using_terminal
level_color = self.level_colors(level);
else
level_color = self.level_colors(logging.logging.INFO);
end
fprintf(self.logcolors(level_color), logline);
end
if self.logLevel_ <= level && self.logfid > -1
fprintf(self.logfid, logline);
end
end
function set.datefmt(self, fmt)
try
datestr(now(), fmt);
catch
error('Invalid date format');
end
self.datefmt_ = fmt;
end
function fmt = get.datefmt(self)
fmt = self.datefmt_;
end
function set.logLevel(self, level)
level = self.getLevelNumber(level);
if level > logging.logging.OFF || level < logging.logging.ALL
error('invalid logging level');
end
self.logLevel_ = level;
end
function level = get.logLevel(self)
level = self.logLevel_;
end
function set.commandWindowLevel(self, level)
self.commandWindowLevel_ = self.getLevelNumber(level);
end
function level = get.commandWindowLevel(self)
level = self.commandWindowLevel_;
end
end
methods (Hidden)
function level = getLevelNumber(self, level)
% LEVEL = GETLEVELNUMBER(LEVEL)
%
% Converts charecter-based level names to level numbers
% used internally by logging.
%
% If given a number, it makes sure the number is valid
% then returns it unchanged.
%
% This allows users to specify levels by name or number.
if isinteger(level) && self.level_range(1) <= level && level <= self.level_range(2)
return
else
level = self.level_numbers(level);
end
end
function message = getMessage(~, message)
if isa(message, 'function_handle')
message = message();
end
[rows, ~] = size(message);
if rows > 1
message = sprintf('\n %s', evalc('disp(message)'));
end
end
end
end
@@ -0,0 +1,41 @@
function testspeed(logPath)
opts.path = logPath;
L = logging.getLogger('testlogger', opts);
L.setCommandWindowLevel(L.TRACE);
L.setLogLevel(L.OFF);
tic;
for i=1:1e3
L.trace('test');
end
disp('1e3 logs when logging only to command window');
toc;
L.setCommandWindowLevel(L.OFF);
L.setLogLevel(L.OFF);
tic;
for i=1:1e3
L.trace('test');
end
disp('1e3 logs when logging is off');
toc;
L.setCommandWindowLevel(L.OFF);
L.setLogLevel(L.TRACE);
tic;
for i=1:1e3
L.trace('test');
end
disp('1e3 logs when logging to file');
toc;
L.setCommandWindowLevel(L.OFF);
L.setLogLevel(L.TRACE);
tic;
for i=1:1e3
L.trace(@() 'test');
end
disp('1e3 logs when logging to file using function handle');
toc;
end
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 optimizers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,154 @@
# Logging for Matlab
This simple logging module is a modification of [`log4m`](http://goo.gl/qDUcvZ)
with the following improvements:
* multiple loggers can be created and retrieved by name (à la Python)
* different logging levels appear in different colors if using Matlab in the terminal
Each logger's output can be directed to the standard output and/or to a file.
Each logger is assigned a logging level that will control the amount of output.
The possible levels are, from high to low:
* ALL (highest)
* TRACE
* DEBUG
* INFO (default)
* WARNING
* ERROR
* CRITICAL
* OFF (lowest)
The default level in INFO.
If a logger outputs at a level lower than or equal to its assigned level, the output will be logged.
To silence a logger, set its level to OFF.
All loggers output a string according to the Matlab format `'%-s %-23s %-8s %s\n'`.
Note that a newline is always appended, so there is no need to terminate log lines
with a newline.
The format is as follows:
* `%-s` is used to display the caller name, i.e., the function or method in which
logging occured
* `%-23s` is used for a time stamp of the form `2016-09-14 14:23:44,271`
* `%-8s` is used for the logging level
* `%s` is used for the message to be logged.
## API
An instance of the `logging` class is created using the `logging.getLogger` function.
The first argument for this function must be the name of the logger. Four additional
optional arguments are also available. These can either be provided as name/value
pairs (such as `logger.getlogger(name, 'path', path)`) or as a struct where the
field names are the names of the argument (such as `logger.getlogger(name, struct('path', path)`).
The available arguments are:
* `path`: The path to the log file. If this is not specified or is an empty string,
then logging to a file is disabled.
This must be a string.
* `logLevel`: set the file log level.
Only log entries with a level greater than or equal to this level will be saved.
This can either be a string or an integer.
Note that this argument will be ignored if `path` is empty or not specified.
* `commandWindowLevel`: set the command window log level.
Only log entries with a level greater than or equal to this level will be displayed.
This can either be a string or an integer.
* `datefmt`: the date/time format string.
This contains the date/time format string used by the logs.
The format must be compatible with the built-in `datestr` function.
This must be a string.
If `logger` is an instance of the `logging` class, the following methods can be used
to log output at different levels:
* `logger.trace(string)`: output `string` at level TRACE.
This level is mostly used to trace a code path.
* `logger.debug(string)`: output `string` at level DEBUG.
This level is mostly used to log debugging output that may help identify an issue
or verify correctness by inspection.
* `logger.info(string)`: output `string` at level INFO.
This level is intended for general user messages about the progress of the program.
* `logger.warn(string)`: output `string` at level WARNING (unrelated to Matlab's `warning()` function).
This level is used to alert the user of a possible problem.
* `logger.error(string)`: output `string` at level ERROR (unrelated to Matlab's `error()` function).
This level is used for non-critical errors that can endanger correctness.
* `logger.critical(string)`: output `string` at level CRITICAL
This level is used for critical errors that definitely endanger correctness.
The following utility methods are also available:
* `logger.setFileName(string)`: set the log file to `string`.
This can be used to specify or change the file logs are saved to.
* `logger.setCommandWindowLevel(level)`: set the command window log level to `level`.
Only log entries with a level greater than or equal to `level` will be displayed.
`level` can either be a string or an integer.
* `logger.setLogLevel(level)`: set the file log level to `level`.
Only log entries with a level greater than or equal to `level` will be saved.
`level` can either be a string or an integer.
Note that even if the level is changed, nothing will be written if a valid
filename has not been set for the log.
The following properties can be read or written:
* `logger.datefmt`: the date/time format string.
This contains the date/time format string used by the logs.
The format must be compatible with the built-in `datestr` function.
* `logger.commandWindowLevel`: the command window log level.
Only log entries with a level greater than or equal to `level` will be displayed.
It can be set with either a string or an integer, but will always return an integer.
* `logger.logLevel`: the file log level.
Only log entries with a level greater than or equal to `level` will be saved.
It can be set with either a string or an integer, but will always return an integer.
The following properties are read-only (note that these are called in a different way):
* `logging.logging.ALL`: The integer value for the `ALL` level (0).
* `logging.logging.TRACE`: The integer value for the `TRACE` level (1).
* `logging.logging.DEBUG`: The integer value for the `DEBUG` level (2).
* `logging.logging.INFO`: The integer value for the `INFO` level (3).
* `logging.logging.WARNING`: The integer value for the `WARNING` level (4).
* `logging.logging.ERROR`: The integer value for the `ERROR` level (5).
* `logging.logging.CRITICAL`: The integer value for the `CRITICAL` level (6).
* `logging.logging.OFF`: The integer value for the `OFF` level (6).
Note that there is no corresponding write method for this level,
so if this level is set no logging will take place.
## Examples
A logger at default level INFO logs messages at levels INFO, WARNING, ERROR and CRITICAL, but not at levels TRACE or DEBUG:
```matlab
>> addpath('/path/to/logging4matlab')
>> logger = logging.getLogger('mylogger') % new logger with default level INFO
>> logger.info('life is just peachy')
logging.info 2016-09-14 15:10:06,049 INFO life is just peachy
>> logger.debug('Easy as pi! (Euclid)') % produces no output
>> logger.critical('run away!')
logging.critical 2016-09-14 15:12:37,652 CRITICAL run away!
```
A logger's assigned level for the command window (or terminal) can be changed:
```matlab
>> logger.setCommandWindowLevel(logging.logging.WARNING)
```
A logger can also output to file:
```matlab
>> logger2 = logging.getLogger('myotherlogger', 'path', '/tmp/logger2.log')
>> logger.setLogLevel(logging.logging.WARNING)
```
Output to either the command window or a file can be suppressed with `logging.logging.OFF`.
# FAQ
1. *Why is there no colored logging in the Matlab command window?*
I haven't gotten around to evaluating the performance of [`cprintf`](https://goo.gl/Nw5OOy),
which seems to be the only viable option for colored output in the command window.
Pull request welcome!
2. *Can I change the colors?*
Currently, no, but feel free to submit a pull request!
3. *Can I change the format string used by loggers?*
Currently, no, but feel free to submit a pull request!
+9
View File
@@ -0,0 +1,9 @@
addpath('Api\')
addpath('logging4matlab\')
addpath('Slack\')
addpath('DLL\')
[ClientResult] = TestClient_basic();
@@ -0,0 +1,135 @@
classdef ConnectToMT5_Api < handle
%CONNECTMT5 Connects to the MtApi Client via .NET
properties
h;
hOutputWindow
end
methods
%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
function obj = ConnectToMT5_Api
obj.h = MtApi5.MtApi5Client();
end
%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
function startMT5 (self,addr,port)
%% Handle to the .NET client
fprintf('Connecting...\n');
self.h.BeginConnect(addr,port);
end
function stopMT5(self)
self.h.BeginDisconnect();
end
function setOutputWindowHandle(self,h)
self.hOutputWindow = h;
end
%%
function [copied_cnt, MqlRates] = getHistoryBars(self)
symbol = 'EURUSD';
period = 'M1';
start_cnt = 0;
end_cnt = 5;
[ copied_cnt,MqlRates ] = self.h.CopyRates(symbol,period,start_cnt,end_cnt);
end
% *************************************************************************
% **************** Api Function **********************************************
%**************************************************************************
%% double = AccountInfoDouble(enum MtApi5.ENUM_ACCOUNT_INFO_DOUBLE)
function res = AccountInfoDouble(self,enum)
res = self.h.AccountInfoDouble(enum);
end
%% uint32 = SymbolsTotal(bool selected)
function res = SymbolsTotal(self,selected)
res = self.h.SymbolsTotal(selected);
end
%% Market Info
%% public bool SymbolInfoTick(string symbol, out MqlTick tick)
function [mqltick] = SymbolInfoTick(self,symbol)
[mqltick] = self.h.SymbolInfoTick(symbol);
end
%% Trading functions
%% bool OrderSend(MqlTradeRequest request, out MqlTradeResult result)
%%
function [res,result] = OrderSend(self, request)
[res,result] = self.h.OrderSend(request);
end
%%
function r = setQuoteListener(self)
r = addlistener(self.h, 'QuoteUpdate', @self.quoteListener);
end
function r = setQuoteAddedListener(self)
r = addlistener(self.h, 'QuoteAdded', @self.quoteAddedListener);
end
function r = setConnectionListener(self)
r = addlistener(self.h, 'ConnectionStateChanged', @self.connectionListener);
end
function quoteAddedListener(event)
askString = num2str(event.Quote.Ask,'%01.5f');
% askString = sprintf(event.Quote.Ask,'%01.5f');
bidString = num2str(event.Quote.Bid,'%01.5f');
% bidString = num2str(event.Quote.Bid,'%01.5f');
transmitString = strcat(askString,',',bidString);
fprintf('%s: %s\n',char(event.Quote.Instrument),transmitString);
end
function quoteListener(self,~,event)
askString = num2str(event.Quote.Ask,'%01.5f');
bidString = num2str(event.Quote.Bid,'%01.5f');
transmitString = strcat(askString,',',bidString);
text_to = sprintf('%s: %s\n',char(event.Quote.Instrument),transmitString);
NT_TextToOutputWindow(self.hOutputWindow,text_to);
end
function connectionListener(self, ~, event)
connectState = event.Status.ToString;
text_to = sprintf('Connection changed: %s\n', char(connectState));
NT_TextToOutputWindow(self.hOutputWindow,text_to);
if (connectState.eq('Failed') == true)
text_to = sprintf('Reason: %s\n', char(event.ConnectionMessage));
NT_TextToOutputWindow(self.hOutputWindow,text_to);
end
end
end
end
@@ -0,0 +1,24 @@
function [FigH,ListH] = NT_CreateOutputWindow(windowname,position)
FigH = figure('Name',windowname, ...
'menubar', 'none', ...
'Position', position,...
'NumberTitle','off');
ListH = uicontrol('Style', 'listbox', ...
'Units', 'normalized', ...
'Position', [0,0,1,1], ...
'String', {}, ...
'Min', 0, 'Max', 2, ...
'Value', []);
end
% for i = 1:10
% pause(0.5);
% Str = datestr(now, 0);
% newString = cat(1, get(ListH, 'String'), {Str});
% set(ListH, 'String', newString);
% drawnow;
% end
@@ -0,0 +1,32 @@
function [] = NT_TextToOutputWindow(ListH,Text)
if isempty(Text)
error(' Text for Outputwindow is empty ');
Text = 'error';
end
% FigH = figure('Name',windowname, ...
% 'menubar', 'none', ...
% 'NumberTitle','off');
%
% ListH = uicontrol('Style', 'listbox', ...
% 'Units', 'normalized', ...
% 'Position', [0,0,1,1], ...
% 'String', {}, ...
% 'Min', 0, 'Max', 2, ...
% 'Value', []);
newString = cat(1, get(ListH, 'String'), {Text});
set(ListH, 'String', newString);
drawnow;
end
+107
View File
@@ -0,0 +1,107 @@
function TestClient
% Main program
% interfaces to the MT5 client
% receives price data from MT5 via .NET interface
% recieives history bars from MT5
ordersend_ok = false;
[output_figH,output_listH] = NT_CreateOutputWindow('Test OutputWindow ',[400,400,800,200]);
NT_TextToOutputWindow(output_listH,'Startup ...');
[Trades_figH,Trades_listH] = NT_CreateOutputWindow('Trades OutputWindow ',[400,800,800,200]);
NT_TextToOutputWindow(Trades_listH,'Startup Trades Window ...');
[Events_figH,Events_listH] = NT_CreateOutputWindow('Events OutputWindow ',[400,1200,800,200]);
NT_TextToOutputWindow(Events_listH,'Startup Events Window ...');
format short
MTApi5_dll_Location = 'C:\Program Files\MtApi5\MtApi5.dll';
%% Connect to .NET
asm1 = NET.addAssembly (MTApi5_dll_Location);
NT_TextToOutputWindow(output_listH,'MtApi5.dll loaded ...');
%% Open the Metatrader Link via .NET
MT5 = ConnectToMT5_Api; % creates the MT5 object
MT5.setOutputWindowHandle(Events_listH) % copy output window pointer to listener
MT5.setConnectionListener; % create connection listener
MT5.setQuoteListener; % create quote listener
MT5.setQuoteAddedListener; % create quote added listener
port = 8301;
addr = '127.0.0.1';
MT5.startMT5(addr,port); % establishes .NET connection
NT_TextToOutputWindow(output_listH,'Setup Mt5Api ...');
while MT5.h.ConnectionState ~= MtApi5.Mt5ConnectionState.Connected
pause(0.01);
NT_TextToOutputWindow(output_listH,'Waiting for Connection....');
end
NT_TextToOutputWindow(output_listH,'Connected ...');
%% Test SymbolsTotal
text_to = sprintf('Symbols= %d ', MT5.SymbolsTotal(true));
NT_TextToOutputWindow(output_listH,text_to);
%% Test AccountInfo
text_to = sprintf('Balance = %d \n',MT5.AccountInfoDouble(MtApi5.ENUM_ACCOUNT_INFO_DOUBLE.ACCOUNT_BALANCE));
NT_TextToOutputWindow(output_listH,text_to);
%% Test OrderSend
request = MtApi5.MqlTradeRequest;
tick = MtApi5.MqlTick;
% [tick] = MT5.SymbolInfoTick('EURUSD');
request.Action = MtApi5.ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_DEAL;
request.Symbol = 'EURUSD';
request.Deviation = 30;
request.Volume = 0.01; %% Account MIN 10000 !
request.Type = MtApi5.ENUM_ORDER_TYPE.ORDER_TYPE_BUY;
request.Price = tick.ask;
try
[ordersend_ok,result] = MT5.OrderSend(request);
catch exception
text_to = sprintf('NET Error in OrderSend = %s\n ',exception.message);
NT_TextToOutputWindow(Trades_listH,text_to);
end
if (ordersend_ok)
text_to = sprintf('OrderSend OK \n');
NT_TextToOutputWindow(Trades_listH,text_to);
text_to = sprintf('Result: %s \n',char(result.ToString));
NT_TextToOutputWindow(Trades_listH,text_to);
else
text_to = sprintf('OrderSend ERROR \n');
NT_TextToOutputWindow(Trades_listH,text_to);
end
%% while not pressed 0
while true
pause(0.1);
prompt = 'Press 0 key to stop\n';
x = input(prompt);
if (x == 0)
break;
end
end
MT5.stopMT5;
fprintf('Connection Stopped \n');
end
+2
View File
@@ -0,0 +1,2 @@
TestClient();
+1
View File
@@ -0,0 +1 @@
/.idea/
+61
View File
@@ -0,0 +1,61 @@
import sys
import clr
import time
sys.path.append(r"C:\Program Files\MtApi5")
asm = clr.AddReference("MtApi5")
import MtApi5 as mt5
def testCopyRates():
symbol = str('EURUSD')
startPos = 1
count = 100
rates = []
tf = mt5.ENUM_TIMEFRAMES.PERIOD_M5
out_dummy = []
try:
result_count, rates_out = client.CopyRates(symbol, tf, startPos, count, out_dummy)
except Exception as e:
print(e)
print('Error in CopyRates = %s\n ', e)
exit()
print("CopyRates: result_count = ", result_count)
if __name__ == '__main__':
client = mt5.MtApi5Client()
ip = str('192.168.178.15')
port = 8300
sleeps = 10
try:
while sleeps > 0:
print("Connecting...")
client.BeginConnect(ip, port)
time.sleep(1)
sleeps = sleeps - 1
if client.ConnectionState == 1:
print("Connected")
testCopyRates()
break
if client.ConnectionState == 0:
print("Connecting...")
continue
if client.ConnectionState == 4:
print("Connection failed")
break
except Exception as e:
print(e)
client.BeginDisconnect()
@@ -0,0 +1 @@
pythonnet
-61
View File
@@ -1,61 +0,0 @@
using System;
using System.Security.Cryptography;
using System.Text;
using System.Security;
namespace Licensing
{
public class DigitalSignatureHelper
{
public static String GeneratePrivateKey()
{
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
return dsa.ToXmlString(true);
}
public static String GetPublicKey(String privateKey)
{
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
dsa.FromXmlString(privateKey);
return dsa.ToXmlString(false);
}
public static string CreateSignature(string inputData, String privateKey)
{
// create the crypto-service provider:
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
// setup the dsa from the private key:
dsa.FromXmlString(privateKey);
byte[] data = UTF8Encoding.ASCII.GetBytes(inputData);
// get the signature:
byte[] signature = dsa.SignData(data);
return Convert.ToBase64String(signature);
}
public static bool VerifySignature(string inputData, string signature, string publicKey)
{
// create the crypto-service provider:
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
// setup the provider from the public key:
dsa.FromXmlString(publicKey);
// get the license terms data:
//byte[] data = Convert.FromBase64String(inputData);
byte[] data = UTF8Encoding.ASCII.GetBytes(inputData);
// get the signature data:
byte[] signatureData = Convert.FromBase64String(signature);
// verify that the license-terms match the signature data
if (dsa.VerifyData(data, signatureData) == false)
throw new SecurityException("Signature Not Verified!");
return true;
}
}
}
-77
View File
@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{21FA6E21-EE5D-4A84-B0ED-E1D8876B41FB}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Licensing</RootNamespace>
<AssemblyName>Licensing</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DigitalSignatureHelper.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MTApiService\MTApiService.csproj">
<Project>{DE76D5C7-B99C-4467-8408-78173BDD84E0}</Project>
<Name>MTApiService</Name>
</ProjectReference>
</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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
-326
View File
@@ -1,326 +0,0 @@
namespace Licensing
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBoxPublicKey = new System.Windows.Forms.TextBox();
this.buttonGenerateKey = new System.Windows.Forms.Button();
this.buttonLoadKey = new System.Windows.Forms.Button();
this.buttonSaveKey = new System.Windows.Forms.Button();
this.textBoxPrivateKey = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.textBoxAccountName = new System.Windows.Forms.TextBox();
this.textBoxAccountNumber = new System.Windows.Forms.TextBox();
this.buttonSign = new System.Windows.Forms.Button();
this.textBoxSignature = new System.Windows.Forms.TextBox();
this.buttonGetPublicKey = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.clipboardCopyBtn = new System.Windows.Forms.Button();
this.buttonExportPublicKey = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.label3 = new System.Windows.Forms.Label();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.saveToRegBtn = new System.Windows.Forms.Button();
this.buttonVerify = new System.Windows.Forms.Button();
this.buttonExportSignature = new System.Windows.Forms.Button();
this.readRegBtn = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox4.SuspendLayout();
this.SuspendLayout();
//
// textBoxPublicKey
//
this.textBoxPublicKey.Location = new System.Drawing.Point(6, 19);
this.textBoxPublicKey.Name = "textBoxPublicKey";
this.textBoxPublicKey.ReadOnly = true;
this.textBoxPublicKey.Size = new System.Drawing.Size(620, 20);
this.textBoxPublicKey.TabIndex = 0;
//
// buttonGenerateKey
//
this.buttonGenerateKey.Location = new System.Drawing.Point(6, 45);
this.buttonGenerateKey.Name = "buttonGenerateKey";
this.buttonGenerateKey.Size = new System.Drawing.Size(75, 23);
this.buttonGenerateKey.TabIndex = 2;
this.buttonGenerateKey.Text = "Generate";
this.buttonGenerateKey.UseVisualStyleBackColor = true;
this.buttonGenerateKey.Click += new System.EventHandler(this.buttonGenerateKey_Click);
//
// buttonLoadKey
//
this.buttonLoadKey.Location = new System.Drawing.Point(168, 45);
this.buttonLoadKey.Name = "buttonLoadKey";
this.buttonLoadKey.Size = new System.Drawing.Size(75, 23);
this.buttonLoadKey.TabIndex = 3;
this.buttonLoadKey.Text = "Load";
this.buttonLoadKey.UseVisualStyleBackColor = true;
this.buttonLoadKey.Click += new System.EventHandler(this.buttonLoadKey_Click);
//
// buttonSaveKey
//
this.buttonSaveKey.Location = new System.Drawing.Point(87, 45);
this.buttonSaveKey.Name = "buttonSaveKey";
this.buttonSaveKey.Size = new System.Drawing.Size(75, 23);
this.buttonSaveKey.TabIndex = 4;
this.buttonSaveKey.Text = "Save";
this.buttonSaveKey.UseVisualStyleBackColor = true;
this.buttonSaveKey.Click += new System.EventHandler(this.buttonSaveKey_Click);
//
// textBoxPrivateKey
//
this.textBoxPrivateKey.Location = new System.Drawing.Point(6, 19);
this.textBoxPrivateKey.Name = "textBoxPrivateKey";
this.textBoxPrivateKey.ReadOnly = true;
this.textBoxPrivateKey.Size = new System.Drawing.Size(620, 20);
this.textBoxPrivateKey.TabIndex = 0;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(8, 48);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(47, 13);
this.label4.TabIndex = 6;
this.label4.Text = "Number:";
//
// textBoxAccountName
//
this.textBoxAccountName.Location = new System.Drawing.Point(67, 19);
this.textBoxAccountName.Name = "textBoxAccountName";
this.textBoxAccountName.Size = new System.Drawing.Size(559, 20);
this.textBoxAccountName.TabIndex = 7;
//
// textBoxAccountNumber
//
this.textBoxAccountNumber.Location = new System.Drawing.Point(67, 45);
this.textBoxAccountNumber.Name = "textBoxAccountNumber";
this.textBoxAccountNumber.Size = new System.Drawing.Size(559, 20);
this.textBoxAccountNumber.TabIndex = 7;
//
// buttonSign
//
this.buttonSign.Location = new System.Drawing.Point(10, 45);
this.buttonSign.Name = "buttonSign";
this.buttonSign.Size = new System.Drawing.Size(75, 23);
this.buttonSign.TabIndex = 8;
this.buttonSign.Text = "Sign";
this.buttonSign.UseVisualStyleBackColor = true;
this.buttonSign.Click += new System.EventHandler(this.buttonSign_Click);
//
// textBoxSignature
//
this.textBoxSignature.Location = new System.Drawing.Point(10, 19);
this.textBoxSignature.Name = "textBoxSignature";
this.textBoxSignature.Size = new System.Drawing.Size(615, 20);
this.textBoxSignature.TabIndex = 10;
//
// buttonGetPublicKey
//
this.buttonGetPublicKey.Location = new System.Drawing.Point(6, 45);
this.buttonGetPublicKey.Name = "buttonGetPublicKey";
this.buttonGetPublicKey.Size = new System.Drawing.Size(75, 23);
this.buttonGetPublicKey.TabIndex = 11;
this.buttonGetPublicKey.Text = "Get Key";
this.buttonGetPublicKey.UseVisualStyleBackColor = true;
this.buttonGetPublicKey.Click += new System.EventHandler(this.buttonGetPublicKey_Click);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.textBoxPrivateKey);
this.groupBox1.Controls.Add(this.buttonGenerateKey);
this.groupBox1.Controls.Add(this.buttonLoadKey);
this.groupBox1.Controls.Add(this.buttonSaveKey);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(632, 78);
this.groupBox1.TabIndex = 12;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Private Key";
//
// groupBox2
//
this.groupBox2.Controls.Add(this.clipboardCopyBtn);
this.groupBox2.Controls.Add(this.buttonExportPublicKey);
this.groupBox2.Controls.Add(this.textBoxPublicKey);
this.groupBox2.Controls.Add(this.buttonGetPublicKey);
this.groupBox2.Location = new System.Drawing.Point(12, 96);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(632, 77);
this.groupBox2.TabIndex = 13;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Public Key";
//
// clipboardCopyBtn
//
this.clipboardCopyBtn.Location = new System.Drawing.Point(169, 46);
this.clipboardCopyBtn.Name = "clipboardCopyBtn";
this.clipboardCopyBtn.Size = new System.Drawing.Size(113, 23);
this.clipboardCopyBtn.TabIndex = 13;
this.clipboardCopyBtn.Text = "Copy to Clipboard";
this.clipboardCopyBtn.UseVisualStyleBackColor = true;
this.clipboardCopyBtn.Click += new System.EventHandler(this.clipboardCopyBtn_Click);
//
// buttonExportPublicKey
//
this.buttonExportPublicKey.Location = new System.Drawing.Point(88, 46);
this.buttonExportPublicKey.Name = "buttonExportPublicKey";
this.buttonExportPublicKey.Size = new System.Drawing.Size(75, 23);
this.buttonExportPublicKey.TabIndex = 12;
this.buttonExportPublicKey.Text = "Export";
this.buttonExportPublicKey.UseVisualStyleBackColor = true;
this.buttonExportPublicKey.Click += new System.EventHandler(this.buttonExportPublicKey_Click);
//
// groupBox3
//
this.groupBox3.Controls.Add(this.textBoxAccountName);
this.groupBox3.Controls.Add(this.label3);
this.groupBox3.Controls.Add(this.textBoxAccountNumber);
this.groupBox3.Controls.Add(this.label4);
this.groupBox3.Location = new System.Drawing.Point(12, 180);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(635, 81);
this.groupBox3.TabIndex = 14;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Account";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(8, 22);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(38, 13);
this.label3.TabIndex = 5;
this.label3.Text = "Name:";
//
// groupBox4
//
this.groupBox4.Controls.Add(this.readRegBtn);
this.groupBox4.Controls.Add(this.saveToRegBtn);
this.groupBox4.Controls.Add(this.buttonVerify);
this.groupBox4.Controls.Add(this.buttonExportSignature);
this.groupBox4.Controls.Add(this.textBoxSignature);
this.groupBox4.Controls.Add(this.buttonSign);
this.groupBox4.Location = new System.Drawing.Point(13, 268);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(631, 76);
this.groupBox4.TabIndex = 15;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Signature";
//
// saveToRegBtn
//
this.saveToRegBtn.Location = new System.Drawing.Point(172, 45);
this.saveToRegBtn.Name = "saveToRegBtn";
this.saveToRegBtn.Size = new System.Drawing.Size(101, 23);
this.saveToRegBtn.TabIndex = 13;
this.saveToRegBtn.Text = "Save To Reg";
this.saveToRegBtn.UseVisualStyleBackColor = true;
this.saveToRegBtn.Click += new System.EventHandler(this.saveToRegBtn_Click);
//
// buttonVerify
//
this.buttonVerify.Location = new System.Drawing.Point(550, 45);
this.buttonVerify.Name = "buttonVerify";
this.buttonVerify.Size = new System.Drawing.Size(75, 23);
this.buttonVerify.TabIndex = 12;
this.buttonVerify.Text = "Verify";
this.buttonVerify.UseVisualStyleBackColor = true;
this.buttonVerify.Click += new System.EventHandler(this.buttonVerify_Click);
//
// buttonExportSignature
//
this.buttonExportSignature.Location = new System.Drawing.Point(91, 45);
this.buttonExportSignature.Name = "buttonExportSignature";
this.buttonExportSignature.Size = new System.Drawing.Size(75, 23);
this.buttonExportSignature.TabIndex = 11;
this.buttonExportSignature.Text = "Export";
this.buttonExportSignature.UseVisualStyleBackColor = true;
this.buttonExportSignature.Click += new System.EventHandler(this.buttonExportSignature_Click);
//
// readRegBtn
//
this.readRegBtn.Location = new System.Drawing.Point(279, 45);
this.readRegBtn.Name = "readRegBtn";
this.readRegBtn.Size = new System.Drawing.Size(132, 23);
this.readRegBtn.TabIndex = 14;
this.readRegBtn.Text = "Read from Registry";
this.readRegBtn.UseVisualStyleBackColor = true;
this.readRegBtn.Click += new System.EventHandler(this.readRegBtn_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(659, 351);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Name = "MainForm";
this.Text = "Liccensing";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TextBox textBoxPublicKey;
private System.Windows.Forms.Button buttonGenerateKey;
private System.Windows.Forms.Button buttonLoadKey;
private System.Windows.Forms.Button buttonSaveKey;
private System.Windows.Forms.TextBox textBoxPrivateKey;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox textBoxAccountName;
private System.Windows.Forms.TextBox textBoxAccountNumber;
private System.Windows.Forms.Button buttonSign;
private System.Windows.Forms.TextBox textBoxSignature;
private System.Windows.Forms.Button buttonGetPublicKey;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Button buttonExportPublicKey;
private System.Windows.Forms.GroupBox groupBox4;
private System.Windows.Forms.Button buttonExportSignature;
private System.Windows.Forms.Button buttonVerify;
private System.Windows.Forms.Button clipboardCopyBtn;
private System.Windows.Forms.Button saveToRegBtn;
private System.Windows.Forms.Button readRegBtn;
}
}
-352
View File
@@ -1,352 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security;
using MTApiService;
namespace Licensing
{
public partial class MainForm : Form
{
private bool mIsSaved = true;
public MainForm()
{
InitializeComponent();
}
private void buttonGenerateKey_Click(object sender, EventArgs e)
{
textBoxPrivateKey.Text = DigitalSignatureHelper.GeneratePrivateKey();
mIsSaved = false;
}
private void buttonGetPublicKey_Click(object sender, EventArgs e)
{
string privateKey = textBoxPrivateKey.Text;
if (string.IsNullOrEmpty(privateKey) == false)
{
textBoxPublicKey.Text = DigitalSignatureHelper.GetPublicKey(privateKey);
}
else
{
MessageBox.Show("Private Key is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void buttonSaveKey_Click(object sender, EventArgs e)
{
string privateKey = textBoxPrivateKey.Text;
if (string.IsNullOrEmpty(privateKey) == false)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "MetaTraderApi Key Files (*.mtk)|*.mtk";
dlg.Title = "Save MetaTraderApi Key File";
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
using (TextWriter file = new StreamWriter(dlg.FileName, true))
{
file.WriteLine(privateKey);
}
mIsSaved = true;
}
catch (Exception ex)
{
var errorMsg = string.Format("Saving failed!\n{0}", ex.Message);
MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
else
{
MessageBox.Show("Private Key is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void buttonLoadKey_Click(object sender, EventArgs e)
{
if (mIsSaved == false)
{
if (MessageBox.Show("Private Key is not saved. Continue?", "Private Key", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
return;
}
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "MetaTraderApi Key Files (*.mtk)|*.mtk";
dlg.Title = "Load MetaTraderApi Key File";
if (dlg.ShowDialog() == DialogResult.OK)
{
textBoxPrivateKey.Text = string.Empty;
textBoxPublicKey.Text = string.Empty;
try
{
using (TextReader file = new StreamReader(dlg.FileName))
{
textBoxPrivateKey.Text = file.ReadLine();
}
mIsSaved = true;
}
catch (Exception ex)
{
var errorMsg = string.Format("Saving failed!\n{0}", ex.Message);
MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void buttonSign_Click(object sender, EventArgs e)
{
string privateKey = textBoxPrivateKey.Text;
if (string.IsNullOrEmpty(privateKey) == false)
{
string accountName = textBoxAccountName.Text;
string accountNumber = textBoxAccountNumber.Text;
if (string.IsNullOrEmpty(accountName) == false)
{
if (string.IsNullOrEmpty(accountNumber) == false)
{
string inputData = accountName + accountNumber;
textBoxSignature.Text = DigitalSignatureHelper.CreateSignature(inputData, privateKey);
}
else
{
MessageBox.Show("AccountNumber is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
MessageBox.Show("AccountName is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
MessageBox.Show("Private Key is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void buttonExportPublicKey_Click(object sender, EventArgs e)
{
string publicKey = textBoxPublicKey.Text;
if (string.IsNullOrEmpty(publicKey) == false)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "MetaTraderApi Key Files (*.mtk)|*.mtk";
dlg.Title = "Export MetaTraderApi Key File";
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
using (TextWriter file = new StreamWriter(dlg.FileName, true))
{
file.WriteLine(publicKey);
}
mIsSaved = true;
}
catch (Exception ex)
{
var errorMsg = string.Format("Export failed!\n{0}", ex.Message);
MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
else
{
MessageBox.Show("Public Key is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void buttonExportSignature_Click(object sender, EventArgs e)
{
string signature = textBoxSignature.Text;
if (string.IsNullOrEmpty(signature) == false)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "MetaTraderApi Key (*.mta)|*.mta";
dlg.Title = "Export MetaTraderApi Key";
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
using (TextWriter file = new StreamWriter(dlg.FileName))
{
file.WriteLine(signature);
}
mIsSaved = true;
}
catch (Exception ex)
{
var errorMsg = string.Format("Export failed!\n{0}", ex.Message);
MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
else
{
MessageBox.Show("Signature is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void buttonVerify_Click(object sender, EventArgs e)
{
string publicKey = textBoxPublicKey.Text;
if (string.IsNullOrEmpty(publicKey) == false)
{
string signature = textBoxSignature.Text;
if (string.IsNullOrEmpty(signature) == false)
{
string accountName = textBoxAccountName.Text;
string accountNumber = textBoxAccountNumber.Text;
if (string.IsNullOrEmpty(accountName) == false)
{
if (string.IsNullOrEmpty(accountNumber) == false)
{
string inputData = accountName + accountNumber;
var verifyResult = false;
try
{
verifyResult = DigitalSignatureHelper.VerifySignature(inputData, signature, publicKey);
}
catch (SecurityException ex)
{
MessageBox.Show(ex.Message, "Verify", MessageBoxButtons.OK, MessageBoxIcon.Warning);
verifyResult = false;
}
catch (Exception ex)
{
string errorMsg = string.Format("Verify process failed!\n{0}", ex.Message);
MessageBox.Show(errorMsg, "Verify", MessageBoxButtons.OK, MessageBoxIcon.Error);
verifyResult = false;
}
if (verifyResult == true)
{
MessageBox.Show("Signature good", "Verify", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
else
{
MessageBox.Show("AccountNumber is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
MessageBox.Show("AccountName is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
MessageBox.Show("Signature is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
MessageBox.Show("Public Key is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void clipboardCopyBtn_Click(object sender, EventArgs e)
{
Clipboard.SetText(textBoxPublicKey.Text);
}
private void saveToRegBtn_Click(object sender, EventArgs e)
{
string signature = textBoxSignature.Text;
string accountName = textBoxAccountName.Text;
string accountNumber = textBoxAccountNumber.Text;
if (string.IsNullOrEmpty(signature))
{
MessageBox.Show("Signature is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(accountName))
{
MessageBox.Show("AccountName is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(accountNumber))
{
MessageBox.Show("AccountNumber is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Registry files (*.reg)|*.reg";
dlg.Title = "Registry files";
if (dlg.ShowDialog() == DialogResult.OK)
{
string key = MtRegistryManager.SaveSignatureKey(accountName, accountNumber, signature);
bool exported = MtRegistryManager.ExportKey(key, dlg.FileName);
if (exported)
{
MessageBox.Show("Export successed.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.None);
}
else
{
MessageBox.Show("Export failed!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void readRegBtn_Click(object sender, EventArgs e)
{
string accountName = textBoxAccountName.Text;
string accountNumber = textBoxAccountNumber.Text;
if (string.IsNullOrEmpty(accountName))
{
MessageBox.Show("AccountName is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(accountNumber))
{
MessageBox.Show("AccountNumber is empty!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string signature = MtRegistryManager.ReadSignatureKey(accountName, accountNumber);
textBoxSignature.Text = signature;
}
}
}
-120
View File
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-21
View File
@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Licensing
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
-36
View File
@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Licensing")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DW")]
[assembly: AssemblyProduct("Licensing")]
[assembly: AssemblyCopyright("Copyright © DW 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2c3df81b-2285-44ff-a152-0111e25d9b1a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+39 -67
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)
@@ -74,6 +58,7 @@ template <typename T> T Execute(std::function<T()> func, wchar_t* err, T default
catch (Exception^ e)
{
convertSystemString(err, e->Message);
MtAdapter::GetInstance()->LogError(e->Message);
}
return result;
}
@@ -104,6 +89,14 @@ _DLLAPI int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid,
}, err, 0);
}
_DLLAPI bool _stdcall sendEvent(int expertHandle, int eventType, wchar_t* payload, wchar_t* err)
{
return Execute<bool>([&expertHandle, &eventType, payload]() {
MtAdapter::GetInstance()->SendEvent(expertHandle, eventType, gcnew String(payload));
return true;
}, err, false);
}
_DLLAPI int _stdcall sendIntResponse(int expertHandle, int response, wchar_t* err)
{
return Execute<int>([&expertHandle, &response]() {
@@ -156,7 +149,7 @@ _DLLAPI int _stdcall sendStringResponse(int expertHandle, wchar_t* response, wch
_DLLAPI int _stdcall sendVoidResponse(int expertHandle, wchar_t* err)
{
return Execute<int>([&expertHandle]() {
MtAdapter::GetInstance()->SendResponse(expertHandle, nullptr);
MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseObject(nullptr));
return 1;
}, err, 0);
}
@@ -216,59 +209,38 @@ _DLLAPI int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates value
}, err, 0);
}
_DLLAPI int _stdcall sendMqlTickResponse(int expertHandle, CMqlTick* response, wchar_t* err)
_DLLAPI int _stdcall sendErrorResponse(int expertHandle, int code, wchar_t* message, 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;
return Execute<int>([&expertHandle, &code, message]() {
MtResponseString^ res = gcnew MtResponseString(gcnew String(message));
res->ErrorCode = code;
MtAdapter::GetInstance()->SendResponse(expertHandle, res);
return true;
}, err, 0);
}
//----------- get values -------------------------------
_DLLAPI int _stdcall getCommandType(int expertHandle, int* res, wchar_t* err)
_DLLAPI int _stdcall getCommandType(int expertHandle, int& res, wchar_t* err)
{
return Execute<int>([&expertHandle, res]() {
*res = MtAdapter::GetInstance()->GetCommandType(expertHandle);
return Execute<int>([&expertHandle, &res]() {
res = MtAdapter::GetInstance()->GetCommandType(expertHandle);
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getIntValue(int expertHandle, int paramIndex, int* res, wchar_t* err)
_DLLAPI int _stdcall getIntValue(int expertHandle, int paramIndex, int& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
*res = (int)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return Execute<int>([&expertHandle, &paramIndex, &res]() {
res = MtAdapter::GetInstance()->GetCommandParameter<int>(expertHandle, paramIndex);
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res, wchar_t* err)
_DLLAPI int _stdcall getDoubleValue(int expertHandle, int paramIndex, double& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
*res = (double)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return Execute<int>([&expertHandle, &paramIndex, &res]() {
res = MtAdapter::GetInstance()->GetCommandParameter<double>(expertHandle, paramIndex);
return 1;
}, err, 0);
}
@@ -276,40 +248,40 @@ _DLLAPI int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* re
_DLLAPI int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
convertSystemString(res, (String^)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
convertSystemString(res, MtAdapter::GetInstance()->GetCommandParameter<String^>(expertHandle, paramIndex));
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getULongValue(int expertHandle, int paramIndex, unsigned __int64* res, wchar_t* err)
_DLLAPI int _stdcall getULongValue(int expertHandle, int paramIndex, unsigned __int64& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
*res = (unsigned __int64)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return Execute<int>([&expertHandle, &paramIndex, &res]() {
res = MtAdapter::GetInstance()->GetCommandParameter<unsigned __int64>(expertHandle, paramIndex);
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getLongValue(int expertHandle, int paramIndex, __int64* res, wchar_t* err)
_DLLAPI int _stdcall getLongValue(int expertHandle, int paramIndex, __int64& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
*res = (__int64)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return Execute<int>([&expertHandle, &paramIndex, &res]() {
res = MtAdapter::GetInstance()->GetCommandParameter<__int64>(expertHandle, paramIndex);
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res, wchar_t* err)
_DLLAPI int _stdcall getBooleanValue(int expertHandle, int paramIndex, int& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
bool val = (bool)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
*res = val == true ? 1 : 0;
return Execute<int>([&expertHandle, &paramIndex, &res]() {
bool val = MtAdapter::GetInstance()->GetCommandParameter<bool>(expertHandle, paramIndex);
res = val == true ? 1 : 0;
return 1;
}, err, 0);
}
_DLLAPI int _stdcall getUIntValue(int expertHandle, int paramIndex, unsigned int* res, wchar_t* err)
_DLLAPI int _stdcall getUIntValue(int expertHandle, int paramIndex, unsigned int& res, wchar_t* err)
{
return Execute<int>([&expertHandle, &paramIndex, res]() {
*res = (unsigned int)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
return Execute<int>([&expertHandle, &paramIndex, &res]() {
res = MtAdapter::GetInstance()->GetCommandParameter<unsigned int>(expertHandle, paramIndex);
return 1;
}, err, 0);
}
+6 -5
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -23,6 +23,7 @@
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>MT5Connector</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -30,28 +31,28 @@
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+88 -8
View File
@@ -8,24 +8,89 @@ using log4net.Repository.Hierarchy;
namespace MTApiService
{
public class MtLog
{
#region ctor
internal MtLog(Type type)
{
_log = LogManager.GetLogger(type);
}
#endregion
#region Public
public void Debug(object message)
{
_log.Debug(message);
}
public void Error(object message)
{
_log.Error(message);
}
public void Fatal(object message)
{
_log.Fatal(message);
}
public void Info(object message)
{
_log.Info(message);
}
public void Warn(object message)
{
_log.Warn(message);
}
#endregion
#region Private
private readonly ILog _log;
#endregion
}
public enum LogLevel
{
Off,
Debug,
Info
}
public class LogConfigurator
{
private const string LogFileNameExtension = "txt";
private const string LogFileNameExtension = "log";
public static void Setup(string profileName)
{
#if (DEBUG)
const LogLevel logLevel = LogLevel.Debug;
#else
const LogLevel logLevel = LogLevel.Info;
#endif
Setup(profileName, logLevel);
}
public static void Setup(string profileName, LogLevel logLevel)
{
if (string.IsNullOrEmpty(profileName))
throw new ArgumentNullException();
var hierarchy = (Hierarchy) LogManager.GetRepository();
//check if logger is already configurated to avoid creation many empty logs files
if (hierarchy.Configured)
return;
var patternLayout = new PatternLayout
{
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
};
patternLayout.ActivateOptions();
string filename = $"{DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss")}-{Process.GetCurrentProcess().Id}.{LogFileNameExtension}";
var filename = $"{DateTime.Now:yyyy-dd-M--HH-mm-ss}-{Process.GetCurrentProcess().Id}.{LogFileNameExtension}";
var roller = new RollingFileAppender
{
@@ -40,13 +105,28 @@ namespace MTApiService
};
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
#if (DEBUG)
hierarchy.Root.Level = Level.Debug;
#else
hierarchy.Root.Level = Level.Info;
#endif
hierarchy.Root.Level = ConvertLogLevel(logLevel);
hierarchy.Configured = true;
}
public static MtLog GetLogger(Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
return new MtLog(type);
}
private static Level ConvertLogLevel(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Debug: return Level.Debug;
case LogLevel.Info: return Level.Info;
case LogLevel.Off: return Level.Off;
default:
throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
}
}
}
}
+2 -5
View File
@@ -38,11 +38,10 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>MtApiKey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
@@ -72,9 +71,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();
}
}
}
+33 -3
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);
}
}
@@ -185,7 +185,7 @@ namespace MTApiService
return retval;
}
public object GetCommandParameter(int expertHandle, int index)
public T GetCommandParameter<T>(int expertHandle, int index)
{
Log.DebugFormat("GetCommandParameter: begin. expertHandle = {0}, index = {1}", expertHandle, index);
@@ -204,7 +204,7 @@ namespace MTApiService
Log.DebugFormat("GetCommandParameter: end. retval = {0}", retval);
return retval;
return (T)retval;
}
public object GetNamedParameter(int expertHandle, string name)
@@ -250,6 +250,11 @@ namespace MTApiService
return retval;
}
public void LogError(string message)
{
Log.Error(message);
}
#endregion
#region Private Methods
@@ -270,6 +275,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.28.0")]
[assembly: AssemblyFileVersion("1.0.28.0")]
[assembly: AssemblyVersion("1.0.34.0")]
[assembly: AssemblyFileVersion("1.0.34.0")]
+6 -5
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -24,6 +24,7 @@
<Keyword>ManagedCProj</Keyword>
<RootNamespace>MTConnector</RootNamespace>
<ProjectName>MTConnector</ProjectName>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -31,28 +32,28 @@
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>NotSet</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>NotSet</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -10,8 +10,13 @@ namespace MtApi.Monitors
Opened = opened;
Closed = closed;
}
/// <summary>
/// Contains all newly opened orders since the last time the monitor checked the open orders.
/// </summary>
public List<MtOrder> Opened { get; private set; }
/// <summary>
/// Contains all newly closed orders since the last time the monitor checked the open orders.
/// </summary>
public List<MtOrder> Closed { get; private set; }
}
}
+113
View File
@@ -0,0 +1,113 @@
using System;
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
public abstract class MtMonitorBase
{
#region Fields
private volatile bool _isStarted = false;
private bool _syncTrigger;
#endregion
#region Properties
/// <summary>
/// ApiClient
/// </summary>
protected MtApiClient ApiClient { get; }
/// <summary>
/// Returns true if the <see cref="ApiClient"/> is connected.
/// </summary>
public bool IsMtConnected => ApiClient.ConnectionState == MtConnectionState.Connected;
/// <summary>
/// Returns the trigger which will be used to raise the monitoring call.
/// </summary>
public IMonitorTrigger MonitorTrigger { get; }
/// <summary>
/// Returns true if the Monitor is started.
/// </summary>
public bool IsStarted { get => _isStarted; }
/// <summary>
/// If true, the <see cref="MonitorTrigger"/> will be stopped or started automatically when <see cref="Start"/> or <see cref="Stop"/> will be called.
/// <para>CAUTION: If you use the MonitorTrigger for different Monitors, this will stop all monitors if you call stop and <see cref="SyncTrigger"/> is <c>true</c>.</para>
/// </summary>
public bool SyncTrigger { get => _syncTrigger; set => _syncTrigger = value; }
#endregion
#region ctor
/// <summary>
/// Default constructor for Monitors
/// </summary>
/// <param name="apiClient">The apiClient which will be used to work with.</param>
/// <param name="monitorTrigger">The trigger which lead this Monitor to do his work.</param>
/// <param name="syncTrigger">See property <see cref="SyncTrigger"/>.</param>
public MtMonitorBase(MtApiClient apiClient, IMonitorTrigger monitorTrigger, bool syncTrigger = false)
{
ApiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
MonitorTrigger = monitorTrigger ?? throw new ArgumentNullException(nameof(monitorTrigger));
SyncTrigger = syncTrigger;
}
#endregion
#region Methods
/// <summary>
/// Let the monitor listen to the <see cref="MonitorTrigger"/>.
/// </summary>
public virtual void Start()
{
if (!_isStarted)
{
ApiClient.ConnectionStateChanged += ApiClientConnectionStateChanged;
MonitorTrigger.Raised += MonitorTriggerRaised;
_isStarted = true;
OnStart();
if (SyncTrigger)
MonitorTrigger.Start();
}
}
/// <summary>
/// Let the monitor stop listening to the <see cref="MonitorTrigger"/>.
/// </summary>
public virtual void Stop()
{
if (_isStarted)
{
MonitorTrigger.Raised -= MonitorTriggerRaised;
ApiClient.ConnectionStateChanged -= ApiClientConnectionStateChanged;
_isStarted = false;
OnStop();
if (SyncTrigger)
MonitorTrigger.Stop();
}
}
private void MonitorTriggerRaised(object sender, EventArgs e) => OnTriggerRaised();
private void ApiClientConnectionStateChanged(object sender, MtConnectionEventArgs e)
{
if (e.Status == MtConnectionState.Connected)
OnMtConnected();
else if (e.Status == MtConnectionState.Failed || e.Status == MtConnectionState.Disconnected)
OnMtDisconnected();
}
/// <summary>
/// Will be called when <see cref="Start"/> will be called.
/// </summary>
protected virtual void OnStart() { }
/// <summary>
/// Will be called when <see cref="Stop"/> will be called.
/// </summary>
protected virtual void OnStop() { }
/// <summary>
/// Will be called when the <see cref="ApiClient"/> is successfully connected.
/// </summary>
protected virtual void OnMtConnected() { }
/// <summary>
/// Will be called when <see cref="ApiClient"/> is disconnected.
/// </summary>
protected virtual void OnMtDisconnected() { }
/// <summary>
/// Will be called when the <see cref="MonitorTrigger"/> raised.
/// </summary>
protected abstract void OnTriggerRaised();
#endregion
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MtApi.Monitors
{
public class ModifiedOrdersEventArgs : EventArgs
{
/// <summary>
/// Returns a list of all modified orders
/// </summary>
public List<MtModifiedOrder> ModifiedOrders { get; }
public ModifiedOrdersEventArgs(List<MtModifiedOrder> modifiedOrders)
{
ModifiedOrders = modifiedOrders;
}
}
}
@@ -0,0 +1,68 @@
using MtApi.Monitors.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MtApi.Monitors
{
public class ModifiedOrdersMonitor : MtMonitorBase
{
#region Fields
private List<MtOrder> _lastOrders = null;
#endregion
#region Properties
/// <summary>
/// Define on which types of modification this monitor should raise <see cref="OrdersModified"/>
/// </summary>
public OrderModifiedTypes OrderModifiedTypes { get; set; }
#endregion
#region Events
/// <summary>
/// Will be raised when this monitor detects changes on open orders
/// </summary>
public event EventHandler<ModifiedOrdersEventArgs> OrdersModified;
#endregion
#region ctor
public ModifiedOrdersMonitor(MtApiClient apiClient, IMonitorTrigger monitorTrigger, OrderModifiedTypes orderModifiedTypes = OrderModifiedTypes.All, bool syncTrigger = false)
: base(apiClient, monitorTrigger, syncTrigger)
{
_lastOrders = GetOrders();
OrderModifiedTypes = orderModifiedTypes;
}
#endregion
/// <summary>
/// Requests all current open orders
/// </summary>
/// <returns></returns>
private List<MtOrder> GetOrders() => IsMtConnected ? ApiClient.GetOrders(OrderSelectSource.MODE_TRADES) : null;
protected override void OnTriggerRaised()
{
if(_lastOrders == null)
{
_lastOrders = GetOrders();
return;
}
List<MtOrder> currentOrders = GetOrders();
OrderModifiedTypes omt = OrderModifiedTypes;
var mtModifiedOrders = currentOrders
.Select(co => new MtModifiedOrder(_lastOrders.FirstOrDefault(x => x.Ticket == co.Ticket), co))
.ToList();
List<MtModifiedOrder> modifiedOrders = new List<MtModifiedOrder>();
modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.TakeProfit)); //If the takeprofit were changed between both calls
modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.StopLoss)); //If the stoploss were changed between both calls
modifiedOrders.AddRange(GetMtModifiedOrdersWithModType(mtModifiedOrders, omt, OrderModifiedTypes.Operation)); //If an order changed from limit / stop order to an open order
if (modifiedOrders.Count > 0)
OrdersModified?.Invoke(this, new ModifiedOrdersEventArgs(modifiedOrders));
_lastOrders = currentOrders;
}
private static IEnumerable<MtModifiedOrder> GetMtModifiedOrdersWithModType(IEnumerable<MtModifiedOrder> orders, OrderModifiedTypes globalSearchFlag, OrderModifiedTypes modifiedType)
=> globalSearchFlag.HasFlag(modifiedType) ? orders.Where(o => o.ModifyType.HasFlag(modifiedType)) : new List<MtModifiedOrder>();
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MtApi.Monitors
{
public class MtModifiedOrder
{
/// <summary>
/// The order in its old state (before the changes)
/// </summary>
public MtOrder OldOrder { get; }
/// <summary>
/// The order in its new state (after the changes)
/// </summary>
public MtOrder NewOrder { get; }
/// <summary>
/// The changes found by this instance
/// </summary>
public OrderModifiedTypes ModifyType { get; private set; }
/// <summary>
/// Initializes an instance and compare the order in its old and new state
/// </summary>
/// <param name="oldOrder">The order in its old state (before the changes)</param>
/// <param name="newOrder">The order in its new state (after the changes)</param>
public MtModifiedOrder(MtOrder oldOrder, MtOrder newOrder)
{
if (oldOrder != null && newOrder != null && oldOrder.Ticket != newOrder.Ticket)
throw new ArgumentException(nameof(oldOrder) + " and " + nameof(newOrder) + " need to have the same ticket id");
OldOrder = oldOrder;
NewOrder = newOrder;
ModifyType = OrderModifiedTypes.None;
Compare();
}
private void Compare()
{
if(NewOrder != null && OldOrder != null)
{
if (OldOrder.StopLoss != NewOrder.StopLoss)
ModifyType |= OrderModifiedTypes.StopLoss;
if (OldOrder.TakeProfit != NewOrder.TakeProfit)
ModifyType |= OrderModifiedTypes.TakeProfit;
if (OldOrder.Operation != NewOrder.Operation)
ModifyType |= OrderModifiedTypes.Operation;
}
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MtApi.Monitors
{
[Flags]
public enum OrderModifiedTypes
{
None = 0x0,
TakeProfit = 1 << 0,
StopLoss = 1 << 1,
Operation = 1 << 2,
All = 7
}
}
+11 -49
View File
@@ -1,56 +1,18 @@

using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
public class TimeframeTradeMonitor : TradeMonitor
{
#region Fields
private volatile bool _isStarted;
#endregion
#region ctor
public TimeframeTradeMonitor(MtApiClient apiClient)
: base(apiClient)
/// <summary>
/// Constructor for initializing a new instance with a trigger instance of <see cref="NewBarTrigger"/>.
/// <para>SyncTrigger is set to true by default</para>
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
public TimeframeTradeMonitor(MtApiClient apiClient)
: base(apiClient, new NewBarTrigger(apiClient))
{
apiClient.OnLastTimeBar += ApiClient_OnLastTimeBar;
SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
}
#endregion
#region Public Methods
//
// Summary:
// Gets a value indicating whether the TimeframeTradeMonitor should raise checking orders
//
// Returns:
// true if PositionMonitor should check orders
// otherwise, false.
public override bool IsStarted => _isStarted;
#endregion
#region Protected Methods
protected override void OnMtConnected() {}
protected override void OnMtDisconnected() {}
protected override void OnStart()
{
_isStarted = true;
}
protected override void OnStop()
{
_isStarted = false;
}
#endregion
#region Private Methods
private void ApiClient_OnLastTimeBar(object sender, TimeBarArgs e)
{
if (_isStarted)
{
Check();
}
}
#endregion
}
}
}
+28 -71
View File
@@ -1,90 +1,47 @@
using System.Timers;
using System;
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
public class TimerTradeMonitor : TradeMonitor
{
#region Fields
private readonly Timer _timer = new Timer();
private readonly TimeElapsedTrigger _timeElapsedTrigger;
#endregion
#region ctor
public TimerTradeMonitor(MtApiClient apiClient)
: base(apiClient)
{
_timer.Interval = 10000; //default interval 10 sec
_timer.Elapsed += _timer_Elapsed;
}
#endregion
#region Public Methods
//
// Summary:
// Gets or sets the interval, expressed in milliseconds, at which to check orders
//
// Returns:
// The time, in milliseconds, between checking events. The value
// must be greater than zero, and less than or equal to System.Int32.MaxValue.
// The default is 10000 milliseconds.
//
// Exceptions:
// T:System.ArgumentException:
// The interval is less than or equal to zero.-or-The interval is greater than System.Int32.MaxValue,
// and the PositionMonitor is currently started.
#region Properties
/// <summary>
/// Interval for raising the trigger
/// </summary>
public double Interval
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}
//
// Summary:
// Gets a value indicating whether the PositionMonitor should raise checking orders
//
// Returns:
// true if TimerTradeMonitor should check orders
// otherwise, false.
public override bool IsStarted
{
get { return _timer.Enabled; }
get => _timeElapsedTrigger.Interval.TotalMilliseconds;
set => _timeElapsedTrigger.Interval = TimeSpan.FromMilliseconds(value);
}
#endregion
#region Protected Methods
protected override void OnStart()
#region ctors
/// <summary>
/// Constructor for initializing a new instance with a default <see cref="Interval"/> of 10 seconds.
/// <para>SyncTrigger is set to true by default</para>
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
public TimerTradeMonitor(MtApiClient apiClient)
: this(apiClient, new TimeElapsedTrigger(TimeSpan.FromSeconds(10)))
{
if (IsMtConnected)
{
_timer.Start();
}
SyncTrigger = true; //Sync-Trigger set to true, to have the same behavior as before
}
protected override void OnStop()
/// <summary>
/// Constructor for initializing a new instance with a custom instance of <see cref="TimeElapsedTrigger"/>.
/// <para>SyncTrigger is set to false by default</para>
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
/// <param name="timeElapsedTrigger">The custom instance of <see cref="TimeElapsedTrigger"/> which will be used to trigger this instance of <see cref="TradeMonitor"/>.</param>
public TimerTradeMonitor(MtApiClient apiClient, TimeElapsedTrigger timeElapsedTrigger)
: base(apiClient, timeElapsedTrigger)
{
_timer.Stop();
}
protected override void OnMtConnected()
{
_timer.Start();
}
protected override void OnMtDisconnected()
{
_timer.Stop();
}
#endregion
#region Private Methods
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Elapsed -= _timer_Elapsed; //unregister from events to prevent rise condition during work with orders
Check();
_timer.Elapsed += _timer_Elapsed; //register again
_timeElapsedTrigger = timeElapsedTrigger;
}
#endregion
}
}
}
+44 -116
View File
@@ -1,63 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MtApi.Monitors.Triggers;
namespace MtApi.Monitors
{
public abstract class TradeMonitor
public class TradeMonitor : MtMonitorBase
{
#region Fields
private readonly MtApiClient _apiClient;
private List<MtOrder> _prevOrders;
private readonly object _locker = new object();
#endregion
#region ctor
protected TradeMonitor(MtApiClient apiClient)
{
if (apiClient == null)
throw new ArgumentNullException(nameof(apiClient));
_apiClient = apiClient;
}
#endregion
#region Public Methods
//
// Summary:
// Gets a value indicating whether the TradeMonitor should raise checking orders
//
// Returns:
// true if TradeMonitor should check orders
// otherwise, false.
public abstract bool IsStarted { get; }
//
// Summary:
// Start checking orders.
//
public void Start()
{
_apiClient.ConnectionStateChanged += _apiClient_ConnectionStateChanged;
if (IsMtConnected)
{
InitialCheck();
}
OnStart();
}
//
// Summary:
// Stop checking orders.
//
public void Stop()
{
_apiClient.ConnectionStateChanged -= _apiClient_ConnectionStateChanged;
OnStop();
}
#endregion
#region Events
//
// Summary:
@@ -65,17 +20,34 @@ namespace MtApi.Monitors
public event EventHandler<AvailabilityOrdersEventArgs> AvailabilityOrdersChanged;
#endregion
#region Protected Methods
#region ctor
/// <summary>
/// Constructor for initializing an instance of <see cref="TradeMonitor"/>.
/// </summary>
/// <param name="apiClient">The <see cref="MtApiClient"/> which will be used to communicate with MetaTrader.</param>
/// <param name="monitorTrigger">The custom instance of <see cref="IMonitorTrigger"/> which will be used to trigger this instance of <see cref="TradeMonitor"/>.</param>
public TradeMonitor(MtApiClient apiClient, IMonitorTrigger monitorTrigger) : base(apiClient, monitorTrigger) { }
#endregion
protected abstract void OnStart();
protected abstract void OnStop();
protected override void OnMtConnected()
{
InitialCheck();
base.OnMtConnected();
}
protected override void OnStart()
{
if (IsMtConnected)
InitialCheck();
base.OnStart();
}
protected abstract void OnMtConnected();
protected abstract void OnMtDisconnected();
public bool IsMtConnected => _apiClient.ConnectionState == MtConnectionState.Connected;
protected void Check()
protected override void OnTriggerRaised()
{
if (IsMtConnected)
Check();
}
private void Check()
{
try
{
@@ -90,92 +62,48 @@ namespace MtApi.Monitors
//TODO: write error to log
}
}
#endregion
private void InitialCheck()
{
lock (_locker)
_prevOrders = null;
#region Private Methods
Task.Factory.StartNew(Check);
}
private void CheckOrders()
{
var openedOrders = new List<MtOrder>();
var closedOrders = new List<MtOrder>();
List<MtOrder> prevOrders;
// get current orders from MetaTrader
var tradesOrders = _apiClient.GetOrders(OrderSelectSource.MODE_TRADES);
var tradesOrders = ApiClient.GetOrders(OrderSelectSource.MODE_TRADES);
List<MtOrder> prevOrders;
lock(_locker)
{
lock (_locker)
prevOrders = _prevOrders;
}
if (prevOrders != null) //skip checking on first load orders
{
//check open orders
foreach (var order in tradesOrders)
{
if (prevOrders.Find(a => a.Ticket == order.Ticket) == null)
{
openedOrders.Add(order);
}
}
openedOrders = tradesOrders.Where(to => prevOrders.Find(a => a.Ticket == to.Ticket) == null).ToList();
//check closed orders
var closeOrdersTemp = new List<MtOrder>();
foreach (var order in prevOrders)
{
if (tradesOrders.Find(a => a.Ticket == order.Ticket) == null)
{
closeOrdersTemp.Add(order);
}
}
var closeOrdersTemp = prevOrders.Where(po => tradesOrders.Find(a => a.Ticket == po.Ticket) == null).ToList();
if (closeOrdersTemp.Count > 0)
{
//get closed orders from history with actual values
var historyOrders = _apiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
foreach (var order in closeOrdersTemp)
{
var closedOrder = historyOrders.Find(a => a.Ticket == order.Ticket);
if (closedOrder != null)
{
closedOrders.Add(closedOrder);
}
}
var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY);
closedOrders = closeOrdersTemp.Where(cot => historyOrders.Find(a => a.Ticket == cot.Ticket) != null).ToList();
}
}
lock(_locker)
{
lock (_locker)
_prevOrders = tradesOrders;
}
if (openedOrders.Count > 0 || closedOrders.Count > 0)
{
AvailabilityOrdersChanged?.Invoke(this, new AvailabilityOrdersEventArgs(openedOrders, closedOrders));
}
}
private void _apiClient_ConnectionStateChanged(object sender, MtConnectionEventArgs e)
{
if (e.Status == MtConnectionState.Connected)
{
InitialCheck();
OnMtConnected();
}
else if (e.Status == MtConnectionState.Failed || e.Status == MtConnectionState.Disconnected)
{
OnMtDisconnected();
}
}
private void InitialCheck()
{
lock (_locker)
{
_prevOrders = null;
}
Task.Factory.StartNew(Check);
}
#endregion
}
}
}
@@ -0,0 +1,27 @@
using System;
namespace MtApi.Monitors.Triggers
{
/// <summary>
/// Interface for triggers which can be used to trigger a <see cref="MtMonitorBase"/>.
/// </summary>
public interface IMonitorTrigger
{
/// <summary>
/// Event will be called if the trigger raised.
/// </summary>
event EventHandler Raised;
/// <summary>
/// Returns whether the trigger is started
/// </summary>
bool IsStarted { get; }
/// <summary>
/// Stops the trigger and prevents further calls of the <see cref="Raised"/> event.
/// </summary>
void Stop();
/// <summary>
/// Starts the trigger.
/// </summary>
void Start();
}
}
+68
View File
@@ -0,0 +1,68 @@
using System;
namespace MtApi.Monitors.Triggers
{
/// <summary>
/// Raises the <see cref="Raised"/> event if a bar is closed and a new one started.
/// </summary>
public class NewBarTrigger : IMonitorTrigger
{
#region Fields
private volatile bool _isStarted;
private readonly MtApiClient _apiClient;
#endregion
#region Properties
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public bool IsStarted => _isStarted;
#endregion
#region Events
/// <summary>
/// Event will be called if the trigger raised.
/// </summary>
public event EventHandler Raised;
#endregion
#region ctor
public NewBarTrigger(MtApiClient apiClient)
{
_apiClient = apiClient;
_apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
}
#endregion
#region Public methods
/// <summary>
/// Starts the trigger
/// </summary>
public void Start() => SetIsStarted(true);
/// <summary>
/// Stops the trigger
/// </summary>
public void Stop() => SetIsStarted(false);
#endregion
#region Private methods
private void _apiClient_OnLastTimeBar(object sender, TimeBarArgs e)
{
if (_isStarted)
Raised?.Invoke(this, EventArgs.Empty);
}
private void SetIsStarted(bool value)
{
if (value != _isStarted)
{
_isStarted = value;
if (value)
_apiClient.OnLastTimeBar += _apiClient_OnLastTimeBar;
else
_apiClient.OnLastTimeBar -= _apiClient_OnLastTimeBar;
}
}
#endregion
}
}
@@ -0,0 +1,74 @@
using System;
using System.Timers;
namespace MtApi.Monitors.Triggers
{
public class TimeElapsedTrigger : IMonitorTrigger
{
#region Fields
readonly Timer _timer;
#endregion
#region Properties
/// <summary>
/// Interval for raising the trigger
/// </summary>
public TimeSpan Interval
{
get => TimeSpan.FromMilliseconds(_timer.Interval);
set => _timer.Interval = value.TotalMilliseconds;
}
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public bool IsStarted => _timer.Enabled;
/// <summary>
/// If true, the trigger will raise continuosly after elapsed <see cref="Interval"/>, otherwise the trigger will raise only once after elapsed <see cref="Interval"/>.
/// </summary>
public bool AutoReset { get => _timer.AutoReset; set => _timer.AutoReset = value; }
#endregion
#region Events
/// <summary>
/// Returns true if the trigger is started, otherwise false
/// </summary>
public event EventHandler Raised;
#endregion
#region ctor
/// <summary>
/// Constructor for initializing TimeElapsedTrigger
/// </summary>
/// <param name="time">Defines the interval for raising the event.</param>
/// <param name="autoReset">If true, the trigger will raise continuosly after elapsed <see cref="Interval"/>, otherwise the trigger will raise only once after elapsed <see cref="Interval"/>.</param>
public TimeElapsedTrigger(TimeSpan time, bool autoReset = true)
{
_timer = new Timer(time.TotalMilliseconds);
_timer.Elapsed += _timer_Elapsed;
AutoReset = autoReset;
}
#endregion
#region Public methods
/// <summary>
/// Starts the trigger
/// </summary>
public void Start() => _timer.Start();
/// <summary>
/// Stops the trigger
/// </summary>
public void Stop() => _timer.Stop();
#endregion
#region private methods
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Elapsed -= _timer_Elapsed;
Raised?.Invoke(this, EventArgs.Empty);
_timer.Elapsed += _timer_Elapsed;
}
#endregion
}
}
+66
View File
@@ -0,0 +1,66 @@
## Monitors
Monitors can be used to monitor different changes on Mt4 structs.
## MtMonitorBase
This is the base class for monitoring extensions. If inherited `MtMonitorBase` needs an instance of `MtApiClient` and `IMonitorTrigger`.
`SyncTrigger` (which can be set in the constructor or as Property) can be used to define whether the trigger should be started and stopped as well if `Start()` or `Stop()` will be called on an instance of a child class of `MtMonitorBase`.
Keep in mind: If an `IMonitorTrigger` will be used for several monitors, `SyncTrigger` set to `true` would cause that all monitors related to this trigger would stop:
```
var fooTrigger = new FooTrigger();
var fooMonitor = new FooMonitor(apiClient, fooTrigger, true);
var barMonitor = new FooMonitor(apiClient, fooTrigger, false);
fooTrigger.Start();
barMonitor.Start();
fooMonitor.Start();
fooMonitor.Stop(); //Because of SyncTrigger = true in the constructor of FooMonitor, fooTrigger.Stop() were triggered as well. Therefore barMonitor will not get any further triggers.
```
## IMonitorTrigger
An `IMonitorTrigger` is for defining when the monitor should check whether his conditions are met for invoking his event.
There are already two `IMonitorTrigger`s which can be used:
### NewBarTrigger
Triggers when a new bar starts
### TimeElapsedTrigger
Triggers when a defined time elapsed
## Default monitors:
There are already two different monitors defined. You can extend them or define new ones by inheriting from `MtMonitorBase`.
### TradeMonitor
Can be used to get updates on new opened trades or closed trades.
## ModifiedOrdersMonitor
Can be used to get updates on modified trades (takeprofit, stoploss, operation).
`OrderModifiedTypes` defines which modifications should be monitored:
1. `None` would cause no monitoring. But please use `Start()` and `Stop()` instead.
2. `TakeProfit` would cause observing whether the TakeProfit were changed.
3. `StopLoss` would cause observing whether the StopLoss were changed.
4. `Operation` would cause observing trades which changed from a stop / limit order to an open order.
5. `All` would cause observing all above defined.
Because `OrderModifiedTypes` is defined with the Flag-Attribute, you can combine the above monitoring types with a pipe: `OrderModifiedTypes.TakeProfit | OrderModifiedTypes.StopLoss`.
### Example
```
var orderModifyMonitor = new ModifiedOrdersMonitor(
_apiClient,
new MtApi.Monitors.Triggers.TimeElapsedTrigger(TimeSpan.FromSeconds(1)),
OrderModifiedTypes.All,
true
);
orderModifyMonitor.OrdersModified += OrderModifyMonitor_OrdersModified;
orderModifyMonitor.Start();
private void OrderModifyMonitor_OrdersModified(object sender, ModifiedOrdersEventArgs e)
{
//Receives the event
}
```
+8
View File
@@ -76,6 +76,14 @@
<Compile Include="EnumTerminalInfoInteger.cs" />
<Compile Include="FlagFontStyle.cs" />
<Compile Include="Monitors\AvailabilityOrdersEventArgs.cs" />
<Compile Include="Monitors\OrderModification\ModifiedOrdersEventArgs.cs" />
<Compile Include="Monitors\OrderModification\ModifiedOrdersMonitor.cs" />
<Compile Include="Monitors\OrderModification\MtModifiedOrder.cs" />
<Compile Include="Monitors\MtMonitorBase.cs" />
<Compile Include="Monitors\OrderModification\OrderModifiedTypes.cs" />
<Compile Include="Monitors\Triggers\IMonitorTrigger.cs" />
<Compile Include="Monitors\Triggers\NewBarTrigger.cs" />
<Compile Include="Monitors\Triggers\TimeElapsedTrigger.cs" />
<Compile Include="MqlRates.cs" />
<Compile Include="MqlTick.cs" />
<Compile Include="MtChartEvent.cs" />
+68 -1
View File
@@ -26,6 +26,8 @@ namespace MtApi
#endregion
#region Private Fields
private static readonly MtLog Log = LogConfigurator.GetLogger(typeof(MtApiClient));
private MtClient _client;
private readonly object _locker = new object();
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
@@ -37,7 +39,12 @@ namespace MtApi
public MtApiClient()
{
LogConfigurator.Setup(LogProfileName);
#if (DEBUG)
const LogLevel logLevel = LogLevel.Debug;
#else
const LogLevel logLevel = LogLevel.Info;
#endif
LogConfigurator.Setup(LogProfileName, logLevel);
}
#endregion
@@ -49,6 +56,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(string host, int port)
{
Log.Info($"BeginConnect: host = {host}, port = {port}");
Task.Factory.StartNew(() => Connect(host, port));
}
@@ -58,6 +66,7 @@ namespace MtApi
///<param name="port">Port of host connection (default 8222) </param>
public void BeginConnect(int port)
{
Log.Info($"BeginConnect: port = {port}");
Task.Factory.StartNew(() => Connect(port));
}
@@ -66,6 +75,7 @@ namespace MtApi
///</summary>
public void BeginDisconnect()
{
Log.Info("BeginDisconnect called.");
Task.Factory.StartNew(() => Disconnect(false));
}
@@ -251,6 +261,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic, DateTime expiration, Color arrowColor)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}, expiration = {expiration}, arrowColor = {arrowColor}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -271,6 +283,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic, DateTime expiration)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}, expiration = {expiration}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -290,6 +304,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment, int magic)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -308,6 +324,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
, string comment)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -324,6 +342,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -339,6 +359,8 @@ namespace MtApi
public int OrderSend(string symbol, TradeOperation cmd, double volume, string price, int slippage, double stoploss, double takeprofit)
{
Log.Debug($"OrderSend: symbol = {symbol}, cmd = {cmd}, volume = {volume}, price = {price}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}");
double dPrice;
return double.TryParse(price, out dPrice) ?
OrderSend(symbol, cmd, volume, dPrice, slippage, stoploss, takeprofit) : 0;
@@ -346,6 +368,8 @@ namespace MtApi
public int OrderSendBuy(string symbol, double volume, int slippage)
{
Log.Debug($"OrderSendBuy: symbol = {symbol}, volume = {volume}, slippage = {slippage}");
return OrderSendBuy(symbol, volume, slippage, 0, 0, null, 0);
}
@@ -366,6 +390,8 @@ namespace MtApi
public int OrderSendBuy(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic)
{
Log.Debug($"OrderSendBuy: symbol = {symbol}, volume = {volume}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -382,6 +408,8 @@ namespace MtApi
public int OrderSendSell(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic)
{
Log.Debug($"OrderSendSell: symbol = {symbol}, volume = {volume}, slippage = {slippage}, stoploss = {stoploss}, takeprofit = {takeprofit}, comment = {comment}, magic = {magic}");
var response = SendRequest<OrderSendResponse>(new OrderSendRequest
{
Symbol = symbol,
@@ -398,6 +426,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, double price, int slippage, Color color)
{
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, price = {price}, slippage = {slippage}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest
{
Ticket = ticket,
@@ -411,6 +441,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, double price, int slippage)
{
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, price = {price}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest
{
Ticket = ticket,
@@ -423,6 +455,8 @@ namespace MtApi
public bool OrderClose(int ticket, double lots, int slippage)
{
Log.Debug($"OrderClose: ticket = {ticket}, lots = {lots}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest
{
Ticket = ticket,
@@ -434,6 +468,8 @@ namespace MtApi
public bool OrderClose(int ticket, int slippage)
{
Log.Debug($"OrderClose: ticket = {ticket}, slippage = {slippage}");
var response = SendRequest<ResponseBase>(new OrderCloseRequest
{
Ticket = ticket,
@@ -444,6 +480,8 @@ namespace MtApi
public bool OrderCloseBy(int ticket, int opposite, Color color)
{
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderCloseByRequest
{
Ticket = ticket,
@@ -455,6 +493,8 @@ namespace MtApi
public bool OrderCloseBy(int ticket, int opposite)
{
Log.Debug($"OrderCloseBy: ticket = {ticket}, opposite = {opposite}");
var response = SendRequest<ResponseBase>(new OrderCloseByRequest
{
Ticket = ticket,
@@ -465,6 +505,8 @@ namespace MtApi
public bool OrderDelete(int ticket, Color color)
{
Log.Debug($"OrderDelete: ticket = {ticket}, color = {color}");
var response = SendRequest<ResponseBase>(new OrderDeleteRequest
{
Ticket = ticket,
@@ -475,6 +517,8 @@ namespace MtApi
public bool OrderDelete(int ticket)
{
Log.Debug($"OrderDelete: ticket = {ticket}");
var response = SendRequest<ResponseBase>(new OrderDeleteRequest
{
Ticket = ticket,
@@ -484,6 +528,8 @@ namespace MtApi
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration, Color arrowColor)
{
Log.Debug($"OrderModify: ticket = {ticket}, price = {price}, stoploss = {stoploss}, takeprofit = {takeprofit}, expiration = {expiration}, arrowColor = {arrowColor}");
var response = SendRequest<ResponseBase>(new OrderModifyRequest
{
Ticket = ticket,
@@ -498,6 +544,8 @@ namespace MtApi
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration)
{
Log.Debug($"OrderModify: ticket = {ticket}, price = {price}, stoploss = {stoploss}, takeprofit = {takeprofit}, expiration = {expiration}");
var response = SendRequest<ResponseBase>(new OrderModifyRequest
{
Ticket = ticket,
@@ -516,6 +564,8 @@ namespace MtApi
public bool OrderSelect(int index, OrderSelectMode select, OrderSelectSource pool)
{
Log.Debug($"OrderSelect: index = {index}, select = {select}, pool = {pool}");
var commandParameters = new ArrayList { index, (int)select, (int)pool };
return SendCommand<bool>(MtCommandType.OrderSelect, commandParameters);
}
@@ -994,6 +1044,12 @@ namespace MtApi
return MtApiTimeConverter.ConvertFromMtTime(commandResponse);
}
public DateTime TimeGMT()
{
var commandResponse = SendCommand<int>(MtCommandType.TimeGMT, null);
return MtApiTimeConverter.ConvertFromMtTime(commandResponse);
}
public int TimeDay(DateTime date)
{
var commandParameters = new ArrayList { MtApiTimeConverter.ConvertToMtTime(date) };
@@ -2888,6 +2944,8 @@ namespace MtApi
{
client.Dispose();
message = string.IsNullOrEmpty(client.Host) ? $"Failed connection to localhost:{client.Port}. {e.Message}" : $"Failed connection to {client.Host}:{client.Port}. {e.Message}";
Log.Warn(message);
}
if (state == MtConnectionState.Connected)
@@ -2900,6 +2958,8 @@ namespace MtApi
_client.ServerFailed += _client_ServerFailed;
_client.MtEventReceived += _client_MtEventReceived;
message = string.IsNullOrEmpty(client.Host) ? $"Connected to localhost:{client.Port}" : $"Connected to { client.Host}:{client.Port}";
Log.Info(message);
}
_connectionState = state;
@@ -2967,6 +3027,7 @@ namespace MtApi
_connectionState = state;
}
Log.Info(message);
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(state, message));
}
@@ -2978,6 +3039,7 @@ namespace MtApi
var client = Client;
if (client == null)
{
Log.Warn("SendCommand: No connection");
throw new MtConnectionException("No connection");
}
@@ -2987,16 +3049,19 @@ namespace MtApi
}
catch (CommunicationException ex)
{
Log.Warn($"SendCommand: {ex.Message}");
throw new MtConnectionException(ex.Message, ex);
}
if (response == null)
{
Log.Warn("SendCommand: Response from MetaTrader is null");
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
}
if (response.ErrorCode != 0)
{
Log.Warn($"SendCommand: ErrorCode = {response.ErrorCode}. {response}");
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ToString());
}
@@ -3020,12 +3085,14 @@ namespace MtApi
if (res == null)
{
Log.Warn("SendRequest: Response from MetaTrader is null");
throw new MtExecutionException(MtErrorCode.MtApiCustomError, "Response from MetaTrader is null");
}
var response = JsonConvert.DeserializeObject<T>(res);
if (response.ErrorCode != 0)
{
Log.Warn($"SendRequest: ErrorCode = {response.ErrorCode}. {response}");
throw new MtExecutionException((MtErrorCode)response.ErrorCode, response.ErrorMessage);
}
+1
View File
@@ -111,6 +111,7 @@
TimeSeconds = 86,
TimeYear = 87,
Year = 88,
TimeGMT = 281,
//Global Variables
GlobalVariableCheck = 89,

Some files were not shown because too many files have changed in this diff Show More