diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@Bars/Bars.m b/Examples/MatLab/AdvancedExample/+DataStore/@Bars/Bars.m new file mode 100644 index 00000000..0715746b --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@Bars/Bars.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@Deal/Deal.m b/Examples/MatLab/AdvancedExample/+DataStore/@Deal/Deal.m new file mode 100644 index 00000000..a12fa235 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@Deal/Deal.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@Position/Position.m b/Examples/MatLab/AdvancedExample/+DataStore/@Position/Position.m new file mode 100644 index 00000000..1ffd9629 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@Position/Position.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@Tick/Tick.m b/Examples/MatLab/AdvancedExample/+DataStore/@Tick/Tick.m new file mode 100644 index 00000000..47775aff --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@Tick/Tick.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@Ticks/Ticks.m b/Examples/MatLab/AdvancedExample/+DataStore/@Ticks/Ticks.m new file mode 100644 index 00000000..132465dd --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@Ticks/Ticks.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/+DataStore/@TradingData/TradingData.m b/Examples/MatLab/AdvancedExample/+DataStore/@TradingData/TradingData.m new file mode 100644 index 00000000..4e34c9c9 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/+DataStore/@TradingData/TradingData.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/Api/Mt5Api.m b/Examples/MatLab/AdvancedExample/Api/Mt5Api.m new file mode 100644 index 00000000..5cceb5e2 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Api/Mt5Api.m @@ -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 + diff --git a/Examples/MatLab/AdvancedExample/Api/Mt5Enums.m b/Examples/MatLab/AdvancedExample/Api/Mt5Enums.m new file mode 100644 index 00000000..b7af492a --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Api/Mt5Enums.m @@ -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 \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/Api/cntMt5Api_apiResult.m b/Examples/MatLab/AdvancedExample/Api/cntMt5Api_apiResult.m new file mode 100644 index 00000000..6659cab0 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Api/cntMt5Api_apiResult.m @@ -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 \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/Api/cntMt5Api_timeseries.m b/Examples/MatLab/AdvancedExample/Api/cntMt5Api_timeseries.m new file mode 100644 index 00000000..8e145b17 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Api/cntMt5Api_timeseries.m @@ -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 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 \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/DLL/MtApi5.dll b/Examples/MatLab/AdvancedExample/DLL/MtApi5.dll new file mode 100644 index 00000000..bc44db0b Binary files /dev/null and b/Examples/MatLab/AdvancedExample/DLL/MtApi5.dll differ diff --git a/Examples/MatLab/AdvancedExample/Slack/MakeSlackAttachment.m b/Examples/MatLab/AdvancedExample/Slack/MakeSlackAttachment.m new file mode 100644 index 00000000..c4454e3a --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/MakeSlackAttachment.m @@ -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, , , strColor, ...) +% Usage: sAttachment = MakeSlackAttachment(..., {strField1Title, strField1Value, }, {strField2Title, strField2Value, }, ...) +% +% Creates an attachment structure, to send along with a Slack notification +% using 'SendSlackNotification'. See +% and 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 +% 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 --- diff --git a/Examples/MatLab/AdvancedExample/Slack/README.md b/Examples/MatLab/AdvancedExample/Slack/README.md new file mode 100644 index 00000000..55120ec5 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/README.md @@ -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]: ', '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). diff --git a/Examples/MatLab/AdvancedExample/Slack/SendSlackNotification.m b/Examples/MatLab/AdvancedExample/Slack/SendSlackNotification.m new file mode 100644 index 00000000..816897cd --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/SendSlackNotification.m @@ -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, , ...) +% SendSlackNotification(..., sAttachment) +% SendSlackNotification(..., {sAttachment1 sAttachment2}) +% +% Use the Slack webhooks API to send a notification to a Slack channel or +% user. See See , +% and +% 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 +% 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 --- diff --git a/Examples/MatLab/AdvancedExample/Slack/TODO.md b/Examples/MatLab/AdvancedExample/Slack/TODO.md new file mode 100644 index 00000000..63bbd3a8 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/TODO.md @@ -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. diff --git a/Examples/MatLab/AdvancedExample/Slack/private/README_JSONLAB.txt b/Examples/MatLab/AdvancedExample/Slack/private/README_JSONLAB.txt new file mode 100644 index 00000000..071a0729 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/README_JSONLAB.txt @@ -0,0 +1,336 @@ +=============================================================================== += JSONlab = += An open-source MATLAB/Octave JSON encoder and decoder = +=============================================================================== + +*Copyright (c) 2011-2014 Qianqian Fang +*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 === +
+  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 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
+
+ +=== savejson.m === + +
+  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 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')
+
+ +=== loadubjson.m === + +
+  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 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
+
+ +=== saveubjson.m === + +
+  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 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')
+
+ + +=== 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). diff --git a/Examples/MatLab/AdvancedExample/Slack/private/http_createHeader.m b/Examples/MatLab/AdvancedExample/Slack/private/http_createHeader.m new file mode 100644 index 00000000..0e80241f --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/http_createHeader.m @@ -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); \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/Slack/private/http_paramsToString.m b/Examples/MatLab/AdvancedExample/Slack/private/http_paramsToString.m new file mode 100644 index 00000000..376a0fa1 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/http_paramsToString.m @@ -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 +end + +switch encodeOption + case 1 + header = http_createHeader('Content-Type','application/x-www-form-urlencoded'); +end + + +end \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/Slack/private/jsonopt.m b/Examples/MatLab/AdvancedExample/Slack/private/jsonopt.m new file mode 100644 index 00000000..4f0f5a0f --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/jsonopt.m @@ -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 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 + diff --git a/Examples/MatLab/AdvancedExample/Slack/private/loadjson.m b/Examples/MatLab/AdvancedExample/Slack/private/loadjson.m new file mode 100644 index 00000000..f4347f87 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/loadjson.m @@ -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 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)) '' 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(pos1 && 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 + diff --git a/Examples/MatLab/AdvancedExample/Slack/private/loadubjson.m b/Examples/MatLab/AdvancedExample/Slack/private/loadubjson.m new file mode 100644 index 00000000..82ee7b16 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/loadubjson.m @@ -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 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)) '' 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(pos1 && 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 + diff --git a/Examples/MatLab/AdvancedExample/Slack/private/mergestruct.m b/Examples/MatLab/AdvancedExample/Slack/private/mergestruct.m new file mode 100644 index 00000000..61b678b1 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/mergestruct.m @@ -0,0 +1,33 @@ +function s=mergestruct(s1,s2) +% +% s=mergestruct(s1,s2) +% +% merge two struct objects into one +% +% authors:Qianqian Fang (fangq 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 + diff --git a/Examples/MatLab/AdvancedExample/Slack/private/savejson.m b/Examples/MatLab/AdvancedExample/Slack/private/savejson.m new file mode 100644 index 00000000..e2458be7 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/savejson.m @@ -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 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(i1) txt=sprintf('%s\n%s]',txt,padding2); end + if(j1) 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(e1)+(len>1))); + if(i1) txt=sprintf('%s\n%s]',txt,padding2); end + if(j1) 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 diff --git a/Examples/MatLab/AdvancedExample/Slack/private/saveubjson.m b/Examples/MatLab/AdvancedExample/Slack/private/saveubjson.m new file mode 100644 index 00000000..06dd2b93 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/saveubjson.m @@ -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 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(:)'; diff --git a/Examples/MatLab/AdvancedExample/Slack/private/urlread2.m b/Examples/MatLab/AdvancedExample/Slack/private/urlread2.m new file mode 100644 index 00000000..b552861c --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/urlread2.m @@ -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 diff --git a/Examples/MatLab/AdvancedExample/Slack/private/urlread_notes.txt b/Examples/MatLab/AdvancedExample/Slack/private/urlread_notes.txt new file mode 100644 index 00000000..8257f092 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/urlread_notes.txt @@ -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. + diff --git a/Examples/MatLab/AdvancedExample/Slack/private/varargin2struct.m b/Examples/MatLab/AdvancedExample/Slack/private/varargin2struct.m new file mode 100644 index 00000000..8ff633c5 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/Slack/private/varargin2struct.m @@ -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 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}) && ihttp://UndocumentedMatlab.com/blog/cprintf/ +% +% 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 MathWorks File Exchange +% +% 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 - 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 = ['' format '']; + + % 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 = ['' format '']; + 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(' '); %fprintf(' \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 % not good because style='text' is evaled! + %if ~isempty(styleNum) + if any(style==' ' | style==',' | style==';') + style = str2num(style); %#ok + 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 + 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 here for details.\n\n'); + url = 'http://UndocumentedMatlab.com/blog/cprintf/'; + fprintf(['Technical description: ' url '\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 \ No newline at end of file diff --git a/Examples/MatLab/AdvancedExample/logging4matlab/+logging/getLogger.m b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/getLogger.m new file mode 100644 index 00000000..eef4d3c1 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/getLogger.m @@ -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 diff --git a/Examples/MatLab/AdvancedExample/logging4matlab/+logging/logging.m b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/logging.m new file mode 100644 index 00000000..43c354d8 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/logging.m @@ -0,0 +1,320 @@ +classdef logging < handle + %LOGGING Simple logging framework. + % + % Author: + % Dominique Orban + % 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 diff --git a/Examples/MatLab/AdvancedExample/logging4matlab/+logging/testspeed.m b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/testspeed.m new file mode 100644 index 00000000..2234f322 --- /dev/null +++ b/Examples/MatLab/AdvancedExample/logging4matlab/+logging/testspeed.m @@ -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 diff --git a/Examples/MatLab/AdvancedExample/logging4matlab/LICENSE b/Examples/MatLab/AdvancedExample/logging4matlab/LICENSE new file mode 100644 index 00000000..efb2aa4f --- /dev/null +++ b/Examples/MatLab/AdvancedExample/logging4matlab/LICENSE @@ -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. diff --git a/Examples/MatLab/AdvancedExample/logging4matlab/README.md b/Examples/MatLab/AdvancedExample/logging4matlab/README.md new file mode 100644 index 00000000..efe645ff --- /dev/null +++ b/Examples/MatLab/AdvancedExample/logging4matlab/README.md @@ -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! diff --git a/Examples/MatLab/AdvancedExample/run.m b/Examples/MatLab/AdvancedExample/run.m new file mode 100644 index 00000000..f9bab46a --- /dev/null +++ b/Examples/MatLab/AdvancedExample/run.m @@ -0,0 +1,9 @@ + + +addpath('Api\') +addpath('logging4matlab\') +addpath('Slack\') +addpath('DLL\') + + +[ClientResult] = TestClient_basic(); \ No newline at end of file