编辑

编辑

对于衍生品定价课程,我想找到一种快速高效地绘制重组二叉树的方法。这门课涉及了相当多的这种树,如果能找到一种允许我半自动化该过程的方法,那将非常有帮助。

这是一个例子(请原谅分辨率低;这是我能找到的最好的例子): 在此处输入图片描述

我希望通过仅指定周期数(即水平级别)来实现此外观;p从任何节点向上的概率;以及所有节点的可能值。然后概率p1-p应自动分别显示在连接线上方向上和向下(如示例所示)。节点本身的所有值都应手动输入,其数量当然取决于级别数。

我知道可以手动指定节点位置以实现重组树,但我的经验不足以构建自动化的东西。我的问题不是一般地绘制重组树;而是找到一种快速完成的方法,因为我使用 LaTeX 来做我的讲义。

答案1

版本2(覆盖节点标签的策略)

我在箭头上方/下方添加了概率;p0可以通过命令进行更改\malp。在它旁边,我d在节点中写入了水平级别加上 s(垂直级别)信息的数量。我们可以通过命令将其关闭\nodeformat。如果我们想添加自己的节点文本,它位于最后一个代码块中,我们会覆盖当前的节点标签,例如

3/2/G/yellow
  • 3- 是第三水平层,
  • 2- 是 s 的数量d(垂直层级,从 0 开始),
  • G- 是我们希望看到的文本,
  • yellow- 是该特定节点的填充颜色。

我正在添加新版本的源代码和简单示例的预览。希望这会有所帮助,因为理解所要求的图表格式并不容易。

% *latex mal-tree.tex
\documentclass[a4paper]{article}
\pagestyle{empty} % no page numbers, please
\usepackage{tikz} % graphics engine
\usetikzlibrary{arrows.meta} % 

\begin{document}
\def\mallevel{5} % a number of levels we wish to get
\def\malp{0.25} % probability p
\def\nodeformat{\x-\numberofd} % text written in the node, {} or {\numberofs-\numberofd}

\def\ratiox{2.5} % longer arrows (horizontal direction)
\def\ratioy{1.5} % longer arrows (vertical direction)

% Defining styles...
\tikzset{
   inner sep=0pt, outer sep=2pt, % some node reserve
   malarrow/.style={->, shorten >=0pt, shorten <=-2pt, -{Stealth[length=5pt, width=3pt, inset=1pt]},
   }, % a style for arrows, -2 is a shift back (an experiment)
   malnode/.style={draw=black, fill=none, minimum width=5mm, circle, inner sep=1pt}, % a style for nodes
   prob/.style={pos=0.3, sloped, font=\footnotesize},
   }

% the picture itself
\begin{tikzpicture}
\foreach \x in {0,...,\mallevel} { % horizontal direction of a tree
\foreach \y in {0,...,\x} { % vertical direction of a tree
\pgfmathparse{-\x/2+\y} % move up by a half of a tree (vertical direction)
\let\movey=\pgfmathresult % save the result
% position of nodes
%\ifnum\y=0 \def\whereto{below} \else \def\whereto{above} \fi
%\ifnum\x=0 \ifnum\y=0 \def\whereto{left} \fi \fi
   % d, number of ds and its output format
   \pgfmathparse{int(\x-\y)} 
   \let\numberofd=\pgfmathresult
   %\ifnum\numberofd=0 \def\mald{} \fi % print nothing if there is no d
   %\ifnum\numberofd=1 \def\mald{d} \fi % print d without superscript
   %\ifnum\numberofd>1 \def\mald{d^{\numberofd}} \fi % regular d with superscript
   % u, number of us and its output format
   \pgfmathparse{int(\y)}
   \let\numberofs=\pgfmathresult
   %\ifnum\y=0 \def\malu{} \fi % print nothing if there is no u
   %\ifnum\y=1 \def\malu{u} \fi % print u without superscript
   %\ifnum\y>1 \def\malu{u^{\y}} \fi % regular u with superscript
\node[malnode, font=\tiny] %label=\whereto:$S_0\mald\malu$
   (\x-\y) at (\ratiox*\x, \ratioy*\movey) {\nodeformat}; % draw a node + its label
   \ifnum\x>0 % draw the arrows
      \pgfmathparse{int(\x-1)}
      \let\previousx=\pgfmathresult % previous level (horizontal direction)
      \pgfmathparse{int(\y-1)}
      \let\previousy=\pgfmathresult % previous level (vertical direction)
            \pgfmathparse{\malp^\y * (1-\malp)^\numberofd}
            \let\maltype=\pgfmathresult      
         \ifnum\y<\x 
            \draw[malarrow] (\previousx-\y)--(\x-\y) node [prob, below] {\maltype}; \fi % arrows from the left top node to the right bottom node, if previous node is defined
         \ifnum\y>0 
            \draw[malarrow] (\previousx-\previousy)--(\x-\y) node [prob, above] {\maltype}; \fi % arrows from the left bottom node to the right top node, if the previous node is defined
    \fi % end of \ifnum\x>0, otherwise we cannot draw an arrow
   } % \y, vertical direction upto \x level
} % \x, horizontal direction upto \mallevel.

