Saturday, 30 June 2012

Machine Learning Course Completed

I'm pleased to say that I have now completed Andrew Ng's machine learning course, which is offered through Coursera. This post is not intended to be a review of the course, which in my opinion is extremely good and very useful, but more of a reflection of my thoughts and what I think will be useful for me personally.

Firstly, I was pleasantly surprised that the software/programming language of instruction was Octave, which regular readers of this blog will know is my main software of choice. Apart from learning the concepts of ML, I also picked up some handy tips for Octave programming, and more importantly for me I now have a set of working Octave ML functions that I can use immediately in my system development.

In my previous post I mentioned that my first attempt at using ML will be to use a Neural Net to classify market types. As background to this, readers might be interested in a pdf file of the video lectures, available from here, which was put together and posted on the course discussion forum by another student - I think this is very good and all credit to said student, José Soares Augusto.

Due to the honour code ( or honor code for American readers ) of the course I will be unable to post the code that I wrote for the programming assignments. However, I do feel that I can post the code shown in the code box below, as the copyright notice allows it. A few slight changes I made are noted in the copyright notice. This is a minimisation function that was used in the training of the Neural Net assignment and was provided in the assignment download.
function [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
% Minimize a continuous differentialble multivariate function. Starting point
% is given by "X" (D by 1), and the function named in the string "f", must
% return a function value and a vector of partial derivatives. The Polack-
% Ribiere flavour of conjugate gradients is used to compute search directions,
% and a line search using quadratic and cubic polynomial approximations and the
% Wolfe-Powell stopping criteria is used together with the slope ratio method
% for guessing initial step sizes. Additionally a bunch of checks are made to
% make sure that exploration is taking place and that extrapolation will not
% be unboundedly large. The "length" gives the length of the run: if it is
% positive, it gives the maximum number of line searches, if negative its
% absolute gives the maximum allowed number of function evaluations. You can
% (optionally) give "length" a second component, which will indicate the
% reduction in function value to be expected in the first line-search (defaults
% to 1.0). The function returns when either its length is up, or if no further
% progress can be made (ie, we are at a minimum, or so close that due to
% numerical problems, we cannot get any closer). If the function terminates
% within a few iterations, it could be an indication that the function value
% and derivatives are not consistent (ie, there may be a bug in the
% implementation of your "f" function). The function returns the found
% solution "X", a vector of function values "fX" indicating the progress made
% and "i" the number of iterations (line searches or function evaluations,
% depending on the sign of "length") used.
%
% Usage: [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5)
%
% See also: checkgrad 
%
% Copyright (C) 2001 and 2002 by Carl Edward Rasmussen. Date 2002-02-13
%
% (C) Copyright 1999, 2000 & 2001, Carl Edward Rasmussen
% 
% Permission is granted for anyone to copy, use, or modify these
% programs and accompanying documents for purposes of research or
% education, provided this copyright notice is retained, and note is
% made of any changes that have been made.
% 
% These programs and documents are distributed without any warranty,
% express or implied.  As the programs were written for research
% purposes only, they have not been tested to the degree that would be
% advisable in any important application.  All use of these programs is
% entirely at the user's own risk.
%
% [ml-class] Changes Made:
% 1) Function name and argument specifications
% 2) Output display
%
% Dekalog Changes Made:
% Some lines have been altered, changing | to || and & to &&.
% This is to avoid "possible Matlab-style short-circuit operator" warnings
% being given when code is run under Octave. The lines where these changes
% have been made are indicated by comments at the end of each respective line. 

% Read options
if exist('options', 'var') && ~isempty(options) && isfield(options, 'MaxIter')
    length = options.MaxIter;
else
    length = 100;
end


RHO = 0.01;                            % a bunch of constants for line searches
SIG = 0.5;       % RHO and SIG are the constants in the Wolfe-Powell conditions
INT = 0.1;    % don't reevaluate within 0.1 of the limit of the current bracket
EXT = 3.0;                    % extrapolate maximum 3 times the current bracket
MAX = 20;                         % max 20 function evaluations per line search
RATIO = 100;                                      % maximum allowed slope ratio

argstr = ['feval(f, X'];                      % compose string used to call function
for i = 1:(nargin - 3)
  argstr = [argstr, ',P', int2str(i)];
end
argstr = [argstr, ')'];

if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end
S=['Iteration '];

i = 0;                                            % zero the run length counter
ls_failed = 0;                             % no previous line search has failed
fX = [];
[f1 df1] = eval(argstr);                      % get function value and gradient
i = i + (length<0);                                            % count epochs?!
s = -df1;                                        % search direction is steepest
d1 = -s'*s;                                                 % this is the slope
z1 = red/(1-d1);                                  % initial step is red/(|s|+1)

