#!/usr/bin/perl -w

use strict;

my $INT = .01/365;      # dayly interest
# my $INTMONTH = .01/12;
my $TC  = 20;           # transaction cost - international stock buy
my $MINI = 300;     # in MO and simulation - minimal amount of cash
print "El mínimo aceptable de tesorería se considera $MINI (DATO DE ENTRADA)\n";

my $INMAX = 600;     # cash incomes
my $INMIN = 100; 

my $PMAX = 400;      # cash payments
my $PMIN = 0;

my $ITERATIONS = 365;  # 3 years
my $ROUNDS = 3;  # 2 de cáculo, 1 de simulación de MO  <--------- IMPORTANTE

my ($i,@cash,$inc,$pay,$variance,$mean,$momax,$modesir);
my ($invest,$obj,$iter,$simumax,$simudesir,$postcash);

$cash[0]=0;
for $i (1..$ITERATIONS*($ROUNDS-1)){
    $inc = $INMIN+ rand() * ($INMAX-$INMIN);
    $pay = $PMIN + rand() * ($PMAX-$PMIN);
    $cash[$i] = $inc-$pay;   # en el periodo de cálculo se invierte todo el dinero + $cash[$i-1];
    $mean += $cash[$i];
    $invest += $cash[$i];
    $invest *= (1+$INT);
}
$mean /= $ITERATIONS*($ROUNDS-1); 
for $i (1..$ITERATIONS*($ROUNDS-1)){
    $variance += ($cash[$i] - $mean)**2; 
}
$variance /= $ITERATIONS*($ROUNDS-1); 
print "mean $mean  variance $variance\n";

$momax = MO_max($variance,$INT,$TC);
$modesir = MO_desir($variance,$INT,$TC);
print "MOmax $momax  MOdesir $modesir\n";

print "Se parte con $cash[$ITERATIONS*($ROUNDS-1)]\n";
print "Se llegó a una inversión $invest\n";

# tras 2 rondas para el cálculo MO, se testea en la tercera ronda

$postcash = $cash[$ITERATIONS*($ROUNDS-1)];
for $i ($ITERATIONS*($ROUNDS-1)+1 .. $ITERATIONS*$ROUNDS){    
    $inc = $INMIN+ rand() * ($INMAX-$INMIN);
    $pay = $PMIN + rand() * ($PMAX-$PMIN);
    $cash[$i] = $inc-$pay + $postcash;
    $postcash += $cash[$i];
    $invest *= (1+$INT);
    if ($postcash>$momax) {
	$invest += $postcash - $modesir - $TC;
	$postcash = $modesir;
    }elsif ($postcash<$MINI) {
	if ($modesir-$postcash+$TC<$invest){
	    $invest -= ($modesir - $postcash) + $TC;
	    $postcash=$modesir;
	}else{
	    $postcash += $invest;
	    $invest = 0;
	}
    }
    print "$i $cash[$i] -> invest $invest  postcash $postcash\n"; 
}
print "El objetivo de inversión es $invest\n";
$obj = $invest;

exit 0;

if (0){                     # esto no tiene sentido, es simular otro periodo para el mismo cálculo
while (1){
    $iter++;
    $simumax = rand(3*$INMAX);
    $simudesir = $MINI + rand($INMAX);
    $invest = $postcash = 0;
    for $i (1..$ITERATIONS){
	$postcash += $cash[$i];
	$invest *= (1+$INT);
	if ($postcash>$simumax) {
	    $invest += $postcash - $simudesir - $TC;
	    $postcash=$simudesir;
	}elsif ($postcash<$MINI) {
	    if ($simudesir-$postcash+$TC<$invest){
		$invest -= ($simudesir - $postcash) + $TC;
		$postcash=$simudesir;
	    }else{
		$postcash += $invest;
		$invest =0;
	    }
	}
    }
    if ($invest > $obj) {
	print "$iter -> $simumax , $simudesir => $invest\n";
	$obj = $invest;
    }
}
}




sub MO {
    my ($var,$int,$ct) = @_;
    return 3*(.75*$ct*$var/$int)**(1/3);
}

sub MO_desir {
    my ($var,$int,$ct) = @_;
    return $MINI + MO($var,$int,$ct)/3;
}

sub MO_max {
    my ($var,$int,$ct) = @_;
    return $MINI + MO($var,$int,$ct);
}

__END__

The formula of Miller-Orr cash limits is on every decent manual of finance.
  It is simple, but: 1) it have had a previous period of calculus 2) it have to be proyected to other to test  