% Overwriting mode...
\foreach \bonusx/\bonusy/\maltext/\malcolor in {1/0/A/yellow, 3/2/G/yellow, 4/2/T/yellow, 5/2/E/orange, 5/3/F/orange} {
   \pgfmathparse{-\bonusx/2+(\bonusx-\bonusy)} % move up by a half of a tree (vertical direction)
   \let\movey=\pgfmathresult % save the result
\node[malnode, font=\footnotesize, fill=\malcolor]
   (\bonusx-\bonusy) at (\ratiox*\bonusx, \ratioy*\movey) {\maltext};
   }   
\end{tikzpicture}
\end{document}

示例 2:覆盖节点标签策略


版本 1(旧版本)

这可能是您在 TikZ 中完成的起点。我使用了此符号问题。我在源代码中添加了一些注释。我们可以运行任何 LaTeX 引擎。

% *latex mal-a-tree.tex
\documentclass[a4paper]{article}
\pagestyle{empty} % no page numbers, please
\usepackage{tikz} % graphics engine
\usetikzlibrary{arrows.meta} % 

\begin{document}
\def\mallevel{7} % a number of levels we wish to get
\def\ratiox{1.7} % longer arrows (horizontal direction)
\def\ratioy{0.9} % longer arrows (vertical direction)

% Defining styles...
\tikzset{
   inner sep=0pt, outer sep=2pt, % some node reserve
   malarrow/.style={->, shorten >=0pt, shorten <=-2pt, -{Stealth[length=5pt, width=3pt, inset=1pt]}}, % a style for arrows, -2 is a shift back (an experiment)
   malnode/.style={draw=none, fill=black, minimum width=5pt, circle}, % a style for nodes
   }

% the picture itself
\begin{tikzpicture}
\foreach \x in {0,...,\mallevel} { % horizontal direction of a tree
\foreach \y in {0,...,\x} { % vertical direction of a tree
\pgfmathparse{-\x/2+\y} % move up by a half of a tree (vertical direction)
\let\movey=\pgfmathresult % save the result
% position of nodes
\ifnum\y=0 \def\whereto{below} \else \def\whereto{above} \fi
\ifnum\x=0 \ifnum\y=0 \def\whereto{left} \fi \fi
   % d, number of ds and its output format
   \pgfmathparse{int(\x-\y)} 
   \let\numberofd=\pgfmathresult
   \ifnum\numberofd=0 \def\mald{} \fi % print nothing if there is no d
   \ifnum\numberofd=1 \def\mald{d} \fi % print d without superscript
   \ifnum\numberofd>1 \def\mald{d^{\numberofd}} \fi % regular d with superscript
   % u, number of us and its output format
   \ifnum\y=0 \def\malu{} \fi % print nothing if there is no u
   \ifnum\y=1 \def\malu{u} \fi % print u without superscript
   \ifnum\y>1 \def\malu{u^{\y}} \fi % regular u with superscript
\node[malnode, label=\whereto:$S_0\mald\malu$] (\x-\y) at (\ratiox*\x, \ratioy*\movey) {}; % draw a node + its label
   \ifnum\x>0 % draw the arrows
      \pgfmathparse{int(\x-1)}
      \let\previousx=\pgfmathresult % previous level (horizontal direction)
      \pgfmathparse{int(\y-1)}
      \let\previousy=\pgfmathresult % previous level (vertical direction)
         \ifnum\y<\x \draw[malarrow] (\previousx-\y)--(\x-\y); \fi % arrows from the left top node to the right bottom node, if previous node is defined
         \ifnum\y>0 \draw[malarrow] (\previousx-\previousy)--(\x-\y); \fi % arrows from the left bottom node to the right top node, if the previous node is defined
      \fi % end of \ifnum\x>0, otherwise we cannot draw an arrow
   } % \y, vertical direction upto \x level
} % \x, horizontal direction upto \mallevel.
\end{tikzpicture}
\end{document}