while i < abs(length)                                      % while not finished
  i = i + (length>0);                                      % count iterations?!

  X0 = X; f0 = f1; df0 = df1;                   % make a copy of current values
  X = X + z1*s;                                             % begin line search
  [f2 df2] = eval(argstr);
  i = i + (length<0);                                          % count epochs?!
  d2 = df2'*s;
  f3 = f1; d3 = d1; z3 = -z1;             % initialize point 3 equal to point 1
  if length>0, M = MAX; else M = min(MAX, -length-i); end
  success = 0; limit = -1;                     % initialize quanteties
  while 1
    while ((f2 > f1+z1*RHO*d1) || (d2 > -SIG*d1)) && (M > 0) % | and & changed to || and && to avoid "possible Matlab-style short-circuit operator" warning 
      limit = z1;                                         % tighten the bracket
      if f2 > f1
        z2 = z3 - (0.5*d3*z3*z3)/(d3*z3+f2-f3);                 % quadratic fit
      else
        A = 6*(f2-f3)/z3+3*(d2+d3);                                 % cubic fit
        B = 3*(f3-f2)-z3*(d3+2*d2);
        z2 = (sqrt(B*B-A*d2*z3*z3)-B)/A;       % numerical error possible - ok!
      end
      if isnan(z2) || isinf(z2)     % | changed to || to avoid "possible Matlab-style short-circuit operator" warning 
        z2 = z3/2;                  % if we had a numerical problem then bisect
      end
      z2 = max(min(z2, INT*z3),(1-INT)*z3);  % don't accept too close to limits
      z1 = z1 + z2;                                           % update the step
      X = X + z2*s;
      [f2 df2] = eval(argstr);
      M = M - 1; i = i + (length<0);                           % count epochs?!
      d2 = df2'*s;
      z3 = z3-z2;                    % z3 is now relative to the location of z2
    end
    if f2 > f1+z1*RHO*d1 || d2 > -SIG*d1                    % | changed to || to avoid "possible Matlab-style short-circuit operator" warning
      break;                                                % this is a failure
    elseif d2 > SIG*d1
      success = 1; break;                                             % success
    elseif M == 0
      break;                                                          % failure
    end
    A = 6*(f2-f3)/z3+3*(d2+d3);                      % make cubic extrapolation
    B = 3*(f3-f2)-z3*(d3+2*d2);
    z2 = -d2*z3*z3/(B+sqrt(B*B-A*d2*z3*z3));        % num. error possible - ok!
    if ~isreal(z2) || isnan(z2) || isinf(z2) || z2 < 0   % num prob or wrong sign? % | changed to || to avoid "possible Matlab-style short-circuit operator" warning
      if limit < -0.5                               % if we have no upper limit
        z2 = z1 * (EXT-1);                 % the extrapolate the maximum amount
      else
        z2 = (limit-z1)/2;                                   % otherwise bisect
      end
    elseif (limit > -0.5) && (z2+z1 > limit)       % extraplation beyond max?   % & changed to && to avoid "possible Matlab-style short-circuit operator" warning
      z2 = (limit-z1)/2;                                               % bisect
    elseif (limit < -0.5) && (z2+z1 > z1*EXT)      % extrapolation beyond limit % & changed to && to avoid "possible Matlab-style short-circuit operator" warning
      z2 = z1*(EXT-1.0);                           % set to extrapolation limit
    elseif z2 < -z3*INT
      z2 = -z3*INT;
    elseif (limit > -0.5) && (z2 < (limit-z1)*(1.0-INT))   % too close to limit? % & changed to && to avoid "possible Matlab-style short-circuit operator" warning
      z2 = (limit-z1)*(1.0-INT);
    end
    f3 = f2; d3 = d2; z3 = -z2;                  % set point 3 equal to point 2
    z1 = z1 + z2; X = X + z2*s;                      % update current estimates
    [f2 df2] = eval(argstr);
    M = M - 1; i = i + (length<0);                             % count epochs?!
    d2 = df2'*s;
  end                                                      % end of line search

  if success                                         % if line search succeeded
    f1 = f2; fX = [fX' f1]';
    fprintf('%s %4i | Cost: %4.6e\r', S, i, f1);
    s = (df2'*df2-df1'*df2)/(df1'*df1)*s - df2;      % Polack-Ribiere direction
    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
    d2 = df1'*s;
    if d2 > 0                                      % new slope must be negative
      s = -df1;                              % otherwise use steepest direction
      d2 = -s'*s;    
    end
    z1 = z1 * min(RATIO, d1/(d2-realmin));          % slope ratio but max RATIO
    d1 = d2;
    ls_failed = 0;                              % this line search did not fail
  else
    X = X0; f1 = f0; df1 = df0;  % restore point from before failed line search
    if ls_failed || i > abs(length)         % line search failed twice in a row % | changed to || to avoid "possible Matlab-style short-circuit operator" warning
      break;                             % or we ran out of time, so we give up
    end
    tmp = df1; df1 = df2; df2 = tmp;                         % swap derivatives
    s = -df1;                                                    % try steepest
    d1 = -s'*s;
    z1 = 1/(1-d1);                     
    ls_failed = 1;                                    % this line search failed
  end
  if exist('OCTAVE_VERSION')
    fflush(stdout);
  end
end
fprintf('\n');

Finally, the last set of videos talked about "Artificial Data Synthesis," otherwise known as creating your own data for training purposes. This is basically what I had planned to do anyway ( see previous post ), but it is nice to learn that it is standard, accepted practice in the ML world. The first such way of creating data, in the context of Photo OCR, is shown below
where various font libraries are used against random backgrounds. I think this very much mirrors my planned approach of training on repeated sets of my "ideal time series" construct. However, another approach which could be used is "data distortion," shown in this next image
which is an approach that my creating synthetic data using FFT might be useful for, or alternatively a correlation and cointegration approach as shown in R code in this Quantitative Finance thread.

All in all, I'm quite excited by the possibilities of my new found knowledge, and I fully expect that in time, after development and testing, any Neural Net I develop will in fact replace my current Naive Bayesian classifier.

Friday, 22 June 2012

Neural Net to Replace my Bayesian Classifier?

Having more or less completed the machine learning course alluded to in my last post I thought I would have a go at programming a neural net as a possible replacement for my Naive Bayesian Classifier. In said machine learning course there was a task to programme a neural net to recognise the digits 0 to 9 inclusive, as shown below.
It struck me whilst completing this task that I could use the code I was writing to recognise price patterns as a way of classifying the market into one of my 5 states. Quickly writing a pre-processing script in Octave I have been able to produce scaled "snapshots" of my "ideal" markets types thus:-
As can be seen, different market types and periods produce distinctive looking plots, and it is my hope that a neural net can be trained to identify them and thus act as a market classifier. More in a future post.

Wednesday, 6 June 2012

Creation of a Simple Benchmark Suite

For some time now I have been toying with the idea of creating a simple benchmark suite to compare my own back test system performance with that of some public domain trading systems. I decided to select a few examples from the Trading Blox Users' Guide, specifically:
  • exponential moving average crossovers of periods 10-20 and 20-50
  • triple moving average crossover system with periods 10-20-50
  • Bollinger band breakouts of periods 20 and 50 with 1 & 2 standard deviations for exits and entries
  • donchian channel breakouts with periods 20-10 and 50-25
This is a total of 7 systems, and in the Rcpp code below these form a sort of "committee" to vote to be either long/short 1 contract, or neutral.

# This function takes as inputs vectors of opening and closing prices
# and creates a basic benchmark output suite of system equity curves 
# for the following basic trend following systems
# exponential moving average crossovers of 10-20 and 20-50
# triple moving average crossovers of 10-20-50
# bollinger band breakouts of 20 and 50 with 1 & 2 standard deviations
# donchian channel breakouts of 20-10 and 50-25
# The libraries required to compile this function are
# "Rcpp," "inline" and "compiler." The function is compiled by the command
# > source("basic_benchmark_equity.r") in the console/terminal.

library(Rcpp) # load the required library
library(inline) # load the required library
library(compiler) # load the required library

src <- '
#include 
#include 

Rcpp::NumericVector open(a) ;
Rcpp::NumericVector close(b) ;
Rcpp::NumericVector market_mode(c) ;
Rcpp::NumericVector kalman(d) ;
Rcpp::NumericVector tick_size(e) ;
Rcpp::NumericVector tick_value(f) ;
int n = open.size() ;
Rcpp::NumericVector sma_10(n) ;
Rcpp::NumericVector sma_20(n) ;
Rcpp::NumericVector sma_50(n) ;
Rcpp::NumericVector std_20(n) ;
Rcpp::NumericVector std_50(n) ;

// create equity output vectors
Rcpp::NumericVector market_mode_long_eq(n) ;
Rcpp::NumericVector market_mode_short_eq(n) ;
Rcpp::NumericVector market_mode_composite_eq(n) ;
Rcpp::NumericVector sma_10_20_eq(n) ; 
Rcpp::NumericVector sma_20_50_eq(n) ; 
Rcpp::NumericVector tma_eq(n) ; 
Rcpp::NumericVector bbo_20_eq(n) ;
Rcpp::NumericVector bbo_50_eq(n) ;
Rcpp::NumericVector donc_20_eq(n) ;
Rcpp::NumericVector donc_50_eq(n) ;
Rcpp::NumericVector composite_eq(n) ; 

// position vectors for benchmark systems
Rcpp::NumericVector sma_10_20_pv(1) ;
sma_10_20_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector sma_20_50_pv(1) ;
sma_20_50_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector tma_pv(1) ;
tma_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector bbo_20_pv(1) ;
bbo_20_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector bbo_50_pv(1) ;
bbo_50_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector donc_20_pv(1) ;
donc_20_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector donc_50_pv(1) ;
donc_50_pv[0] = 0.0 ; // initialise to zero, no position

Rcpp::NumericVector comp_pv(1) ;
comp_pv[0] = 0.0 ; // initialise to zero, no position

// fill the equity curve vectors with zeros for "burn in" period
// and create the initial values for all indicators

for ( int ii = 0 ; ii < 50 ; ii++ ) {
    
    if ( ii >= 40 ) {
    sma_10[49] += close[ii] ; }

    if ( ii >= 30 ) {
    sma_20[49] += close[ii] ; }

    sma_50[49] += close[ii] ;

    std_20[ii] = 0.0 ;
    std_50[ii] = 0.0 ;

    market_mode_long_eq[ii] = 0.0 ;
    market_mode_short_eq[ii] = 0.0 ;
    market_mode_composite_eq = 0.0 ;
    sma_10_20_eq[ii] = 0.0 ;
    sma_20_50_eq[ii] = 0.0 ; 
    bbo_20_eq[ii] = 0.0 ;
    bbo_50_eq[ii] = 0.0 ;
    tma_eq[ii] = 0.0 ;
    donc_20_eq[ii] = 0.0 ;
    donc_50_eq[ii] = 0.0 ; 
    composite_eq[ii] = 0.0 ; } // end of initialising loop

    sma_10[49] = sma_10[49] / 10.0 ;
    sma_20[49] = sma_20[49] / 20.0 ;
    sma_50[49] = sma_50[49] / 50.0 ;

// the main calculation loop
for ( int ii = 50 ; ii < n-2 ; ii++ ) {

    // calculate the smas
    sma_10[ii] = ( sma_10[ii-1] - sma_10[ii-10] / 10.0 ) + ( close[ii] / 10.0 ) ;
    sma_20[ii] = ( sma_20[ii-1] - sma_20[ii-20] / 20.0 ) + ( close[ii] / 20.0 ) ;
    sma_50[ii] = ( sma_50[ii-1] - sma_50[ii-50] / 50.0 ) + ( close[ii] / 50.0 ) ;

      // calculate the standard deviations
      for ( int jj = 0 ; jj < 50 ; jj++ ) {
    
      if ( jj < 20 ) {
      std_20[ii] += ( close[ii-jj] - sma_20[ii] ) * ( close[ii-jj] - sma_20[ii] )  ; } // end of jj if

      std_50[ii] += ( close[ii-jj] - sma_50[ii] ) * ( close[ii-jj] - sma_50[ii] ) ; } // end of standard deviation loop

    std_20[ii] = sqrt( std_20[ii] / 20.0 ) ;
    std_50[ii] = sqrt( std_50[ii] / 50.0 ) ;

    //-------------------------------------------------------------------------------------------------------------------

    // calculate the equity values of the market modes
    // market_mode uwr and unr long signals
    if ( market_mode[ii] == 1 || market_mode[ii] == 2 ) {
    market_mode_long_eq[ii] = market_mode_long_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ;
    market_mode_short_eq[ii] = market_mode_short_eq[ii-1] ;
    market_mode_composite_eq[ii] = market_mode_composite_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; }

    // market_mode dwr and dnr short signals
    if ( market_mode[ii] == 3 || market_mode[ii] == 4 ) {
    market_mode_long_eq[ii] = market_mode_long_eq[ii-1] ;
    market_mode_short_eq[ii] = market_mode_short_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ;
    market_mode_composite_eq[ii] = market_mode_composite_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; }

    // calculate the equity values of the market modes
    // market_mode cyc long signals
    if ( market_mode[ii] == 0 && kalman[ii] > kalman[ii-1] ) {
    market_mode_long_eq[ii] = market_mode_long_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ;
    market_mode_short_eq[ii] = market_mode_short_eq[ii-1] ;
    market_mode_composite_eq[ii] = market_mode_composite_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; }

    // market_mode cyc short signals
    if ( market_mode[ii] == 0 && kalman[ii] < kalman[ii-1] ) {
    market_mode_long_eq[ii] = market_mode_long_eq[ii-1] ;
    market_mode_short_eq[ii] = market_mode_short_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ;
    market_mode_composite_eq[ii] = market_mode_composite_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; }

    //----------------------------------------------------------------------------------------------------------------------------

    // calculate the equity values and positions of each benchmark system
    // sma_10_20_eq
    if ( sma_10[ii] > sma_20[ii] ) { 
    sma_10_20_eq[ii] = sma_10_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
    sma_10_20_pv[0] = 1.0 ; } // long

    // sma_10_20_eq
    if ( sma_10[ii] < sma_20[ii] ) { 
    sma_10_20_eq[ii] = sma_10_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
    sma_10_20_pv[0] = -1.0 ; } // short

    // sma_10_20_eq
    if ( sma_10[ii] == sma_20[ii] && sma_10[ii-1] > sma_20[ii-1] ) { 
    sma_10_20_eq[ii] = sma_10_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
    sma_10_20_pv[0] = 1.0 ; } // long

    // sma_10_20_eq
    if ( sma_10[ii] == sma_20[ii] && sma_10[ii-1] < sma_20[ii-1] ) { 
    sma_10_20_eq[ii] = sma_10_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
    sma_10_20_pv[0] = -1.0 ; } // short

    //-----------------------------------------------------------------------------------------------------------

    // sma_20_50_eq
    if ( sma_20[ii] > sma_50[ii] ) { 
    sma_20_50_eq[ii] = sma_20_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
    sma_20_50_pv[0] = 1.0 ; } // long

    // sma_20_50_eq
    if ( sma_20[ii] < sma_50[ii] ) { 
    sma_20_50_eq[ii] = sma_20_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
    sma_20_50_pv[0] = -1.0 ; } // short

    // sma_20_50_eq
    if ( sma_20[ii] == sma_50[ii] && sma_20[ii-1] > sma_50[ii-1] ) { 
    sma_20_50_eq[ii] = sma_20_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
    sma_20_50_pv[0] = 1.0 ; } // long

    // sma_20_50_eq
    if ( sma_20[ii] == sma_50[ii] && sma_20[ii-1] < sma_50[ii-1] ) { 
    sma_20_50_eq[ii] = sma_20_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
    sma_20_50_pv[0] = -1.0 ; } // short

    //-----------------------------------------------------------------------------------------------------------

    // tma_eq
    if ( tma_pv[0] == 0.0 ) {

      // default position
      tma_eq[ii] = tma_eq[ii-1] ;

      // unless one of the two following conditions is true

      if ( sma_10[ii] > sma_20[ii] && sma_20[ii] > sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      tma_pv[0] = 1.0 ; } // long

      if ( sma_10[ii] < sma_20[ii] && sma_20[ii] < sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      tma_pv[0] = -1.0 ; } // short

    } // end of tma_pv == 0.0 loop

    if ( tma_pv[0] == 1.0 ) {

      // default long position
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; // long

      // unless one of the two following conditions is true

      if ( sma_10[ii] < sma_20[ii] && sma_10[ii] > sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] ; 
      tma_pv[0] = 0.0 ; } // exit long, go neutral

      if ( sma_10[ii] < sma_20[ii] && sma_20[ii] < sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      tma_pv[0] = -1.0 ; } // short
    
    } // end of tma_pv == 1.0 loop

    if ( tma_pv[0] == -1.0 ) {

      // default short position
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; // short

      // unless one of the two following conditions is true

      if ( sma_10[ii] > sma_20[ii] && sma_10[ii] < sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] ; 
      tma_pv[0] = 0.0 ; } // exit short, go neutral

      if ( sma_10[ii] > sma_20[ii] && sma_20[ii] > sma_50[ii] ) { 
      tma_eq[ii] = tma_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      tma_pv[0] = 1.0 ; } // long

    } // end of tma_pv == -1.0 loop

    //------------------------------------------------------------------------------------------------------------

    // bbo_20_eq
    if ( bbo_20_pv[0] == 0.0 ) {

      // default position
      bbo_20_eq[ii] = bbo_20_eq[ii-1] ;

      // unless one of the two following conditions is true

      if ( close[ii] > sma_20[ii] + 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      bbo_20_pv[0] = 1.0 ; } // long

      if ( close[ii] < sma_20[ii] - 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      bbo_20_pv[0] = -1.0 ; } // short

    } // end of bbo_20_pv == 0.0 loop

    if ( bbo_20_pv[0] == 1.0 ) {

      // default long position
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; // long

      // unless one of the two following conditions is true

      if ( close[ii] < sma_20[ii] + std_20[ii] && close[ii] > sma_20[ii] - 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] ; 
      bbo_20_pv[0] = 0.0 ; } // exit long, go neutral

      if ( close[ii] < sma_20[ii] - 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      bbo_20_pv[0] = -1.0 ; } // short
    
    } // end of bbo_20_pv == 1.0 loop

    if ( bbo_20_pv[0] == -1.0 ) {

      // default short position
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; // short

      // unless one of the two following conditions is true

      if ( close[ii] > sma_20[ii] - std_20[ii] && close[ii] < sma_20[ii] + 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] ; 
      bbo_20_pv[0] = 0.0 ; } // exit short, go neutral

      if ( close[ii] > sma_20[ii] + 2.0 * std_20[ii] ) { 
      bbo_20_eq[ii] = bbo_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      bbo_20_pv[0] = 1.0 ; } // long

    } // end of bbo_20_pv == -1.0 loop

    //-------------------------------------------------------------------------------------------------

    // bbo_50_eq
    if ( bbo_50_pv[0] == 0.0 ) {

      // default position
      bbo_50_eq[ii] = bbo_50_eq[ii-1] ;

      // unless one of the two following conditions is true

      if ( close[ii] > sma_50[ii] + 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      bbo_50_pv[0] = 1.0 ; } // long

      if ( close[ii] < sma_50[ii] - 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      bbo_50_pv[0] = -1.0 ; } // short

    } // end of bbo_50_pv == 0.0 loop

    if ( bbo_50_pv[0] == 1.0 ) {

      // default long position
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; // long

      // unless one of the two following conditions is true

      if ( close[ii] < sma_50[ii] + std_50[ii] && close[ii] > sma_50[ii] - 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] ; 
      bbo_50_pv[0] = 0.0 ; } // exit long, go neutral

      if ( close[ii] < sma_50[ii] - 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      bbo_50_pv[0] = -1.0 ; } // short
    
    } // end of bbo_50_pv == 1.0 loop

    if ( bbo_50_pv[0] == -1.0 ) {

      // default short position
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; // short

      // unless one of the two following conditions is true

      if ( close[ii] > sma_50[ii] - std_50[ii] && close[ii] < sma_50[ii] + 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] ; 
      bbo_50_pv[0] = 0.0 ; } // exit short, go neutral

      if ( close[ii] > sma_50[ii] + 2.0 * std_50[ii] ) { 
      bbo_50_eq[ii] = bbo_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      bbo_50_pv[0] = 1.0 ; } // long

    } // end of bbo_50_pv == -1.0 loop

    //-----------------------------------------------------------------------------------------------------

    // donc_20_eq
    if ( donc_20_pv[0] == 0.0 ) {

      // default position
      donc_20_eq[ii] = donc_20_eq[ii-1] ;

      // unless one of the two following conditions is true

      if ( close[ii] > *std::max_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      donc_20_pv[0] = 1.0 ; } // long

      if ( close[ii] < *std::min_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      donc_20_pv[0] = -1.0 ; } // short

    } // end of donc_20_pv == 0.0 loop

    if ( donc_20_pv[0] == 1.0 ) {

      // default long position
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; // long

      // unless one of the two following conditions is true

      if ( close[ii] < *std::min_element( &close[ii-10], &close[ii] ) && close[ii] > *std::min_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] ; 
      donc_20_pv[0] = 0.0 ; } // exit long, go neutral

      if ( close[ii] < *std::min_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      donc_20_pv[0] = -1.0 ; } // short
    
    } // end of donc_20_pv == 1.0 loop

    if ( donc_20_pv[0] == -1.0 ) {

      // default short position
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; // short

      // unless one of the two following conditions is true

      if ( close[ii] > *std::max_element( &close[ii-10], &close[ii] ) && close[ii] < *std::max_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] ; 
      donc_20_pv[0] = 0.0 ; } // exit short, go neutral

      if ( close[ii] > *std::max_element( &close[ii-20], &close[ii] ) ) { 
      donc_20_eq[ii] = donc_20_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      donc_20_pv[0] = 1.0 ; } // long

    } // end of donc_20_pv == -1.0 loop

    //-------------------------------------------------------------------------------------------------

    // donc_50_eq
    if ( donc_50_pv[0] == 0.0 ) {

      // default position
      donc_50_eq[ii] = donc_50_eq[ii-1] ;

      // unless one of the two following conditions is true

      if ( close[ii] > *std::max_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      donc_50_pv[0] = 1.0 ; } // long

      if ( close[ii] < *std::min_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      donc_50_pv[0] = -1.0 ; } // short

    } // end of donc_50_pv == 0.0 loop

    if ( donc_50_pv[0] == 1.0 ) {

      // default long position
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; // long

      // unless one of the two following conditions is true

      if ( close[ii] < *std::min_element( &close[ii-25], &close[ii] ) && close[ii] > *std::min_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] ; 
      donc_50_pv[0] = 0.0 ; } // exit long, go neutral

      if ( close[ii] < *std::min_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; 
      donc_50_pv[0] = -1.0 ; } // short
    
    } // end of donc_50_pv == 1.0 loop

    if ( donc_50_pv[0] == -1.0 ) {

      // default short position
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; // short

      // unless one of the two following conditions is true

      if ( close[ii] > *std::max_element( &close[ii-25], &close[ii] ) && close[ii] < *std::max_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] ; 
      donc_50_pv[0] = 0.0 ; } // exit short, go neutral

      if ( close[ii] > *std::max_element( &close[ii-50], &close[ii] ) ) { 
      donc_50_eq[ii] = donc_50_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; 
      donc_50_pv[0] = 1.0 ; } // long

    } // end of donc_50_pv == -1.0 loop

    //-------------------------------------------------------------------------------------------------

    // composite_eq
    comp_pv[0] = sma_10_20_pv[0] + sma_20_50_pv[0] + tma_pv[0] + bbo_20_pv[0] + bbo_50_pv[0] + donc_20_pv[0] + donc_50_pv[0] ;
    
    if ( comp_pv[0] > 0 ) {
    composite_eq[ii] = composite_eq[ii-1] + tick_value[0] * ( (open[ii+2]-open[ii+1])/tick_size[0] ) ; } // long

    if ( comp_pv[0] < 0 ) {
    composite_eq[ii] = composite_eq[ii-1] + tick_value[0] * ( (open[ii+1]-open[ii+2])/tick_size[0] ) ; } // short 

    if ( comp_pv[0] == 0 ) {
    composite_eq[ii] = composite_eq[ii-1] ; } // neutral 

} // end of main for loop

