################################################
##
## This module contains the frequently used functions.
##
################################################
## 
## CHANGELOG
##
## 1.0 - 25 Apr 2013
## * First public version
##
################################################

use strict;
use warnings;
use Carp;
use Statistics::Descriptive;
use Statistics::Basic qw(:all);
use Data::Dumper;

our $AUTHOR  = 'Joachim De Schrijver';
our $VERSION = '1.0';
our $DATE    = '25 Apr 2013';
our $MODULE  = 'Finance::Functions';

################################################

###########
# Calculate sample variance (i.e. divided by n-1).
#
# Input [array]:
#   1) Reference to array with values
# 
# Output [array]:
#   1) Sample variance
#
###########

sub SampleVar {

	# Capture array
	my @array = @{$_[0]};
	
	# Fix degree of freedom
	my $df = scalar(@array) - 1;
	
	if ($df == 0){
		$df++;
	}
	
	# Calculate fixed
	my $var = variance(@array) * ($df+1) / $df;
	
	# Return
	return $var;
}

###########
# Calculate sample mean.
#
# Input [array]:
#   1) Reference to array with values
# 
# Output [array]:
#   1) Sample mean
#
###########

sub SampleMean  {

	# Capture array
	my @array = @{$_[0]};
	
	# Calculate
	my $avg = 0;
	foreach (@array){
		$avg += $_;
	}
	$avg /= scalar(@array);
	
	# Return
	return $avg;
}

###########
# Normalize values by standard error.
#
# Input [array]:
#   1) Reference to array with values
# 
# Output [array]:
#   1) Sample variance
#
###########

sub SENormalize {
	
	# Capture
	my $array_ref = $_[0];
	my @array = @$array_ref;
	
	# Get variance
	my $var = SampleVar($array_ref);
	my $se  = sqrt($var);
	
	# Normalize
	my @b;
	foreach(@array){
		push(@b,$_/$se);
	}
	
	# Return
	return(\@b);
}

###########
# Calculate JarquerBera statistic for normality.
#
# Input [array]:
#   1) Reference to array with values
# 
# Output [array]:
#   1) JB value
#
###########

sub JarqueBera	{

	# Capture
	my $array_ref = $_[0];

	my $stat = Statistics::Descriptive::Full->new();
    	$stat->add_data($array_ref);
	
	# Observations 
	my $n = scalar(@$array_ref);
	
	# Skewness
	my $skew = $stat->skewness();
	
	# Kurtosis
	my $kurt = $stat->kurtosis();
	
	# JB
	my $JB = $n/6*(($skew ** 2) + 1/4*(($kurt) ** 2));

	# Return
	return($JB);
}

###########
# Calculate position of a value in a distribution.
#
# Input [array]:
#   1) Reference to array with values
#   2) Test value
# 
# Output [array]:
#   1) Position in distribution
#
###########

sub rank_pos {
	
	# Catch
	my @array = @{$_[0]};
	my $val = $_[1];
	
	# Sort
	my @sort = sort {$b <=> $a} @array;
	
	# Find position & return
	for (my $i = 1; $i<=scalar(@sort); $i++){
		if ($val >= $sort[($i-1)]){
			return $i;
		}
	}
	
	# Return last position if no hit
	return(scalar(@sort) + 1);
}

1;