7 个级别的示例

答案2

尝试使用 MetaPost 解决此问题。它定义了一个宏binomial_tree(expr N, p)(text thelabels),其中N是周期数(水平/垂直级别),p是概率值,并且(由于 OP 需要手动标记)thelabels是包含所有正确顺序的标签的列表,节点从左到右、从上到下编号。

编辑我稍微改变了前面的例子并引入了第二个例子。

\documentclass[border=2mm, multi=mplibcode]{standalone}
\usepackage{luatex85,luamplib}
  \mplibsetformat{metafun}
  \mplibtextextlabel{enable}
  \everymplib{
    % Horizontal and vertical distance
    % between consecutive nodes
    h := 3.25cm; v := 2.75cm;
    % Arrows a bit thinner and longer
    ahlength := 6bp; ahangle := 30; 

    % The main macro 
    def binomial_tree(expr N, p)(text thelabels) =
      pair pos[]; pos0 = pos1 = origin;
      value1 := 1; pen pendot; pendot = pencircle scaled 5; 
      string name[]; 
      k:= 0; for t = thelabels: k := k+1; name[k] = t; endfor
      k := 1; draw pos1 withpen pendot; label.lft(name1, pos0);

      for i = 2 upto N:
        labeloffset := 5bp;
        K := k-(i-2);
        pos0 := pos0 + (h, .5v);
        for j = 1 upto i:
          k := k+1;
          pos[k] := pos0 + (0, -(j-1)*v);
          value[k] := if j = 1: value[k-i+1]*p else: value[k-i]*(1-p) fi;
          draw pos[k] withpen pendot;
          label.if i=N: rt elseif j<>i:top else: bot fi(name[k], pos[k]);
        endfor

        labeloffset := 3bp;
        for j = 0 upto i-2:
          pair A, B, C; A = pos[K+j]; B = pos[K+j+i-1]; C = pos[K+j+i];
          drawarrow A -- B cutends 2.5bp; 
          label.top(decimal value[K+j+i-1], .5[A,B]) 
            rotatedaround(.5[A,B], angle(B-A));
          drawarrow A -- C cutends 2.5bp;
          label.bot(decimal value[K+j+i], .5[A,C]) 
            rotatedaround(.5[A,C], angle(C-A));
        endfor
      endfor
    enddef;
    beginfig(1);}

  \everyendmplib{endfig;}

\begin{document}
   \begin{mplibcode}
     binomial_tree(4, .65)("O", "I", "II", "$A$", "$B$", "$C$", 
       "$\alpha$", "$\beta$", "$\gamma$", "$\delta$");
   \end{mplibcode}
   \begin{mplibcode}
     binomial_tree(6, .25)("$A$" for i=1 upto 20:, "$" & char(65+i) & "$" endfor); 
   \end{mplibcode}
\end{document}

使用 LuaLaTeX 进行处理。这是第一个例子,带有p = .65N = 4和一个不太严肃的标签 :

binomial_tree(4, .65)("O", "I", "II", "$A$", "$B$", "$C$", 
  "$\alpha$", "$\beta$", "$\gamma$", "$\delta$");    

在此处输入图片描述

这是第二个示例,带有N=6p=0.25字母标签。我使用循环来解决这个问题,这样就不用手动输入 20 个字母了。:-)

