Skip to content

Instantly share code, notes, and snippets.

@Beliavsky
Created March 18, 2020 14:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Beliavsky/c81919cae66bbe77d1c32360a7a992a3 to your computer and use it in GitHub Desktop.
Save Beliavsky/c81919cae66bbe77d1c32360a7a992a3 to your computer and use it in GitHub Desktop.
! RESULTS:
! #paths initial ann_drift ann_vol min max <terminal> terminal terminal-max sd(terminal) %bottom
! 100000 100.00 0.15 0.40 77.99 145.60 116.18 115.95 -29.65 48.21 4.52
! 100000 100.00 0.15 0.40 77.97 145.67 116.18 116.04 -29.63 48.30 4.39
! 100000 100.00 0.15 0.40 77.92 145.58 116.18 115.88 -29.70 48.25 4.33
! 100000 100.00 0.15 0.40 78.02 145.96 116.18 116.27 -29.69 48.64 4.41
! 100000 100.00 0.15 0.40 78.02 145.53 116.18 115.93 -29.60 47.89 4.37
module statistics_mod
implicit none
public :: dp,mean,sd,random_normal
integer, parameter :: dp = kind(1.0d0)
contains
pure function mean(xx) result(xmean)
! compute the mean of xx(:)
real(kind=dp), intent(in) :: xx(:)
real(kind=dp) :: xmean
integer :: n
n = size(xx)
if (n > 0) then
xmean = sum(xx)/n
else
xmean = 0.0_dp
end if
end function mean
!
pure function sd(xx) result(xsd)
! compute the standard deviation of xx(:)
real(kind=dp), intent(in) :: xx(:)
real(kind=dp) :: xsd
real(kind=dp) :: xmean
integer :: n
n = size(xx)
if (n > 1) then
xmean = sum(xx)/n
xsd = sqrt(sum((xx-xmean)**2)/(n-1))
else
xsd = -1.0
end if
end function sd
!
function random_normal() result(fn_val)
! Generate a random normal deviate using the polar method.
! Reference: Marsaglia,G. & Bray,T.A. 'A convenient method for generating
! normal variables',Siam Rev.,vol.6,260-264,1964.
real(kind=dp) :: fn_val
! Local variables
real(kind=dp) :: u,sum
real(kind=dp),save :: v,sln
logical,save :: second = .false.
real(kind=dp),parameter :: one = 1.0d0,vsmall = tiny(one)
if (second) then
! If second,use the second random number generated on last call
second = .false.
fn_val = v*sln
else
! First call; generate a pair of random normals
second = .true.
do
call random_number(u)
call random_number(v)
u = scale(u,1) - one
v = scale(v,1) - one
sum = u*u + v*v + vsmall ! vsmall added to prevent log(zero) / zero
if(sum < one) exit
end do
sln = sqrt(- scale(log(sum),1) / sum)
fn_val = u*sln
end if
end function random_normal
end module statistics_mod
!
program xxreturns_drawdown
! 03/18/2020 10:16 AM branched from xreturns_drawdown.f90 to xxreturns_drawdown.f90
! 03/18/2020 09:50 AM simulate the maximum cumulative loss given expected return and volatility
use statistics_mod , only: dp,mean,sd,random_normal
integer, parameter :: tdy = 252 ! trading days per year
integer, parameter :: nfwd = 252
integer, parameter :: niter = 100000, nsim = 5
real(kind=dp) :: ann_drift,ann_vol,daily_drift,daily_vol,x0,xx(0:nfwd),xmin(niter),xmax(niter),xlast(niter)
integer :: i,iter,isim
call random_seed()
ann_drift = 0.15_dp ! annualized simple daily return
ann_vol = 0.40_dp ! annualized daily volatility
daily_drift = ann_drift/tdy
daily_vol = ann_vol/sqrt(dble(tdy))
x0 = 100.0_dp ! initial stock price
write (*,"(100a13)") "#paths","initial","ann_drift","ann_vol","min","max","<terminal>", &
"terminal","terminal-max","sd(terminal)","%bottom"
do_sim: do isim=1,nsim
do iter=1,niter
do i=0,nfwd
if (i > 0) then
xx(i) = xx(i-1)*(1 + daily_drift + daily_vol*random_normal())
else
xx(i) = x0
end if
end do
xmin(iter) = minval(xx)
xmax(iter) = maxval(xx)
xlast(iter) = xx(nfwd)
end do
write (*,"(i13,100f13.2)") niter,x0,ann_drift,ann_vol,mean(xmin),mean(xmax),x0*(1+daily_drift)**nfwd, &
mean(xlast),mean(xlast-xmax),sd(xlast),100.0_dp*count(xmin >= x0)/niter
end do do_sim
end program xxreturns_drawdown
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment