7
\$\begingroup\$

Background:

In finance, the binomial options pricing model (BOPM) is the simplest technique used for option pricing. The mathematics behind the model is relatively easy to understand and (at least in their basic form) it is not difficult to implement. This model was first proposed by Cox, Ross, and Rubinstein in 1979. Quoting Wikipedia:

The binomial pricing model traces the evolution of the option's key underlying variables in discrete-time. This is done by means of a binomial lattice (tree), for a number of time steps between the valuation and expiration dates. Each node in the lattice represents a possible price of the underlying at a given point in time.

Valuation is performed iteratively, starting at each of the final nodes (those that may be reached at the time of expiration), and then working backwards through the tree towards the first node (valuation date). The value computed at each stage is the value of the option at that point in time.

For this challenge's sake, we will create a simple model to predict potential future prices of the option(s) by creating a lattice or a tree as shown below (a picture is worth a thousand words):

enter image description here

where S is the option price today, p is the probability of a price rise, and t is the period of time or number of steps.

Challenge:

The challenge is to write either a program or a function which take S, p (in percent), and t as the inputs and give the binomial tree as the output. The output of the program or the function must follow the format above, but the boxes and the arrow lines are optional. For example, if the program take inputs S = 100, p = 10%, and t = 3, then its output may be in the following simple form:

                        133.1
                121 
        110             108.9
100              99 
         90              89.1
                 81 
                         72.9

General rules:

  • This is , so the shortest answer in bytes wins the challenge.
    Don't let esolangs discourage you from posting an answer with regular languages. Enjoy this challenge by providing an answer as short as possible with your programming language. If you post a clever answer and a clear explanation, your answer will be appreciated (hence the upvotes) regardless of the programming language you use.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/ method with the proper parameters, full programs, etc. The choice is yours.
  • Using a binomial tree built-in is forbidden.
  • If possible, your program can properly handle a large number of steps. If not, that will just be fine.

References:

  1. Binomial options pricing model
  2. Binomial tree option calculator
\$\endgroup\$
  • \$\begingroup\$ Just for the sake of precision, aren't the formula more (1+p).S, (1+(1-p)).S at T1, (1+p²).S, (1+(p.(1-p))).s and (1-(1-p)²).s at T2 and so on? \$\endgroup\$ – Sefa Aug 30 '16 at 7:13
  • \$\begingroup\$ @Sefa I apologize for the mistake I made. I've already edited to fix the issue accordingly. \$\endgroup\$ – Anastasiya-Romanova 秀 Aug 30 '16 at 7:17
  • 1
    \$\begingroup\$ 10% is not a valid number in many languages. Are we to take in 0.1 or 10 for 10%? \$\endgroup\$ – Leaky Nun Aug 30 '16 at 7:58
  • 2
    \$\begingroup\$ @LeakyNun I read "(in percent)" in it's true meaning which would mean 0.1 is 10%. \$\endgroup\$ – Jonathan Allan Aug 30 '16 at 8:01
  • \$\begingroup\$ I think p is the probability of a price rise should be p is the **percentage** of a price rise. \$\endgroup\$ – randomra Aug 30 '16 at 10:17
2
\$\begingroup\$

Dyalog APL, 60 56 bytes

Needs ⎕IO←0 which is default on many systems. Prompts for S then t then p.

⍉{⍵⌽⍨-⌽⍳≢⍵}↑{⍵\⍨0 1⍴⍨2×≢⍵}¨⍕¨¨⎕{⍵,⊂∪∊(⊃⌽⍵)∘.×1+⍺,-⍺}⍣⎕⊢⎕

Over 50% of the code is to get the right display form.

TryAPL online! (]Box off for proper display – the default on installed systems – emulated here using .)

Example run:

                133.1 
           121        
      110       108.9 
 100       99         
      90        89.1  
           81         
                72.9  
|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ How do I insert the inputs there? \$\endgroup\$ – Anastasiya-Romanova 秀 Aug 30 '16 at 8:20
  • \$\begingroup\$ If you run it on a regular system, it will prompt you for S, t, and p (e.g. 0.1) – in that order. If you use TryAPL, you will need to press UpArrow to recall the previous statement, then edit the line right after ∆←. \$\endgroup\$ – Adám Aug 30 '16 at 9:47
  • \$\begingroup\$ Ah, it works like R. Unfortunately, it only handles 11 steps. But it's OK. Well done. (+1) \$\endgroup\$ – Anastasiya-Romanova 秀 Aug 30 '16 at 9:50
  • \$\begingroup\$ Why do you say so? TryAPL chops output to avoid scrolling, but a real APL system doesn't. You can download it for free here. \$\endgroup\$ – Adám Aug 30 '16 at 9:53
  • \$\begingroup\$ I said so because when I input the number of steps 12, the format breaks. R also uses Up Arrow to show the previous code. Thanks for the offer, though it's a good programming language but I'm not interested in learning APL \$\endgroup\$ – Anastasiya-Romanova 秀 Aug 30 '16 at 9:57
2
\$\begingroup\$

Python, 168 167 bytes