binomial_tree(6, .25)("$A$" for i=1 upto 20:, "$" & char(65+i) & "$" endfor);

在此处输入图片描述

答案3

这将计算给定 值的概率p。您只需要my binomial=<value>在树的开头放置 ,以选择具有适当 值的适当样式p。我已将其用作0.25示例。您还可以根据要求手动指定节点的内容。

\documentclass[tikz,border=10pt]{standalone}
\usepackage{forest}
\tikzset{
  my label/.style={font=\small},
  my edge label/.style={font=\scriptsize, midway, sloped},
}
\forestset{
  my binomial/.style={
    TeX={\def\p{#1}},
    for tree={
      grow'=0,
      parent anchor=east,
      child anchor=west,
      circle,
      fill,
      text width=2.5pt,
      inner sep=0pt,
      outer sep=0pt,
      edge={->},
      s sep+=5pt,
      l sep+=25pt,
      before typesetting nodes={
        if level=0{
          label/.wrap pgfmath arg={[my label]left:##1}{content()},
          content={1},
        }{
          if n children=0{
            label/.wrap pgfmath arg={[my label]right:##1}{content()},
          }{
            if n=1{
              label/.wrap pgfmath arg={[my label]above:##1}{content()},
            }{
              label/.wrap pgfmath arg={[my label]below:##1}{content()},
            },
          },
          if n=1{
            content/.wrap pgfmath arg={##1}{content("!u")*\p},
            edge label/.wrap pgfmath arg={{node [my edge label, above] {##1}}}{content("!u")*\p}
          }{
            content/.wrap pgfmath arg={##1}{content("!u")*(1-\p)},
            edge label/.wrap pgfmath arg={{node [my edge label, below] {##1}}}{content("!u")*(1-\p)}
          },
        },
        delay={
          content={},
        },
      },
    }
  }
}
\begin{document}
  \begin{forest}
    my binomial=.25
    [A
      [B
        [D
          [H]
          [I]
        ]
        [E
          [J]
          [K]
        ]
      ]
      [C
        [F
          [L]
          [M]
        ]
        [G
          [N]
          [O]
        ]
      ]
    ]
  \end{forest}
\end{document}

二叉树

编辑

弄清楚了如何将其转变为合适的风格,这要归功于萨索·日瓦诺维奇

答案4

此解决方案使用matrix,不像 Malipivo 的解决方案那样自动化。所有链接都可以在某个\foreach循环内绘制,但我现在没有足够的灵感。

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{matrix,shapes}

\begin{document}
\begin{tikzpicture}[mynode/.style={draw,ellipse, minimum width=1.5cm, minimum height=.8mm}]
\matrix (A) [matrix of math nodes, nodes={mynode}, column sep=3mm, row sep=1mm]
{
&&&&S_0u\\
&&&S_0u&\\
&&S_0u&&S_0u&\\
&S_0u&&S_0u&\\
S_0&&S_0&&S_0\\
&S_0d&&S_0d&\\
&&S_0d^2&&S_0d^2\\
&&&S_0d^3&\\
&&&&S_0d^4\\
};
\draw[->] (A-5-1)--(A-4-2);
\draw[->] (A-5-1)--(A-6-2);

\draw[->] (A-4-2)--(A-3-3);
\draw[->] (A-4-2)--(A-5-3);

\draw[->] (A-3-3)--(A-2-4);
\draw[->] (A-3-3)--(A-4-4);

\draw[->] (A-2-4)--(A-1-5);
\draw[->] (A-2-4)--(A-3-5);

\draw[->] (A-6-2)--(A-5-3);
\draw[->] (A-6-2)--(A-7-3);

\draw[->] (A-5-3)--(A-4-4);
\draw[->] (A-5-3)--(A-6-4);

\draw[->] (A-4-4)--(A-3-5);
\draw[->] (A-4-4)--(A-5-5);

\draw[->] (A-7-3)--(A-6-4);
\draw[->] (A-7-3)--(A-8-4);

\draw[->] (A-6-4)--(A-5-5);
\draw[->] (A-6-4)--(A-7-5);

\draw[->] (A-8-4)--(A-7-5);
\draw[->] (A-8-4)--(A-9-5);
\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容