'drawing a binomial tree in latex with python

I want to have some code that draws a binomial tree (for finance) for how ever many periods I give it.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\begin{document}
\begin{tikzpicture}[>=stealth,sloped]
            \matrix (tree) [%
            matrix of nodes,
            minimum size=1cm,
            column sep=3.5cm,
            row sep=1cm,
            ]
        { &  & $S_0U^2 $ \\
 & $S_0U $ &  \\
$S_0$ &  & $S_0U D$ \\
 & $S_0 D$ &  \\
 &  & $S_0 D^2$ \\
};
\draw[->] (tree-4-2) -- (tree-3-3) node [midway,above] {$ p (1-p) $};
\draw[->] (tree-4-2) -- (tree-5-3) node [midway,above] {$  (1-p)^2 $};
\draw[->] (tree-3-1) -- (tree-2-2) node [midway,above] {$ p  $};
\draw[->] (tree-3-1) -- (tree-4-2) node [midway,above] {$  (1-p) $};
\draw[->] (tree-2-2) -- (tree-1-3) node [midway,above] {$ p^2  $};
\draw[->] (tree-2-2) -- (tree-3-3) node [midway,above] {$ p (1-p) $};
\end{tikzpicture}
\end{document} 

Binomial tree output

Something like this but that then can be extended to however my periods want ?



Solution 1:[1]

I made the following function

def make_binomial_tree(number_of_periods):
    columns = {}
    columns2 = {}
    if number_of_periods < 4:
        st = """\\begin{tikzpicture}[>=stealth,sloped]
            \\matrix (tree) [%
            matrix of nodes,
            minimum size=1cm,
            column sep=3.5cm,
            row sep=1cm,
            ]
        {"""
    else:
        st = '''\\begin{tikzpicture}[>=stealth,sloped]
            \\matrix (tree) [%
            matrix of nodes,minimum size=0.5cm,
        column sep=1cm,
        row sep=0.5cm,]{'''
    st2 = ''
    for j in range_(-number_of_periods, 1, -1):
        for i in range_(0, j+1):
            try:
                columns[j].append('')
                columns2[j].append('')
            except:
                columns[j] = ['' for i in range(number_of_periods-j)]
                columns2[j] = ['' for i in range(number_of_periods-j)]
            columns2[j].append(('U'*i+'D'*(j-i)))
            columns[j].append(
                (f"""{'$S_0U' if i==1 else f'$S_0U^{i}'if i>0 else '$S_0'} {"D$" if j-i==1 else f'D^{(j-i)}$'if j-i>0 else '$'}"""
                 if not (i == j and j == 0) else '$S_0$')
            )
        for i in range(number_of_periods-j):
            columns[j].append('')
            columns2[j].append('')
    for i in range_(-2*number_of_periods, 1, -1):
        for j in range(len(columns)):
            if j != len(columns)-1:
                st += (columns[j][i] + ' & ')
                if columns[j][i] != '':
                    U1, D1, U2, D2 = columns2[j+1][i-1].count("D"), columns2[j+1][i-1].count(
                        "U"), columns2[j+1][i+1].count("D"), columns2[j+1][i+1].count("U")
                    # adding the ligns and their values between nodes on the tree
                    st2 += (
                        f'\draw[->] (tree-{i+1}-{j+1}) -- (tree-{i}-{j+2}) node [midway,above] ') + \
                        f'{"{"}$ {"p" if U1 ==1 else f"p^{U1}" if U1 > 0 else ""} {"(1-p)" if D1 == 1 else f"(1-p)^{D1}" if D1 > 0 else ""} ${"}"};\n' + \
                        (
                        f'\draw[->] (tree-{i+1}-{j+1}) -- (tree-{i+2}-{j+2}) node [midway,above] ') +\
                        f'{"{"}$ {"p" if U2 ==1 else f"p^{U2}" if U2 > 0 else ""} {"(1-p)" if D2 == 1 else f"(1-p)^{D2}" if D2 > 0 else ""} ${"}"};\n'
            else:
                st += (columns[j][i])
        st += ' \\\\\n'
    st += '};\n' + st2 + '\end{tikzpicture}'
    return st

Hopefully this helps someone else!

Solution 2:[2]