// Now fill in the last two spaces in the equity vectors
market_mode_long_eq[n-1] = market_mode_long_eq[n-3] ;
market_mode_long_eq[n-2] = market_mode_long_eq[n-3] ;

market_mode_short_eq[n-1] = market_mode_short_eq[n-3] ;
market_mode_short_eq[n-2] = market_mode_short_eq[n-3] ;

market_mode_composite_eq[n-1] = market_mode_composite_eq[n-3] ;
market_mode_composite_eq[n-2] = market_mode_composite_eq[n-3] ;

sma_10_20_eq[n-1] = sma_10_20_eq[n-3] ;
sma_10_20_eq[n-2] = sma_10_20_eq[n-3] ;

sma_20_50_eq[n-1] = sma_20_50_eq[n-3] ;
sma_20_50_eq[n-2] = sma_20_50_eq[n-3] ;

tma_eq[n-1] = tma_eq[n-3] ;
tma_eq[n-2] = tma_eq[n-3] ;

bbo_20_eq[n-1] = bbo_20_eq[n-3] ;
bbo_20_eq[n-2] = bbo_20_eq[n-3] ;

bbo_50_eq[n-1] = bbo_50_eq[n-3] ;
bbo_50_eq[n-2] = bbo_50_eq[n-3] ;