q=lambda s,p,t:'\n'.join(''.join('%e'%(s*(1+p)**(c-(r+c-t)//2)*(1-p)**((r+c-t)//2))if(t-c<=r<=t+c)&(r%2^(c+~t%2)%2)else' '*12for c in range(t+1))for r in range(2*t+1))

Test case with anonymous function above assigned to f would be print(f(100,0.1,3)), yielding:

                                    1.331000e+02
                        1.210000e+02
            1.100000e+02            1.089000e+02
1.000000e+02            9.900000e+01
            9.000000e+01            8.910000e+01
                        8.100000e+01
                                    7.290000e+01

Extending the same to t=4 would be print(f(100,0.1,3)), yielding:

                                                1.464100e+02
                                    1.331000e+02
                        1.210000e+02            1.197900e+02
            1.100000e+02            1.089000e+02
1.000000e+02            9.900000e+01            9.801000e+01
            9.000000e+01            8.910000e+01
                        8.100000e+01            8.019000e+01
                                    7.290000e+01
                                                6.561000e+01

For the avoidance of scientific notation while keeping at least 3 significant figures we can use the following 211 byte code instead:

lambda s,p,t:'\n'.join(''.join('%12s'%(v and(10**5>v>.0001and'%f'%v or'%e'%v)or'')for v in[(t-c<=r<=t+c)&(r%2^(c+~t%2)%2)and s*(1+p)**(c-(r+c-t)//2)*(1-p)**((r+c-t)//2)for c in range(t+1)])for r in range(2*t+1))

Test case, print(f(100,0.1,3)) yields:

                                      133.100000
                          121.000000
              110.000000              108.900000
  100.000000               99.000000
               90.000000               89.100000
                           81.000000
                                       72.900000

then when numbers get too big or small, for example print(f(9876.000123,0.99,6)):

                                                                        6.133375e+05
                                                            3.082098e+05
                                                1.548793e+05             3082.098178
                                    77828.796693             1548.793054
                        39109.948087              778.287967               15.487931
            19653.240245              391.099481                7.782880
 9876.000123              196.532402                3.910995                0.077829
               98.760001                1.965324                0.039110
                            0.987600                0.019653                0.000391
                                        0.009876                0.000197
                                                9.876000e-05            1.965324e-06
                                                            9.876000e-07
                                                                        9.876000e-09
|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ Is this a valid output format? \$\endgroup\$ – Adám Aug 30 '16 at 7:54
  • \$\begingroup\$ @Adám I don't see why not, the values are clearly separated, readable and in a deterministic order, the question has no output format specification and the example states "may". I'll add more code if need be though - Anastasiya-Romanova? \$\endgroup\$ – Jonathan Allan Aug 30 '16 at 7:59
  • \$\begingroup\$ I understand The output of the program or the function must follow the format above, but the boxes and the arrow lines are optional to mean that the 2D layout must remain. \$\endgroup\$ – Adám Aug 30 '16 at 8:03
  • \$\begingroup\$ @Adám yes you may well be correct! \$\endgroup\$ – Jonathan Allan Aug 30 '16 at 8:05
  • 1
    \$\begingroup\$ @Anastasiya-Romanova秀 I've added longer code that will fall over to scientific notation while keeping 3 significant figures. \$\endgroup\$ – Jonathan Allan Aug 30 '16 at 12:52
1
\$\begingroup\$

R, 288 bytes

x=scan()
M=Map
U=rbind
noquote(t(do.call(U,M(function(x,y){r=rep;c(r(" ",x),rev(as.vector(U(y,r(" ",length(y))))),r(" ",x))},as.list(x[3]:0),M(function(x,y){sapply(y,function(y)(1-x[2])^y[1]*(1+x[2])^y[2]*x[1])},list(x),lapply(0:x[3],function(y)data.frame(do.call(U,list(y:0, 0:y)))))))))

Sometimes I feel like I'm not even golfing. The maximum t is limited by the amount of system memory. The readability of output is determined by the resolution of your screen/console size. If we write to file instead, the readability limitations can be bypassed. I was able to run t = 5000, 100, 0.1 on my 16GB ram system; the output is 400+ mb plain text file.

      [,1] [,2] [,3] [,4]  [,5]   [,6]    [,7]     [,8]      [,9]       [,10]            [,11]            [,12]           
 [1,]                                                                                                                     
 [2,]                                                                                                     285.311670611   
 [3,]                                                                                    259.37424601                     
 [4,]                                                                   235.7947691                       233.436821409   
 [5,]                                                        214.358881                  212.21529219                     
 [6,]                                              194.87171            192.9229929                       190.993762971   
 [7,]                                     177.1561           175.384539                  173.63069361                     
 [8,]                             161.051          159.44049            157.8460851                       156.267624249   
 [9,]                      146.41         144.9459           143.496441                  142.06147659                     
[10,]                133.1        131.769          130.45131            129.1467969                       127.855328931   
[11,]           121        119.79         118.5921           117.406179                  116.23211721                     
[12,]      110       108.9        107.811          106.73289            105.6655611                       104.608905489   
[13,] 100       99         98.01          97.0299            96.059601                   95.0990049900001                 
[14,]      90        89.1         88.209           87.32691             86.4536409000001                  85.5891044910001
[15,]           81         80.19          79.3881            78.594219                   77.80827681                      
[16,]                72.9         72.171           71.44929             70.7347971000001                  70.027449129    
[17,]                      65.61          64.9539            64.304361                   63.66131739                      
[18,]                             59.049           58.45851             57.8739249                        57.295185651    
[19,]                                     53.1441            52.612659                   52.08653241                      
[20,]                                              47.82969             47.3513931                        46.877879169    
[21,]                                                        43.046721                   42.61625379                      
[22,]                                                                   38.7420489                        38.354628411    
[23,]                                                                                    34.86784401                      
[24,]                                                                                                     31.381059609 

t = 5000; enter image description here

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for?Browse other questions tagged or ask your own question.