Monday 20 November 2017

Candlestick Plotting Function for Octave.

I have long been frustrated by the lack of an "out of the box" solution for plotting OHLC candlestick charts natively in Octave, the closest solution I know being the highlow plot function from the financial package ( which does not yet implement a candle function ) over at Octave Sourceforge. This being the case, I decided to write my own candlestick plotting functions, the codes for which are shown below.

This first, basic version just plots a candlestick chart with blue for up bars ( close higher than open ) or red for down bars ( close less than open ).
## Copyright (C) 2017 dekalog
## 
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see .
## -*- texinfo -*- 
## @deftypefn {} {@var{retval} =} candles (@var{O}, @var{H}, @var{L}, @var{C})
## 
## Takes O, H, L and C inputs and plots a candlestick chart, with blue bars for
## close up days and red bars for close down days.
##
## @seealso{}
## @end deftypefn

## Author: dekalog 
## Created: 2017-11-16

function [retval] = candles ( open , high , low , close )
  
  if ( nargin != 4 )
      error ( "Not enough input arguments. Should be OHLC vectors." ) ;
  endif
  
  wicks = high .- low ;
  body = close .- open ;
  up_down = sign( body ) ;
  
  hold on ;
  % plot the wicks
  x = ( 1 : length( close ) ) ; % the x-axis
  idx = x ;
  high_nan = nan( size( high ) ) ; high_nan( idx ) = high ; % highs
  low_nan = nan( size( low ) ) ; low_nan( idx ) = low ;     % lows
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , "k" , 'linewidth' , 2 ) ;                   % plot black wicks
  
  % plot the up bars
  x = ( 1 : length( high ) ) ;                                      % the x-axis
  idx = ( up_down == 1 ) ; idx = find( idx ) ;                      % index by condition
  high_nan = nan( size( high ) ) ; high_nan( idx ) = close( idx ) ; % index closes > opens
  low_nan = nan( size( low ) ) ; low_nan( idx ) = open( idx ) ;     % index opens < closes
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , "b" , 'linewidth' , 20 ) ;                           % plot blue up bars
  
  % plot the down bars
  x = ( 1 : length( high ) ) ;                                      % the x-axis
  idx = ( up_down == -1 ) ; idx = find( idx ) ;                     % index by condition
  high_nan = nan( size( high ) ) ; high_nan( idx ) = open( idx ) ;  % index opens > closes
  low_nan = nan( size( low ) ) ; low_nan( idx ) = close( idx ) ;    % index closes < opens
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , "r" , 'linewidth' , 20 ) ;                          % plot red down bars
  
  hold off ; 

endfunction
The second version is a conditional plotting version which takes a condition vector as input along with the OHLC vectors and plots candlesticks with different colours according to the condition in the condition vector ( conditions are integers 1 to 3 inclusive ).
## Copyright (C) 2017 dekalog
## 
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see .
## -*- texinfo -*- 
## @deftypefn {} {@var{retval} =} candles (@var{O}, @var{H}, @var{L}, @var{C}, @var{TC})
## 
## Takes OHLC inputs and a TC vector and plots a candlestick chart, with up bars coloured
## cyan or blue and down bars magenta or red, dependent on value contained in the 
## condition vector TC ( values == 1 or == 2 ).
##
## @seealso{}
## @end deftypefn

## Author: dekalog 
## Created: 2017-11-16

function [retval] = candles_tc ( open , high , low , close , tc )
  
  if ( nargin != 5 )
     error ( "Not enough input arguments. Should be OHLC and a condition vector" ) ;
  endif
  
  if ( length( unique( tc ) ) > 3 )
     error ( "Too many conditions in condition vector. Maximum of 3 conditions allowed." ) ;
  endif
  
  wicks = high .- low ;
  body = close .- open ;
  up_down = sign( body ) ;
  up_colours = "cbg" ;
  down_colours = "mrk" ;
  candle_body_width = 20 ;
  
  hold on ;
  
  % plot the wicks
  x = ( 1 : length( close ) ) ; % the x-axis
  idx = x ;
  high_nan = nan( size( high ) ) ; high_nan( idx ) = high ; % highs
  low_nan = nan( size( low ) ) ; low_nan( idx ) = low ;     % lows
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , "k" , 'linewidth' , 2 ) ;                   % plot black wicks

  for ii = 1 : length( unique( tc ) )
  
  % plot the up bars for ii condition
  x = ( 1 : length( high ) ) ;                                      % the x-axis
  idx = ( up_down == 1 ) .* ( tc == ii ) ; idx = find( idx ) ;      % index by condition
  high_nan = nan( size( high ) ) ; high_nan( idx ) = close( idx ) ; % index closes > opens
  low_nan = nan( size( low ) ) ; low_nan( idx ) = open( idx ) ;     % index opens < closes
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , up_colours( ii ) , 'linewidth' , candle_body_width ) ;
  
  % plot the down bars for ii condition
  x = ( 1 : length( high ) ) ;                                      % the x-axis
  idx = ( up_down == -1 ) .* ( tc == ii ) ; idx = find( idx ) ;     % index by condition
  high_nan = nan( size( high ) ) ; high_nan( idx ) = open( idx ) ;  % index opens > closes
  low_nan = nan( size( low ) ) ; low_nan( idx ) = close( idx ) ;    % index closes < opens
  x = reshape( [ x ; x ; nan( size( x ) ) ] , [] , 1 ) ;
  y = reshape( [ high_nan(:)' ; low_nan(:)' ; nan( 1 , length( high ) ) ] , [] , 1 ) ;
  plot( x , y , down_colours( ii ) , 'linewidth' , candle_body_width ) ;

  endfor
  
  hold off ; 

endfunction
An example of a plot by this second version is
There are two conditions being plotted on this 1 hour chart: cyan up bars and magenta down bars are bars that occur in the "Asian session," i.e. after 17:00 New York Time local time and before 07:00 London local time; and blue up bars and red down bars are bars that occur in the overlapping London - New York session, i.e. between 07:00 London local time and 17:00 New York local time.

The horizontal black lines are not part of the basic plot function but are added later by use of the "hold" function. These lines are the "Tokyo Channel," i.e. the high and low of the Asian session extended into the immediately following London - New York session.

I hope readers who use Octave will find these plotting functions useful.