对于衍生品定价课程,我想找到一种快速高效地绘制重组二叉树的方法。这门课涉及了相当多的这种树,如果能找到一种允许我半自动化该过程的方法,那将非常有帮助。
这是一个例子(请原谅分辨率低;这是我能找到的最好的例子):
我希望通过仅指定周期数(即水平级别)来实现此外观;p
从任何节点向上的概率;以及所有节点的可能值。然后概率p
和1-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}
版本 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}
答案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 = .65
、N = 4
和一个不太严肃的标签 :
binomial_tree(4, .65)("O", "I", "II", "$A$", "$B$", "$C$",
"$\alpha$", "$\beta$", "$\gamma$", "$\delta$");
这是第二个示例,带有N=6
和p=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}