donc_20_eq[n-1] = donc_20_eq[n-3] ;
donc_20_eq[n-2] = donc_20_eq[n-3] ;

donc_50_eq[n-1] = donc_50_eq[n-3] ;
donc_50_eq[n-2] = donc_50_eq[n-3] ;

composite_eq[n-1] = composite_eq[n-3] ;
composite_eq[n-2] = composite_eq[n-3] ;

return List::create(
  _["market_mode_long_eq"] = market_mode_long_eq ,
  _["market_mode_short_eq"] = market_mode_short_eq ,
  _["market_mode_composite_eq"] = market_mode_composite_eq ,
  _["sma_10_20_eq"] = sma_10_20_eq ,
  _["sma_20_50_eq"] = sma_20_50_eq , 
  _["tma_eq"] = tma_eq ,
  _["bbo_20_eq"] = bbo_20_eq ,
  _["bbo_50_eq"] = bbo_50_eq ,
  _["donc_20_eq"] = donc_20_eq ,
  _["donc_50_eq"] = donc_50_eq ,
  _["composite_eq"] = composite_eq ) ; '

basic_benchmark_equity <- cxxfunction(signature(a = "numeric", b = "numeric", c = "numeric",
                                d = "numeric", e = "numeric", f = "numeric"), body=src, 
                                plugin = "Rcpp")

This Rcpp function is then called thus, using Rstudio

library(xts)  # load the required library

# load the "indicator" file 
data <- read.csv(file="usdyenind",head=FALSE,sep=,)
tick_size <- 0.01
tick_value <- 12.50

# extract other vectors of interest
open <- data[,2]
close <- data[,5]
market_mode <- data[,228]
kalman <- data[,283]

results <- basic_benchmark_equity(open,close,market_mode,kalman,tick_size,tick_value)

# coerce the above results list object to a data frame object
results_df <- data.frame( results )
df_max <- max(results_df) # for scaling of results plot
df_min <- min(results_df) # for scaling of results plot

# and now create an xts object for plotting
results_xts <- xts(results_df,as.Date(data[,'V1']))