thank you very much. Really helpful. Though I had some issues with your code (the range_ is not a standard function so it doesn't work). I rewrote the code and this one seems to work fine

def make_binomial_tree(number_of_periods):
    columns = {}
    columns2 = {}
    if number_of_periods < 4:
        st = """\\begin{tikzpicture}[>=stealth,sloped]
            \\matrix (tree) [%
            matrix of nodes,
            minimum size=1cm,
            column sep=3.5cm,
            row sep=1cm,
            ]
        {"""
    else:
        st = '''\\begin{tikzpicture}[>=stealth,sloped]
            \\matrix (tree) [%
            matrix of nodes,minimum size=0.5cm,
        column sep=1cm,
        row sep=0.5cm,]{'''
    st2 = ''
    for j in range(number_of_periods, -1, -1):
        for i in range(0, j+1):
            if j in columns:
                columns[j].append('')
                columns2[j].append('')
            else:
                columns[j] = ['' for i in range(number_of_periods-j)]
                columns2[j] = ['' for i in range(number_of_periods-j)]
                
            columns2[j].append(('U'*(j-i)+'D'*(i)))
            tmp = (f"""{'$S_0U' if j-i==1 else f'$S_0U^{j-i}'if j-i>0 else '$S_0'} {"D$" if i==1 else f'D^{(i)}$'if i>0 else '$'}"""
                 if not (i == j and j == 0) else '$S_0$')
            columns[j].append(tmp)
        for i in range(number_of_periods-j):
            columns[j].append('')
            columns2[j].append('')

    columns = dict(reversed(list(columns.items())))

    for i in range(2*number_of_periods+1):
        for j in range(len(columns)):
            if j != len(columns)-1:
                st += (columns[j][i] + ' & ')
                if columns[j][i] != '':
                    U1, D1, U2, D2 = columns2[j+1][i-1].count("U"), columns2[j+1][i-1].count(
                        "D"), columns2[j+1][i+1].count("U"), columns2[j+1][i+1].count("D")
                    # adding the ligns and their values between nodes on the tree
                    st2 += (
                        f'\draw[->] (tree-{i+1}-{j+1}) -- (tree-{i}-{j+2}) node [midway,above] ') + \
                        f'{"{"}$ {"p" if U1 ==1 else f"p^{U1}" if U1 > 0 else ""} {"(1-p)" if D1 == 1 else f"(1-p)^{D1}" if D1 > 0 else ""} ${"}"};\n' + \
                        (
                        f'\draw[->] (tree-{i+1}-{j+1}) -- (tree-{i+2}-{j+2}) node [midway,above] ') +\
                        f'{"{"}$ {"p" if U2 ==1 else f"p^{U2}" if U2 > 0 else ""} {"(1-p)" if D2 == 1 else f"(1-p)^{D2}" if D2 > 0 else ""} ${"}"};\n'
            else:
                st += (columns[j][i])
        st += ' \\\\\n'
    st += '};\n' + st2 + '\end{tikzpicture}'
    return st

When you call print(make_binomial_tree(4)) you get:

\begin{tikzpicture}[>=stealth,sloped]
        \matrix (tree) [%
        matrix of nodes,minimum size=0.5cm,
    column sep=1cm,
    row sep=0.5cm,]{ &  &  &  & $S_0U^4 $ \\
&  &  & $S_0U^3 $ &  \\
 &  & $S_0U^2 $ &  & $S_0U^3 D$ \\
 & $S_0U $ &  & $S_0U^2 D$ &  \\
$S_0$ &  & $S_0U D$ &  & $S_0U^2 D^2$ \\
 & $S_0 D$ &  & $S_0U D^2$ &  \\
 &  & $S_0 D^2$ &  & $S_0U D^3$ \\
 &  &  & $S_0 D^3$ &  \\
 &  &  &  & $S_0 D^4$ \\
};
\draw[->] (tree-2-4) -- (tree-1-5) node [midway,above] {$ p^4  $};
\draw[->] (tree-2-4) -- (tree-3-5) node [midway,above] {$ p^3 (1-p) $};
\draw[->] (tree-3-3) -- (tree-2-4) node [midway,above] {$ p^3  $};
\draw[->] (tree-3-3) -- (tree-4-4) node [midway,above] {$ p^2 (1-p) $};
\draw[->] (tree-4-2) -- (tree-3-3) node [midway,above] {$ p^2  $};
\draw[->] (tree-4-2) -- (tree-5-3) node [midway,above] {$ p (1-p) $};
\draw[->] (tree-4-4) -- (tree-3-5) node [midway,above] {$ p^3 (1-p) $};
\draw[->] (tree-4-4) -- (tree-5-5) node [midway,above] {$ p^2 (1-p)^2 $};
\draw[->] (tree-5-1) -- (tree-4-2) node [midway,above] {$ p  $};
\draw[->] (tree-5-1) -- (tree-6-2) node [midway,above] {$  (1-p) $};
\draw[->] (tree-5-3) -- (tree-4-4) node [midway,above] {$ p^2 (1-p) $};
\draw[->] (tree-5-3) -- (tree-6-4) node [midway,above] {$ p (1-p)^2 $};
\draw[->] (tree-6-2) -- (tree-5-3) node [midway,above] {$ p (1-p) $};
\draw[->] (tree-6-2) -- (tree-7-3) node [midway,above] {$  (1-p)^2 $};
\draw[->] (tree-6-4) -- (tree-5-5) node [midway,above] {$ p^2 (1-p)^2 $};
\draw[->] (tree-6-4) -- (tree-7-5) node [midway,above] {$ p (1-p)^3 $};
\draw[->] (tree-7-3) -- (tree-6-4) node [midway,above] {$ p (1-p)^2 $};
\draw[->] (tree-7-3) -- (tree-8-4) node [midway,above] {$  (1-p)^3 $};
\draw[->] (tree-8-4) -- (tree-7-5) node [midway,above] {$ p (1-p)^3 $};
\draw[->] (tree-8-4) -- (tree-9-5) node [midway,above] {$  (1-p)^4 $};
\end{tikzpicture}

and putting it into a latex document like this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\begin{document}
\begin{tikzpicture}[>=stealth,sloped]
            \matrix (tree) [%
            matrix of nodes,minimum size=0.5cm,
        column sep=1cm,
        row sep=0.5cm,]{ &  &  &  & $S_0U^4 $ \\
 &  &  & $S_0U^3 $ &  \\
 &  & $S_0U^2 $ &  & $S_0U^3 D$ \\
 & $S_0U $ &  & $S_0U^2 D$ &  \\
$S_0$ &  & $S_0U D$ &  & $S_0U^2 D^2$ \\
 & $S_0 D$ &  & $S_0U D^2$ &  \\
 &  & $S_0 D^2$ &  & $S_0U D^3$ \\
 &  &  & $S_0 D^3$ &  \\
 &  &  &  & $S_0 D^4$ \\
};
\draw[->] (tree-2-4) -- (tree-1-5) node [midway,above] {$ p^4  $};
\draw[->] (tree-2-4) -- (tree-3-5) node [midway,above] {$ p^3 (1-p) $};
\draw[->] (tree-3-3) -- (tree-2-4) node [midway,above] {$ p^3  $};
\draw[->] (tree-3-3) -- (tree-4-4) node [midway,above] {$ p^2 (1-p) $};
\draw[->] (tree-4-2) -- (tree-3-3) node [midway,above] {$ p^2  $};
\draw[->] (tree-4-2) -- (tree-5-3) node [midway,above] {$ p (1-p) $};
\draw[->] (tree-4-4) -- (tree-3-5) node [midway,above] {$ p^3 (1-p) $};
\draw[->] (tree-4-4) -- (tree-5-5) node [midway,above] {$ p^2 (1-p)^2 $};
\draw[->] (tree-5-1) -- (tree-4-2) node [midway,above] {$ p  $};
\draw[->] (tree-5-1) -- (tree-6-2) node [midway,above] {$  (1-p) $};
\draw[->] (tree-5-3) -- (tree-4-4) node [midway,above] {$ p^2 (1-p) $};
\draw[->] (tree-5-3) -- (tree-6-4) node [midway,above] {$ p (1-p)^2 $};
\draw[->] (tree-6-2) -- (tree-5-3) node [midway,above] {$ p (1-p) $};
\draw[->] (tree-6-2) -- (tree-7-3) node [midway,above] {$  (1-p)^2 $};
\draw[->] (tree-6-4) -- (tree-5-5) node [midway,above] {$ p^2 (1-p)^2 $};
\draw[->] (tree-6-4) -- (tree-7-5) node [midway,above] {$ p (1-p)^3 $};
\draw[->] (tree-7-3) -- (tree-6-4) node [midway,above] {$ p (1-p)^2 $};
\draw[->] (tree-7-3) -- (tree-8-4) node [midway,above] {$  (1-p)^3 $};
\draw[->] (tree-8-4) -- (tree-7-5) node [midway,above] {$ p (1-p)^3 $};
\draw[->] (tree-8-4) -- (tree-9-5) node [midway,above] {$  (1-p)^4 $};
\end{tikzpicture}
\end{document} 

you get:

binomial tree

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 gmv
Solution 2