# a nice plot of the results_xts object
par(col="#0000FF")
plot(results_xts[,'market_mode_long_eq'],main="USDYEN Pair",ylab="$ Equity Value",ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="#B0171F")
plot(results_xts[,'market_mode_short_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="#00FF00")
plot(results_xts[,'market_mode_composite_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="#808080")
plot(results_xts[,'sma_10_20_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'sma_20_50_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'tma_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'bbo_20_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'bbo_50_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'donc_20_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE)
plot(results_xts[,'donc_50_eq'],main="",ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="black")
plot(results_xts[,'composite_eq'],main="",ylim=c(df_min,df_max),type="l")


to output .png files which I have strung together in this video
Non-embedded view here.
The light grey equity curves are the individual curves for the benchmark systems and the black is the "committee" 1 contract equity curve. Also shown are the long and short 1 contract equity curves ( blue and red respectively ), along with a green combined equity curve for these, for my Naive Bayesian Classifier following the simple rules
  • be long 1 contract if the market type is uwr, unr or cyclic with my Kalman filter pointing upwards
  • be short 1 contract if the market type is dwr, dnr or cyclic with my Kalman filter pointing downwards
Again this is just a toy example of the use of my Bayesian Classifier.  After I have completed Andrew Ng's machine learning course, as mentioned in my previous post, I will have a go at coding a neural net which may end up replacing the Bayesian Classifier.

Monday, 28 May 2012

Update on Gold Delta Solution

Back in February I published a post about the Delta solution for Gold, and this post is a follow up to that earlier post.

Below is an updated chart of Gold showing the next few turning points following on from where the previous chart ended.

My read of this chart is that MTD 1 (solid green line) is a high which came in early March, followed by a low MTD 2 which came in a week late (the second solid red line). The market then struggled to move up to a high MTD 3, indicating a very weak market, and now the market is moving down to a low MTD 4 (the second solid yellow line). Since the most recent MTD 3 high is lower than the previous MTD 1 high and it looks like the MTD 4 low will come in lower that the MTD 2 low, I'd say that on the MTD time frame Gold is now a bear market.

On an unrelated note, it has been more than a month since my last post. During this time I have been busy working through the free, online version of Andrew Ng's Machine Learning course. More on this in a future post.

Tuesday, 24 April 2012

First Use of Rcpp Package

In preparation for the tests I want to conduct, I have finally started to use the Rcpp package. The reason for this decision is straightforward; I cannot begin to imagine how the code for the tests I want to conduct could be vectorised, and since loops in R are slow and not recommended there is no realistic alternative to biting the Rcpp bullet. Another reason is that some R packages, such as the ttrTests package, require an R function as part of the input and using Rcpp will enable me to transfer my .oct C++ function coding directly into R without having to rewrite in R code itself. A simple proof of concept programming exercise I set myself is shown below.
rm(list=ls()) # clear the entire workspace
library(xts)  # load the required library
library(zoo)  # load the required library
library(Rcpp) # load the required library
library(inline) # load the required library
library(compiler) # load the required library

# load the "indicator" file 
data <- read.csv(file="sind",head=FALSE,sep=,)
tick_size <- 0.025
tick_value <- 12.50

# extract other vectors of interest
#open <- data[,2]
market_mode <- data[,228]
kalman <- data[,283]

# source the Rcpp inline file for the C++ code for the test in question
# this file effectively creates a function that takes input and gives test 
# output in the desired form e.g. equity curve, position vector etc. for
# further statistical tests in the R environment, e.g the ttrTests package.

source("basic_market_mode_equity.r")
results <- basic_market_mode_equity(data[,2],market_mode,kalman,tick_size,tick_value)
This is "normal" R code which
  • loads the required libraries
  • loads the required file(s) from disk and takes other inputs for the test in question
  • extracts the required information from the loaded file(s)
  • sources and then calls the test function, named "basic_market_mode_equity"
This second code block contains the actual C++ test function code, which is contained in a file named "basic_market_mode_equity.r"
# This function takes as inputs vectors of opening prices, the "market mode," 
# the kalman filter of vwap, and single values for tick size and tick value.
# The values of "market_mode" are as follows:-
# 0 = cyclic
# 1 = up with retracement
# 2 = up with no retracement
# 3 = down with retracement
# 4 = down with no retracement
# 
# This first test is very simple - be long when market mode is 1 or 2, 
# short when 3 or 4, and when 0 be long or short depending on the direction
# of the kalman filter. This test is just practice in coding using Rcpp:- 
# don't expect any meaningful results. Equity curves for each market mode 
# are the function outputs

src <- '
Rcpp::NumericVector open(a) ;
Rcpp::NumericVector market_mode(b) ;
Rcpp::NumericVector kalman(c) ;
Rcpp::NumericVector tick_size(d) ;
Rcpp::NumericVector tick_value(e) ;
int n = open.size() ;
Rcpp::NumericVector cyc(n) ; // create output vector
Rcpp::NumericVector uwr(n) ; // create output vector
Rcpp::NumericVector unr(n) ; // create output vector
Rcpp::NumericVector dwr(n) ; // create output vector
Rcpp::NumericVector dnr(n) ; // create output vector

// fill the equity_curve with zeros for "burn in" period
for ( int ii = 0 ; ii < 100 ; ii++ ) {
    cyc[ii] = 0.0 ;
    uwr[ii] = 0.0 ;
    unr[ii] = 0.0 ;
    dwr[ii] = 0.0 ;
    dnr[ii] = 0.0 ; }

for ( int ii = 100 ; ii < n ; ii++ ) {
    
    // uwr market type
    if ( market_mode[ii-2] == 1 ) { 
    cyc[ii] = cyc[ii-1] ;
    uwr[ii] = uwr[ii-1] + tick_value[0] * ( (open[ii]-open[ii-1])/tick_size[0] ) ;
    unr[ii] = unr[ii-1] ;
    dwr[ii] = dwr[ii-1] ;
    dnr[ii] = dnr[ii-1] ; }

    // unr market type
    if ( market_mode[ii-2] == 2 ) { 
    cyc[ii] = cyc[ii-1] ;
    uwr[ii] = uwr[ii-1] ; 
    unr[ii] = unr[ii-1] + tick_value[0] * ( (open[ii]-open[ii-1])/tick_size[0] ) ;
    dwr[ii] = dwr[ii-1] ;
    dnr[ii] = dnr[ii-1] ; }

    // dwr
    if ( market_mode[ii-2] == 3 ) { 
    cyc[ii] = cyc[ii-1] ;
    uwr[ii] = uwr[ii-1] ;
    unr[ii] = unr[ii-1] ;
    dwr[ii] = dwr[ii-1] + tick_value[0] * ( (open[ii-1]-open[ii])/tick_size[0] ) ; 
    dnr[ii] = dnr[ii-1] ; }

    // dnr
    if ( market_mode[ii-2] == 4 ) { 
    cyc[ii] = cyc[ii-1] ;
    uwr[ii] = uwr[ii-1] ;
    unr[ii] = unr[ii-1] ;
    dwr[ii] = dwr[ii-1] ; 
    dnr[ii] = dnr[ii-1] + tick_value[0] * ( (open[ii-1]-open[ii])/tick_size[0] ) ; }

    // cyc long
    if ( market_mode[ii-2] == 0 && kalman[ii-2] > kalman[ii-3] ) { 
    cyc[ii] = cyc[ii-1] + tick_value[0] * ( (open[ii]-open[ii-1])/tick_size[0] ) ;
    uwr[ii] = uwr[ii-1] ;
    unr[ii] = unr[ii-1] ;
    dwr[ii] = dwr[ii-1] ; 
    dnr[ii] = dnr[ii-1] ; }

    // cyc short
    if ( market_mode[ii-2] == 0 && kalman[ii-2] < kalman[ii-3] ) { 
    cyc[ii] = cyc[ii-1] + tick_value[0] * ( (open[ii-1]-open[ii])/tick_size[0] ) ;
    uwr[ii] = uwr[ii-1] ;
    unr[ii] = unr[ii-1] ;
    dwr[ii] = dwr[ii-1] ; 
    dnr[ii] = dnr[ii-1] ; }

} // end of main for loop

return List::create(
  _["cyc"] = cyc ,
  _["uwr"] = uwr ,
  _["unr"] = unr ,
  _["dwr"] = dwr ,
  _["dnr"] = dnr ) ; '

basic_market_mode_equity <- cxxfunction(signature(a = "numeric", b = "numeric", c = "numeric",
                                d = "numeric", e = "numeric"), body=src, 
                                plugin = "Rcpp")
which basically just outputs five equity curves corresponding to the identified market mode (see the comments in the code for more details).

This final code block is again "normal" R code
# coerce the above results list object to a data frame object
results_df <- data.frame( results )
df_max <- max(results_df) # for scaling of results plot
df_min <- min(results_df) # for scaling of results plot

# and now create an xts object for plotting
results_xts <- xts(results_df,as.Date(data[,'V1']))

# a nice plot of the results_xts object
plot(results_xts[,'cyc'],ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="cyan")
plot(results_xts[,'uwr'],ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="blue")
plot(results_xts[,'unr'],ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="green")
plot(results_xts[,'dwr'],ylim=c(df_min,df_max),type="l")
par(new=TRUE,col="red")
plot(results_xts[,'dnr'],ylim=c(df_min,df_max),type="l")
which produces this typical plot output.
This test is just a toy test and the results are not really important. The important thing is that I can now easily import the output of my Octave .oct C++ functions into R and conduct a whole range of tests utilising R packages from CRAN or simply write my own test routines in C++ (my intention) to run in R and not have to struggle with vectorising code for speed optimisation purposes.

Saturday, 14 April 2012

Bayesian Classifier Sanity Check, Part 2

Here are the results of the sliced_charts script when applied to the "down with no retracement" market mode, and again it is pleasing to see such high percentages.
octave:1> sliced_charts
Enter matrix e.g. gcmatrix: clmatrix
points_of_interest =  132
dwr_to_dnr =  118
dwr_to_dnr_percent =  0.89394
cyc_to_dnr =  13
cyc_to_dnr_percent =  0.098485
octave:2> sliced_charts
Enter matrix e.g. gcmatrix: homatrix
points_of_interest =  124
dwr_to_dnr =  100
dwr_to_dnr_percent =  0.80645
cyc_to_dnr =  20
cyc_to_dnr_percent =  0.16129
octave:3> sliced_charts
Enter matrix e.g. gcmatrix: ngmatrix
points_of_interest =  150
dwr_to_dnr =  127
dwr_to_dnr_percent =  0.84667
cyc_to_dnr =  21
cyc_to_dnr_percent =  0.14000
octave:4> sliced_charts
Enter matrix e.g. gcmatrix: rbmatrix
points_of_interest =  121
dwr_to_dnr =  104
dwr_to_dnr_percent =  0.85950
cyc_to_dnr =  13
cyc_to_dnr_percent =  0.10744
octave:5> sliced_charts
Enter matrix e.g. gcmatrix: ccmatrix
points_of_interest =  153
dwr_to_dnr =  132
dwr_to_dnr_percent =  0.86275
cyc_to_dnr =  19
cyc_to_dnr_percent =  0.12418
octave:6> sliced_charts
Enter matrix e.g. gcmatrix: kcmatrix
points_of_interest =  148
dwr_to_dnr =  123
dwr_to_dnr_percent =  0.83108
cyc_to_dnr =  23
cyc_to_dnr_percent =  0.15541
octave:7> sliced_charts
Enter matrix e.g. gcmatrix: ojmatrix
points_of_interest =  147
dwr_to_dnr =  120
dwr_to_dnr_percent =  0.81633
cyc_to_dnr =  21
cyc_to_dnr_percent =  0.14286
octave:8> sliced_charts
Enter matrix e.g. gcmatrix: sbmatrix
points_of_interest =  109
dwr_to_dnr =  94
dwr_to_dnr_percent =  0.86239
cyc_to_dnr =  12
cyc_to_dnr_percent =  0.11009
octave:9> sliced_charts
Enter matrix e.g. gcmatrix: ctmatrix
points_of_interest =  143
dwr_to_dnr =  122
dwr_to_dnr_percent =  0.85315
cyc_to_dnr =  14
cyc_to_dnr_percent =  0.097902
octave:10> sliced_charts
Enter matrix e.g. gcmatrix: lbmatrix
points_of_interest =  142
dwr_to_dnr =  120
dwr_to_dnr_percent =  0.84507
cyc_to_dnr =  20
cyc_to_dnr_percent =  0.14085
octave:11> sliced_charts
Enter matrix e.g. gcmatrix: hgmatrix
points_of_interest =  119
dwr_to_dnr =  101
dwr_to_dnr_percent =  0.84874
cyc_to_dnr =  10
cyc_to_dnr_percent =  0.084034
octave:12> sliced_charts
Enter matrix e.g. gcmatrix: smatrix
points_of_interest =  117
dwr_to_dnr =  107
dwr_to_dnr_percent =  0.91453
cyc_to_dnr =  8
cyc_to_dnr_percent =  0.068376
octave:13> sliced_charts
Enter matrix e.g. gcmatrix: smmatrix
points_of_interest =  123
dwr_to_dnr =  105
dwr_to_dnr_percent =  0.85366
cyc_to_dnr =  17
cyc_to_dnr_percent =  0.13821
octave:14> sliced_charts
Enter matrix e.g. gcmatrix: bomatrix
points_of_interest =  136
dwr_to_dnr =  121
dwr_to_dnr_percent =  0.88971
cyc_to_dnr =  11
cyc_to_dnr_percent =  0.080882
octave:15> sliced_charts
Enter matrix e.g. gcmatrix: cmatrix
points_of_interest =  137
dwr_to_dnr =  111
dwr_to_dnr_percent =  0.81022
cyc_to_dnr =  24
cyc_to_dnr_percent =  0.17518
octave:16> sliced_charts
Enter matrix e.g. gcmatrix: omatrix
points_of_interest =  138
dwr_to_dnr =  108
dwr_to_dnr_percent =  0.78261
cyc_to_dnr =  24
cyc_to_dnr_percent =  0.17391
octave:17> sliced_charts
Enter matrix e.g. gcmatrix: wmatrix
points_of_interest =  145
dwr_to_dnr =  122
dwr_to_dnr_percent =  0.84138
cyc_to_dnr =  21
cyc_to_dnr_percent =  0.14483
octave:18> sliced_charts
Enter matrix e.g. gcmatrix: lcmatrix
points_of_interest =  136
dwr_to_dnr =  113
dwr_to_dnr_percent =  0.83088
cyc_to_dnr =  22
cyc_to_dnr_percent =  0.16176
octave:19> sliced_charts
Enter matrix e.g. gcmatrix: fcmatrix
points_of_interest =  123
dwr_to_dnr =  105
dwr_to_dnr_percent =  0.85366
cyc_to_dnr =  15
cyc_to_dnr_percent =  0.12195
octave:20> sliced_charts
Enter matrix e.g. gcmatrix: lhmatrix
points_of_interest =  147
dwr_to_dnr =  122
dwr_to_dnr_percent =  0.82993
cyc_to_dnr =  21
cyc_to_dnr_percent =  0.14286
octave:21> sliced_charts
Enter matrix e.g. gcmatrix: gcmatrix
points_of_interest =  132
dwr_to_dnr =  115
dwr_to_dnr_percent =  0.87121
cyc_to_dnr =  16
cyc_to_dnr_percent =  0.12121
octave:22> sliced_charts
Enter matrix e.g. gcmatrix: simatrix
points_of_interest =  127
dwr_to_dnr =  105
dwr_to_dnr_percent =  0.82677
cyc_to_dnr =  16
cyc_to_dnr_percent =  0.12598
octave:23> sliced_charts
Enter matrix e.g. gcmatrix: plmatrix
points_of_interest =  128
dwr_to_dnr =  112
dwr_to_dnr_percent =  0.87500
cyc_to_dnr =  14
cyc_to_dnr_percent =  0.10938
octave:24> sliced_charts
Enter matrix e.g. gcmatrix: pamatrix
points_of_interest =  120
dwr_to_dnr =  96
dwr_to_dnr_percent =  0.80000
cyc_to_dnr =  18
cyc_to_dnr_percent =  0.15000
octave:25> sliced_charts
Enter matrix e.g. gcmatrix: usmatrix
points_of_interest =  94
dwr_to_dnr =  78
dwr_to_dnr_percent =  0.82979
cyc_to_dnr =  14
cyc_to_dnr_percent =  0.14894
octave:26> sliced_charts
Enter matrix e.g. gcmatrix: tymatrix
points_of_interest =  104
dwr_to_dnr =  99
dwr_to_dnr_percent =  0.95192
cyc_to_dnr =  2
cyc_to_dnr_percent =  0.019231
octave:27> sliced_charts
Enter matrix e.g. gcmatrix: edmatrix
points_of_interest =  108
dwr_to_dnr =  96
dwr_to_dnr_percent =  0.88889
cyc_to_dnr =  10
cyc_to_dnr_percent =  0.092593
octave:28> sliced_charts
Enter matrix e.g. gcmatrix: dxmatrix
points_of_interest =  116
dwr_to_dnr =  94
dwr_to_dnr_percent =  0.81034
cyc_to_dnr =  20
cyc_to_dnr_percent =  0.17241
octave:29> sliced_charts
Enter matrix e.g. gcmatrix: spmatrix
points_of_interest =  106
dwr_to_dnr =  85
dwr_to_dnr_percent =  0.80189
cyc_to_dnr =  19
cyc_to_dnr_percent =  0.17925
octave:30> sliced_charts
Enter matrix e.g. gcmatrix: esmatrix
points_of_interest =  109
dwr_to_dnr =  86
dwr_to_dnr_percent =  0.78899
cyc_to_dnr =  20
cyc_to_dnr_percent =  0.18349
octave:31> sliced_charts
Enter matrix e.g. gcmatrix: ndmatrix
points_of_interest =  107
dwr_to_dnr =  83
dwr_to_dnr_percent =  0.77570
cyc_to_dnr =  18
cyc_to_dnr_percent =  0.16822
octave:32> sliced_charts
Enter matrix e.g. gcmatrix: eurusdmatrix
points_of_interest =  72
dwr_to_dnr =  60
dwr_to_dnr_percent =  0.83333
cyc_to_dnr =  11
cyc_to_dnr_percent =  0.15278
octave:33> sliced_charts
Enter matrix e.g. gcmatrix: gbpusdmatrix
points_of_interest =  85
dwr_to_dnr =  72
dwr_to_dnr_percent =  0.84706
cyc_to_dnr =  11
cyc_to_dnr_percent =  0.12941
octave:34> sliced_charts
Enter matrix e.g. gcmatrix: usdchfmatrix
points_of_interest =  86
dwr_to_dnr =  69
dwr_to_dnr_percent =  0.80233
cyc_to_dnr =  14
cyc_to_dnr_percent =  0.16279
octave:35> sliced_charts
Enter matrix e.g. gcmatrix: usdyenmatrix
points_of_interest =  100
dwr_to_dnr =  80
dwr_to_dnr_percent =  0.80000
cyc_to_dnr =  16
cyc_to_dnr_percent =  0.16000
octave:36> sliced_charts
Enter matrix e.g. gcmatrix: eurchfmatrix
points_of_interest =  100
dwr_to_dnr =  83
dwr_to_dnr_percent =  0.83000
cyc_to_dnr =  15
cyc_to_dnr_percent =  0.15000
octave:37> sliced_charts
Enter matrix e.g. gcmatrix: eurgbpmatrix
points_of_interest =  91
dwr_to_dnr =  79
dwr_to_dnr_percent =  0.86813
cyc_to_dnr =  12
cyc_to_dnr_percent =  0.13187
octave:38> sliced_charts
Enter matrix e.g. gcmatrix: euryenmatrix
points_of_interest =  94
dwr_to_dnr =  75
dwr_to_dnr_percent =  0.79787
cyc_to_dnr =  15
cyc_to_dnr_percent =  0.15957
octave:39> sliced_charts
Enter matrix e.g. gcmatrix: eurausmatrix
points_of_interest =  99
dwr_to_dnr =  81
dwr_to_dnr_percent =  0.81818
cyc_to_dnr =  18
cyc_to_dnr_percent =  0.18182
octave:40> sliced_charts
Enter matrix e.g. gcmatrix: eurcadmatrix
points_of_interest =  92
dwr_to_dnr =  81
dwr_to_dnr_percent =  0.88043
cyc_to_dnr =  9
cyc_to_dnr_percent =  0.097826
octave:41> sliced_charts
Enter matrix e.g. gcmatrix: usdcadmatrix
points_of_interest =  97
dwr_to_dnr =  86
dwr_to_dnr_percent =  0.88660
cyc_to_dnr =  7
cyc_to_dnr_percent =  0.072165
octave:42> sliced_charts
Enter matrix e.g. gcmatrix: gbpchfmatrix
points_of_interest =  87
dwr_to_dnr =  70
dwr_to_dnr_percent =  0.80460
cyc_to_dnr =  14
cyc_to_dnr_percent =  0.16092
octave:43> sliced_charts
Enter matrix e.g. gcmatrix: gbpyenmatrix
points_of_interest =  85
dwr_to_dnr =  74
dwr_to_dnr_percent =  0.87059
cyc_to_dnr =  9
cyc_to_dnr_percent =  0.10588
octave:44> sliced_charts
Enter matrix e.g. gcmatrix: auscadmatrix
points_of_interest =  72
dwr_to_dnr =  59
dwr_to_dnr_percent =  0.81944
cyc_to_dnr =  13
cyc_to_dnr_percent =  0.18056
octave:45> sliced_charts
Enter matrix e.g. gcmatrix: aususdmatrix
points_of_interest =  74
dwr_to_dnr =  59
dwr_to_dnr_percent =  0.79730
cyc_to_dnr =  9
cyc_to_dnr_percent =  0.12162
octave:46> sliced_charts
Enter matrix e.g. gcmatrix: ausyenmatrix
points_of_interest =  65
dwr_to_dnr =  49
dwr_to_dnr_percent =  0.75385
cyc_to_dnr =  13
cyc_to_dnr_percent =  0.20000
But what does this all mean? For the purposes of simplicity I shall discuss "up with no retracement" only, but everything will apply equally to the "down with retracement," but of course in reverse.

My original concern was that the market classifications might have been erratically switching directly from "dnr" to "unr" with resultant lurches from short to long market positions and along the way incurring whipsaw losses from false signals. However, the high percentages from these simple tests show that this is not actually the case. Based on this, one can assume that
  • when the market classification changes to "unr" a long position will already be held because either
  1. a cyclic long position is held, having been initiated at the most recent low cyclic turn, or
  2. a "uwr" long position is held, having been initiated at the most recent rebound from a resistance/retracement level
  • which means that this market classification change is not necessarily a new entry signal, but rather a signal to change to a trend following exit criteria
Therefore, my next test(s) will be to assume that such a long position is held when the market classification changes to "unr" and will continued to be held until a trend following exit occurs, coupled with a "re-entry" signal if appropriate. My intent at the moment is simply to plot equity curves of these long positions, in the supposition that these equity curves will be "additions" or "extensions" to the equity curves generated by signals when in other market modes. More details in a coming post.

Friday, 13 April 2012

My Naive Bayesian Classifier Sanity Check

Following on from my previous post, as part of my initial attempts to "come up with a robust rule set that combines all these disparate indicators into a coherent whole," I have written a simple Octave script to conduct a basic sanity check of my Naive Bayesian Classifier. The purpose of this is to ensure that the various classifications are not wildly fluctuating between bull and bear market modes with no discernible order. This particular test identifies which market modes are indicated immediately prior to an "up with no retracement" mode being indicated. This code box shows the Octave terminal output of the test script, which is named "sliced_charts".
octave:1> sliced_charts
Enter matrix e.g. gcmatrix: clmatrix
points_of_interest =  147
uwr_to_unr =  126
uwr_to_unr_percent =  0.85714
cyc_to_unr =  16
cyc_to_unr_percent =  0.10884
octave:2> sliced_charts
Enter matrix e.g. gcmatrix: homatrix
points_of_interest =  130
uwr_to_unr =  106
uwr_to_unr_percent =  0.81538
cyc_to_unr =  20
cyc_to_unr_percent =  0.15385
octave:3> sliced_charts
Enter matrix e.g. gcmatrix: ngmatrix
points_of_interest =  123
uwr_to_unr =  104
uwr_to_unr_percent =  0.84553
cyc_to_unr =  15
cyc_to_unr_percent =  0.12195
octave:4> sliced_charts
Enter matrix e.g. gcmatrix: rbmatrix
points_of_interest =  162
uwr_to_unr =  134
uwr_to_unr_percent =  0.82716
cyc_to_unr =  23
cyc_to_unr_percent =  0.14198
octave:5> sliced_charts
Enter matrix e.g. gcmatrix: ccmatrix
points_of_interest =  123
uwr_to_unr =  95
uwr_to_unr_percent =  0.77236
cyc_to_unr =  24
cyc_to_unr_percent =  0.19512
octave:6> sliced_charts
Enter matrix e.g. gcmatrix: kcmatrix
points_of_interest =  114
uwr_to_unr =  98
uwr_to_unr_percent =  0.85965
cyc_to_unr =  14
cyc_to_unr_percent =  0.12281
octave:7> sliced_charts
Enter matrix e.g. gcmatrix: ojmatrix
points_of_interest =  129
uwr_to_unr =  109
uwr_to_unr_percent =  0.84496
cyc_to_unr =  17
cyc_to_unr_percent =  0.13178
octave:8> sliced_charts
Enter matrix e.g. gcmatrix: sbmatrix
points_of_interest =  141
uwr_to_unr =  113
uwr_to_unr_percent =  0.80142
cyc_to_unr =  23
cyc_to_unr_percent =  0.16312
octave:9> sliced_charts
Enter matrix e.g. gcmatrix: ctmatrix
points_of_interest =  114
uwr_to_unr =  90
uwr_to_unr_percent =  0.78947
cyc_to_unr =  16
cyc_to_unr_percent =  0.14035
octave:10> sliced_charts
Enter matrix e.g. gcmatrix: lbmatrix
points_of_interest =  113
uwr_to_unr =  89
uwr_to_unr_percent =  0.78761
cyc_to_unr =  19
cyc_to_unr_percent =  0.16814
octave:11> sliced_charts
Enter matrix e.g. gcmatrix: hgmatrix
points_of_interest =  132
uwr_to_unr =  118
uwr_to_unr_percent =  0.89394
cyc_to_unr =  14
cyc_to_unr_percent =  0.10606
octave:12> sliced_charts
Enter matrix e.g. gcmatrix: smatrix
points_of_interest =  141
uwr_to_unr =  118
uwr_to_unr_percent =  0.83688
cyc_to_unr =  20
cyc_to_unr_percent =  0.14184
octave:13> sliced_charts
Enter matrix e.g. gcmatrix: smmatrix
points_of_interest =  140
uwr_to_unr =  110
uwr_to_unr_percent =  0.78571
cyc_to_unr =  29
cyc_to_unr_percent =  0.20714
octave:14> sliced_charts
Enter matrix e.g. gcmatrix: bomatrix
points_of_interest =  121
uwr_to_unr =  97
uwr_to_unr_percent =  0.80165
cyc_to_unr =  16
cyc_to_unr_percent =  0.13223
octave:15> sliced_charts
Enter matrix e.g. gcmatrix: cmatrix
points_of_interest =  128
uwr_to_unr =  103
uwr_to_unr_percent =  0.80469
cyc_to_unr =  23
cyc_to_unr_percent =  0.17969
octave:16> sliced_charts
Enter matrix e.g. gcmatrix: omatrix
points_of_interest =  128
uwr_to_unr =  104
uwr_to_unr_percent =  0.81250
cyc_to_unr =  20
cyc_to_unr_percent =  0.15625
octave:17> sliced_charts
Enter matrix e.g. gcmatrix: wmatrix
points_of_interest =  105
uwr_to_unr =  91
uwr_to_unr_percent =  0.86667
cyc_to_unr =  11
cyc_to_unr_percent =  0.10476
octave:18> sliced_charts
Enter matrix e.g. gcmatrix: lcmatrix
points_of_interest =  144
uwr_to_unr =  119
uwr_to_unr_percent =  0.82639
cyc_to_unr =  23
cyc_to_unr_percent =  0.15972
octave:19> sliced_charts
Enter matrix e.g. gcmatrix: fcmatrix
points_of_interest =  132
uwr_to_unr =  110
uwr_to_unr_percent =  0.83333
cyc_to_unr =  19
cyc_to_unr_percent =  0.14394
octave:20> sliced_charts
Enter matrix e.g. gcmatrix: lhmatrix
points_of_interest =  136
uwr_to_unr =  113
uwr_to_unr_percent =  0.83088
cyc_to_unr =  21
cyc_to_unr_percent =  0.15441
octave:21> sliced_charts
Enter matrix e.g. gcmatrix: gcmatrix
points_of_interest =  137
uwr_to_unr =  118
uwr_to_unr_percent =  0.86131
cyc_to_unr =  16
cyc_to_unr_percent =  0.11679
octave:22> sliced_charts
Enter matrix e.g. gcmatrix: simatrix
points_of_interest =  121
uwr_to_unr =  102
uwr_to_unr_percent =  0.84298
cyc_to_unr =  15
cyc_to_unr_percent =  0.12397
octave:23> sliced_charts
Enter matrix e.g. gcmatrix: plmatrix
points_of_interest =  149
uwr_to_unr =  126
uwr_to_unr_percent =  0.84564
cyc_to_unr =  18
cyc_to_unr_percent =  0.12081
octave:24> sliced_charts
Enter matrix e.g. gcmatrix: pamatrix
points_of_interest =  129
uwr_to_unr =  103
uwr_to_unr_percent =  0.79845
cyc_to_unr =  22
cyc_to_unr_percent =  0.17054
octave:25> sliced_charts
Enter matrix e.g. gcmatrix: usmatrix
points_of_interest =  143
uwr_to_unr =  122
uwr_to_unr_percent =  0.85315
cyc_to_unr =  16
cyc_to_unr_percent =  0.11189
octave:26> sliced_charts
Enter matrix e.g. gcmatrix: tymatrix
points_of_interest =  148
uwr_to_unr =  128
uwr_to_unr_percent =  0.86486
cyc_to_unr =  17
cyc_to_unr_percent =  0.11486
octave:27> sliced_charts
Enter matrix e.g. gcmatrix: edmatrix
points_of_interest =  150
uwr_to_unr =  118
uwr_to_unr_percent =  0.78667
cyc_to_unr =  26
cyc_to_unr_percent =  0.17333
octave:28> sliced_charts
Enter matrix e.g. gcmatrix: dxmatrix
points_of_interest =  141
uwr_to_unr =  122
uwr_to_unr_percent =  0.86525
cyc_to_unr =  14
cyc_to_unr_percent =  0.099291
octave:29> sliced_charts
Enter matrix e.g. gcmatrix: spmatrix
points_of_interest =  158
uwr_to_unr =  123
uwr_to_unr_percent =  0.77848
cyc_to_unr =  31
cyc_to_unr_percent =  0.19620
octave:30> sliced_charts
Enter matrix e.g. gcmatrix: esmatrix
points_of_interest =  160
uwr_to_unr =  125
uwr_to_unr_percent =  0.78125
cyc_to_unr =  30
cyc_to_unr_percent =  0.18750
octave:31> sliced_charts
Enter matrix e.g. gcmatrix: ndmatrix
points_of_interest =  129
uwr_to_unr =  116
uwr_to_unr_percent =  0.89922
cyc_to_unr =  12
cyc_to_unr_percent =  0.093023
octave:32> sliced_charts
Enter matrix e.g. gcmatrix: eurusdmatrix
points_of_interest =  79
uwr_to_unr =  69
uwr_to_unr_percent =  0.87342
cyc_to_unr =  9
cyc_to_unr_percent =  0.11392
octave:33> sliced_charts
Enter matrix e.g. gcmatrix: gbpusdmatrix
points_of_interest =  84
uwr_to_unr =  72
uwr_to_unr_percent =  0.85714
cyc_to_unr =  11
cyc_to_unr_percent =  0.13095
octave:34> sliced_charts
Enter matrix e.g. gcmatrix: usdchfmatrix
points_of_interest =  80
uwr_to_unr =  73
uwr_to_unr_percent =  0.91250
cyc_to_unr =  6
cyc_to_unr_percent =  0.075000
octave:35> sliced_charts
Enter matrix e.g. gcmatrix: usdyenmatrix
points_of_interest =  74
uwr_to_unr =  62
uwr_to_unr_percent =  0.83784
cyc_to_unr =  8
cyc_to_unr_percent =  0.10811
octave:36> sliced_charts
Enter matrix e.g. gcmatrix: eurchfmatrix
points_of_interest =  93
uwr_to_unr =  80
uwr_to_unr_percent =  0.86022
cyc_to_unr =  10
cyc_to_unr_percent =  0.10753
octave:37> sliced_charts
Enter matrix e.g. gcmatrix: eurgbpmatrix
points_of_interest =  91
uwr_to_unr =  78
uwr_to_unr_percent =  0.85714
cyc_to_unr =  11
cyc_to_unr_percent =  0.12088
octave:38> sliced_charts
Enter matrix e.g. gcmatrix: euryenmatrix
points_of_interest =  103
uwr_to_unr =  88
uwr_to_unr_percent =  0.85437
cyc_to_unr =  14
cyc_to_unr_percent =  0.13592
octave:39> sliced_charts
Enter matrix e.g. gcmatrix: eurausmatrix
points_of_interest =  73
uwr_to_unr =  64
uwr_to_unr_percent =  0.87671
cyc_to_unr =  9
cyc_to_unr_percent =  0.12329
octave:40> sliced_charts
Enter matrix e.g. gcmatrix: eurcadmatrix
points_of_interest =  76
uwr_to_unr =  56
uwr_to_unr_percent =  0.73684
cyc_to_unr =  17
cyc_to_unr_percent =  0.22368
octave:41> sliced_charts
Enter matrix e.g. gcmatrix: usdcadmatrix
points_of_interest =  73
uwr_to_unr =  60
uwr_to_unr_percent =  0.82192
cyc_to_unr =  13
cyc_to_unr_percent =  0.17808
octave:42> sliced_charts
Enter matrix e.g. gcmatrix: gbpchfmatrix
points_of_interest =  98
uwr_to_unr =  84
uwr_to_unr_percent =  0.85714
cyc_to_unr =  12
cyc_to_unr_percent =  0.12245
octave:43> sliced_charts
Enter matrix e.g. gcmatrix: gbpyenmatrix
points_of_interest =  97
uwr_to_unr =  84
uwr_to_unr_percent =  0.86598
cyc_to_unr =  11
cyc_to_unr_percent =  0.11340
octave:44> sliced_charts
Enter matrix e.g. gcmatrix: auscadmatrix
points_of_interest =  107
uwr_to_unr =  92
uwr_to_unr_percent =  0.85981
cyc_to_unr =  14
cyc_to_unr_percent =  0.13084
octave:45> sliced_charts
Enter matrix e.g. gcmatrix: aususdmatrix
points_of_interest =  97
uwr_to_unr =  82
uwr_to_unr_percent =  0.84536
cyc_to_unr =  14
cyc_to_unr_percent =  0.14433
octave:46> sliced_charts
Enter matrix e.g. gcmatrix: ausyenmatrix
points_of_interest =  103
uwr_to_unr =  89
uwr_to_unr_percent =  0.86408
cyc_to_unr =  11
cyc_to_unr_percent =  0.10680
  • The clmatrix indicates which market is being tested e.g. crude oil (cl)
  • points of interest is the number of times the market mode changes to "up with no retracement" from a previously different classification
  • uwr_to_unr is the number of times such a change is from "up with retracement" to "up with no retracement"
  • cyc_to_unr is similarly from "cyclic" to "up with no retracement"
  • the *_percent is the previous two expressed as a percentage of the points of interest
It is pleasing to see such high percentages overall. I will perform a similar analysis for "down with retracement" and discuss the significance of this in my next post.