6

The following type of graph (MWE below) describes the stream of flows received and paid over 10 dates.

enter image description here

Problematic

In economics/finance we frequently need "cash flow diagram" CashFlowDiagram that describe what is received and what is paid over time, whether what is paid is certain, random or conditional, at what frequency.

I need a better solution (chain ?)

I had a valid solution until... I needed more flexibility. As you can see in MWE i have a laborious definition of each date then each node for fix arrows and floating arrows. Already boring to tell :) Also, I hardcoded the fact that if arrows up are fix then arrows down are floating and vice versa. Whereas today i'd like to choose if arrow up/down are floating/fix.

Recipe

All these graphs require

  • dates
  • Flows above vs flow below timeline
  • arrows going up and down from these dates
  • frequency of the up flows and the down flows
  • styles to describe the arrows (type of flows)

It's customary in the field to have

  • "fix" payments are fixed straight arrows. Up when they are received , down when they are paid.
  • "floating" payments (variable, based on rand) payments could use snake arrows. Again, up when they are received, down they are paid.
  • we can define other things like conditionality of the flow with dotted style arrows.

I have to confess most of the time, generic tools provide a poor visual and obviously lack the potentiality of TikZ to provide appealing self explanatory graph.

enter image description here enter image description here

and previous posts (drawing-cash-flows and here draw-cash-flow-diagram) do not answer my present question.

MWE

\documentclass{standalone}
%----------------Tikz libraries -------------------------
\usetikzlibrary{
    arrows,
    arrows.meta,
    decorations,
    decorations.shapes,
    decorations.pathmorphing,
    decorations.text,
}

\def\M{10}      %Number od dates
\def\Couleur{blue}
\def\SigTF{1}   %+1 Arrow up, i receive the fix flow, -1 Arrow down, i pay the fix flow
\def\TF{2}      % amount of the flow in 
\def\SigTV{-1}  %%+1 Arrow up, i receive the variable flow, -1 Arrow down, i pay the variable flow
\def\TV{3}      % amount of the variable in 
\def\SpreadTV{1} % +1 Arrow up, on top of the floating arrow
\def\TSpread{3}     % sze of the arrow  
\def\SigUF{0}       % Payment on Start Date
\def\UF{0}          % Amount
\def\SigLastF{0}    % Payment on Last Date
\def\LastF{0}       % Amout


\begin{document}

\pgfmathsetseed{1}

\begin{tikzpicture}                     
    \tikzset{
    InitialPoint/.style={circle,draw=red!40,fill=red!40,minimum size=40},
    D0/.style={draw=red!40,fill=red!40,circle,minimum size=10},
    N_date/.style={circle,draw=blue!50,minimum size=20,draw=\Couleur,},
    N_TF/.style={circle,minimum size=20},
    N_TV/.style={circle,minimum size=0},
    fleche/.style={>=latex,very thick},
    flecheTV/.style={->,ultra thick, decorate,decoration={snake, amplitude=1mm,segment length=3mm,  pre length=3mm, post length=3mm}, color=\Couleur!50!white},
    flecheTF/.style={fleche, color=\Couleur!50!white},      
    flecheSpread/.style={>=latex,very thick,gray},
    flecheUF/.style={fleche,->,ultra thick,decorate,decoration={zigzag, amplitude=1mm,segment length=15mm,  pre length= 30mm, post length=30mm},\Couleur},
    }                           


%------------- Starting poinr ---------------
    \node [D0]  (D0) at (0,0) {Start};
%-------------    Upfront   payment   ---------------
    \ifnum\numexpr\UF=0\relax
    \else
        \node [N_TF]    (UF)    at (0,\SigUF*\UF)   {UpFront};
        \draw [flecheUF] (D0) -- (UF);
    \fi                             
%-------------    Last payment      ---------------
    \ifnum\numexpr\LastF=0\relax
    \else
        \node [N_TF]    (LastF)     at (1+1.5*\M,\SigLastF*\LastF)  {Reimbursment};
        \draw [flecheUF] (D\M) -- (LastF);
    \fi                             
%------------- Nodes for dates ---------------
    \foreach \x in {1,...,\M}{
        \pgfmathtruncatemacro{\prev}{\x - 1}  
        \node [N_date] (D\x) at (1+1.5*\x,0) {\scriptsize{$t_{\x}$}};
        \draw[opacity=0.5] (D\prev) -- (D\x);   
    }

%------------- Nodes for variables flows---------------
    \foreach \x in {1,...,\M}{          
        \pgfmathtruncatemacro{\prev}{\x - 1}  
        \pgfmathsetmacro{\TVnew}{\SigTV*\TV*rnd}%
        \ifnum\numexpr\TV>0\relax
            \node [N_TV] (TV\x) at (1+1.5*\x,\SigTV*1.5+\TVnew) {\normalsize {$TV_{\x}$}};
            \draw [flecheTV] (D\x) -- (TV\x);
        \fi
        \ifnum\numexpr\TV=0\relax
        \else
            \ifnum\numexpr\SpreadTV=0\relax
            \else
                \node [N_TV,gray] (spread\x) at (1+1.5*\x,\SigTV*1.5+\TVnew+\SigTV*2) 
                {\normalsize{$spread$}};
                %\SpreadTV) {\normalsize{$spread$}};
                \draw [->,ultra thick,gray!50] (TV\x)--(spread\x);
            \fi
        \fi         
    }

%------------- Fix payment flows ---------------
    \foreach \x in {2,4,...,\M}{
        \pgfmathtruncatemacro{\z}{0.5*\x}             
        \ifnum\numexpr\TF=0\relax
        \else
            \node[N_TF]     (TF\x)  at (1+1.5*\x,\SigTF*\TF) {\normalsize{$TF_{\z}$}};
            \draw [->,very thick, blue!80] (D\x) -- (TF\x);
        \fi
    }               



\end{tikzpicture}                                                                               

\end{document}  

Edit Following @BambOo's really flexible and efficient answer, some parameters on labels, \newif to diplay or not spread, updated table (spread column not functional yet) that handle single first of final flow (without spread).

enter image description here

\documentclass[tikz,margin=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathmorphing,decorations.markings,arrows.meta}
\usepgfplotslibrary{dateplot}
\pgfmathsetseed{2}

\newif\ifShowSpread     % Display Spread or not
\ShowSpreadtrue         % Display or not the gray arrow
\def\Couleur{orange}    % Parameter the color
\def\FixLabel{C}        % Label for fixed
\def\FloatingLabel{V}   % Label for Floating
\def\SpreadLabel{$+50$bps} % Label for Spread


\tikzset{
    fixedarrow/.style={
    -stealth, color=\Couleur,  thick, solid,
  },
  floatingarrow/.style={
    -stealth, color=\Couleur!50, thick, solid, decorate,
    decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,
                post length=1mm},
  },
  Conditonarrow/.style={
    -stealth, color=\Couleur!50, ultra thick, densely dotted, decorate,
    decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,
                post length=1mm},
  },
}

\pgfplotsset{
    fixed/.style={
        point meta=\thisrow{fixed},
        quiver={u=0, v=\thisrow{fixed},every arrow/.append style={fixedarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \node[anchor=south,opacity=\opa] at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$\FixLabel_{\newindex}$};
            \pgfkeys{/pgf/fpu=false}
            }}},
    floating/.style={
        point meta=\thisrow{floating},
        quiver={u=0, 
                v=\thisrow{floating},
                every arrow/.append style={Conditonarrow}, %% sould not it be {floatingarrow}, ?
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfkeys{/pgf/fpu=false}
            \node[anchor=north,opacity=\opa] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$\FloatingLabel_{\newindex}$};

    \ifShowSpread            
\draw[gray,-stealth,thick] (tempnode) --++ (0pt,-20pt) node[at end,below,font=\itshape] {\SpreadLabel}; 
    \fi
            }}},
    fixedConditional/.style={fixed,densely dotted},
    floatingConditional/.style={floating,densely dotted},
}

%% for testing
%Table ReceiveFixPayFloating where I receive fix....
\begin{filecontents*}[overwrite]{ReceiveFixPayFloating.dat}
date        fixed    floating  spread
2019-12-28  5       0        0  %Fixed upfront received, no floating but no spread    
2020-02-01  7       -5      0.5
2020-03-01  0       -6      0.5
2020-04-01  5       -1      0.5
2020-05-01  0       -4      0.5
2020-06-01  7       -3      0.5
2020-07-01  0      -4.5     0.5
2020-08-01  6       -1      0.5
2020-09-01  0       -1.     0.5
2020-10-01  0       -5       0   % Floating final payment paid
\end{filecontents*}

%Table ReceiveFloatingPayFix where I receive floating....
\begin{filecontents*}[overwrite]{ReceiveFloatingPayFix.dat}
date        fixed    floating  spread
2019-12-28  -5       0       0  %Fixed upfront received, no floating but no spread    
2020-02-01  -7       5      0.5
2020-03-01  -0       6      0.5
2020-04-01  -5       1      0.5
2020-05-01  -0       4      0.5
2020-06-01  -7       3      0.5
2020-07-01  -0      4.5     0.5
2020-08-01  -6       1      0.5
2020-09-01  -0       1.     0.5
2020-10-01  -0       5       0   % Floating final payment paid
\end{filecontents*}


\begin{document}

\begin{tikzpicture}
    \begin{axis}[
            width=15cm,
            height=5cm,
            axis y line=none,
            axis x line*=center,
            date coordinates in=x,
            tick align=inside,
            xtick=data,
            xticklabel={$d_{\pgfmathprintnumber[/pgf/number format/fixed]{\month}}$},
            xticklabel style={anchor=center,outer sep=0pt, inner sep=0pt,circle,draw=\Couleur,fill=\Couleur!20,thick,text width=1.5em,align=center},
            axis on top=true,
            clip=false,
        ]

%% All good here
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFixPayFloating.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};

%% Pb of above/below labels 
%       \addplot[fixed] table [x=date,y expr=0]     {ReceiveFloatingPayFix.dat};
%       \addplot[floating] table [x=date,y expr=0]  {ReceiveFloatingPayFix.dat};

%% I created 
%    fixedConditional/.style={fixed,densely dotted},
%    floatingConditional/.style={floating,densely dotted},
% but they don't seem to apply. 
%
    \addplot[fixedConditional] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
    \addplot[floatingConditional] table [x=date,y expr=0]   {ReceiveFixPayFloating.dat};


%       \node[circle,fill=red!50,xshift=-2cm] at (2020-01-01,0) {Start};
    \end{axis}
\end{tikzpicture}
\end{document}
5
  • 1
    Before digging deeply into this: you got already [this nice solution] (tex.stackexchange.com/a/540635/194703), which you accepted, and another nice answer under the same thread. I think one can simplify the first of these posts by using ycomb, and get the first output (maybe with some more scatter plots). Now I am wondering why you switched back to plain TikZ. This seems to indicate that you do not want a pgfplots solution. Is that so?
    – user194703
    May 3 '20 at 1:45
  • @Schrödinger'scat I did not think of pgf TBH. I thought straight away of a tikz solution with chain.
    – JeT
    May 3 '20 at 2:58
  • Please remove ` \input{../../JeTstyles/TikZManagement}` and load decorations.pathmorphing. I fail to understand what the precise input is, and how it should be used in the graph.
    – user194703
    May 3 '20 at 3:50
  • When you put your question this way, it seems to be a job for pgfplots and ybar stacked plots, with data coming from a table...
    – BambOo
    May 3 '20 at 12:03
  • @BambOo You're right. I used the wrong tag. I update that.
    – JeT
    May 3 '20 at 12:04
4

Here is my proposal (took me the whole afternoon to figure it out), hope this helps.

Based on frougon's proposal to your previous question to use quiver plots to obtain the decorated arrows, I added some code to show the extra labels.

The code takes a data file as argument for the plots, so it should be easier to use than the pure TikZ script above.

There is surely some room for improvement, as I myself had a lot of trouble making this work.

\documentclass[tikz,margin=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\usetikzlibrary{decorations.pathmorphing,decorations.markings,arrows.meta}
\usepgfplotslibrary{dateplot}

\tikzset{
    fixedarrow/.style={
    -stealth, color=blue,  thick, solid,
  },
  floatingarrow/.style={
    -stealth, color=blue!50, thick, solid, decorate,
    decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,
                post length=1mm},
  },
}

\pgfplotsset{
    fixed/.style={
        point meta=\thisrow{fixed},
        quiver={u=0, v=\thisrow{fixed},every arrow/.append style={fixedarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \node[anchor=south,opacity=\opa] at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$TF_{\newindex}$};
            \pgfkeys{/pgf/fpu=false}
            }}},
    floating/.style={
        point meta=\thisrow{floating},
        quiver={u=0, v=\thisrow{floating},every arrow/.append style={floatingarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfkeys{/pgf/fpu=false}
            \node[anchor=north,opacity=\opa] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$TV_{\newindex}$};
            \draw[gray,-stealth,thick] (tempnode) --++ (0pt,-20pt) node[at end,below,font=\itshape] {spread};
            }}},
    conditional/.style={fixed,densely dashed}, %base on fixed style
}

\begin{filecontents*}[overwrite]{test.dat}
date        fixed   floating 
2020-01-01  0       -50 
2020-02-01  10      -5   
2020-03-01  0       -60  
2020-04-01  10      -10   
2020-05-01  0       -40     
2020-06-01  10      -30   
2020-07-01  0       -45   
2020-08-01  10      -10   
2020-09-01  0       -15     
2020-10-01  10      -40      
\end{filecontents*}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[
            width=15cm,
            height=10cm,
            axis y line=none,
            axis x line*=center,
            date coordinates in=x,
            tick align=inside,
            xtick=data,
            xticklabel={$t_{\pgfmathprintnumber[/pgf/number format/fixed]{\month}}$},
            xticklabel style={anchor=center,outer sep=0pt, inner sep=0pt,circle,draw=blue,thick,fill=white,text width=1.5em,align=center},
            axis on top=true,
            clip=false,
        ]
        \addplot[fixed] table [x=date,y expr=0] {test.dat};
        \addplot[floating] table [x=date,y expr=0] {test.dat};
        \node[circle,fill=red!50,xshift=-2cm] at (2020-01-01,0) {Start};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

UPDATE

  1. Correction of the north/south anchors based on the value of point meta.
  2. Correct application of the arrow styles for conditional arrows
  3. Handling of spread arrows using an additional quiver plot starting from the minimal value of columns fixed/floating and ending at -spread*scale the scale factor is provided to make the gray arrow long enough to be meaningful (otherwise these of far too short to be readable).
\documentclass[tikz,margin=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathmorphing}
\usepgfplotslibrary{dateplot}
\pgfmathsetseed{2}

\newif\ifShowSpread     % Display Spread or not
\ShowSpreadtrue         % Display or not the gray arrow
\def\Couleur{orange}    % Parameter the color
\def\FixLabel{C}        % Label for fixed
\def\FloatingLabel{V}   % Label for Floating
\def\SpreadLabel{$+50$bps} % Label for Spread
\def\SpreadScale{10}


\tikzset{
    fixedarrow/.style={-stealth, color=\Couleur,  thick},
    floatingarrow/.style={-stealth, color=\Couleur!50, thick, decorate,decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,post length=1mm}},
    spreadarrow/.style={-stealth, color=gray,  thick},
}

\pgfplotsset{
    fixed/.style={
        point meta={\thisrow{fixed}},
        quiver={u=0, v={\thisrow{fixed}},every arrow/.style={fixedarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathsetmacro{\anc}{ifthenelse(\pgfkeysvalueof{/data point/meta}>=0,-90,90)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfkeys{/pgf/fpu=false}
            \node[anchor=\anc,opacity=\opa] at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$\FixLabel_{\newindex}$};
            }}},
    floating/.style={
        point meta=\thisrow{floating},
        quiver={u=0,v=\thisrow{floating},every arrow/.style={floatingarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathsetmacro{\anc}{ifthenelse(\pgfkeysvalueof{/data point/meta}>=0,-90,90)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfkeys{/pgf/fpu=false}
            \node[anchor=\anc,opacity=\opa] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\pgfkeysvalueof{/data point/meta}) {$\FloatingLabel_{\newindex}$};
            }}},
        spread/.style={
        point meta={-\SpreadScale*\thisrow{spread}},
        quiver={u=0,v={-\SpreadScale*\thisrow{spread}},every arrow/.style={spreadarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathsetmacro{\opa}{ifthenelse(\pgfkeysvalueof{/data point/meta}==0,0,1)}
            \pgfmathsetmacro{\anc}{ifthenelse(\pgfkeysvalueof{/data point/meta}>=0,-90,90)}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\spreadend}{\pgfkeysvalueof{/data point/y}+\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[anchor=\anc,gray,opacity=\opa] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\spreadend) {\SpreadLabel};
            }}},
    fixedConditional/.style={fixed,densely dotted},
    floatingConditional/.style={floating,densely dotted},
    spreadConditional/.style={spread,densely dotted},
    customaxis/.style={
        width=15cm,
            height=5cm,
            axis y line=none,
            axis x line*=center,
            date coordinates in=x,
            tick align=inside,
            xtick=data,
            xticklabel={$d_{\pgfmathprintnumber[/pgf/number format/fixed]{\month}}$},
            xticklabel style={anchor=center,outer sep=0pt, inner sep=0pt,circle,draw=\Couleur,fill=\Couleur!20,thick,text width=1.5em,align=center},
            axis on top=true,
            clip=false,
    }
}

%% for testing
%Table ReceiveFixPayFloating where I receive fix....
\begin{filecontents*}[overwrite]{ReceiveFixPayFloating.dat}
date        fixed    floating  spread
2019-12-28  5       0       0  %Fixed upfront received, no floating but no spread    
2020-02-01  7       -5      0.5
2020-03-01  0       -6      0.5
2020-04-01  5       -1      0.5
2020-05-01  0       -4      0.5
2020-06-01  7       -3      0.5
2020-07-01  0      -4.5     0.5
2020-08-01  6       -1      0.5
2020-09-01  0       -1.     0.5
2020-10-01  0       -5      0   % Floating final payment paid
\end{filecontents*}

%Table ReceiveFloatingPayFix where I receive floating....
\begin{filecontents*}[overwrite]{ReceiveFloatingPayFix.dat}
date        fixed    floating  spread
2019-12-28  -5       0      0  %Fixed upfront received, no floating but no spread    
2020-02-01  -7       5      0.5
2020-03-01  -0       6      0.5
2020-04-01  -5       1      0.5
2020-05-01  -0       4      0.5
2020-06-01  -7       3      0.5
2020-07-01  -0      4.5     0.5
2020-08-01  -6       1      0.5
2020-09-01  -0       1.     0.5
2020-10-01  -0       5      0   % Floating final payment paid
\end{filecontents*}


\begin{document}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFixPayFloating.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[spread] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})}]  {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFloatingPayFix.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFloatingPayFix.dat};
        \addplot[spread] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})}]  {ReceiveFloatingPayFix.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixedConditional] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[floatingConditional] table [x=date,y expr=0]   {ReceiveFixPayFloating.dat};
        \addplot[spreadConditional] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})}]   {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

enter image description here

enter image description here

UPDATE n°2 Last styling tweaks

\documentclass[tikz,margin=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathmorphing}
\usepgfplotslibrary{dateplot}
\pgfmathsetseed{2}

\newif\ifShowSpread     % Display Spread or not
\ShowSpreadtrue         % Display or not the gray arrow
\def\Couleur{orange}    % Parameter the color
\def\FixLabel{C}        % Label for fixed
\def\FloatingLabel{V}   % Label for Floating
\def\SpreadLabel{$+50$bps} % Label for Spread
\def\SpreadScale{4}


\tikzset{
    fixedarrow/.style={-stealth, color=\Couleur,  thick},
    floatingarrow/.style={-stealth, color=\Couleur!50, thick, decorate,decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,post length=1mm}},
    spreadarrow/.style={-stealth, color=gray,  thick},
    labelnode/.style={fill opacity=0.5,text opacity=1,draw opacity=1,fill=#1,draw=none,text=black,inner sep=1pt, outer sep=0pt,font=\small}
}

\pgfplotsset{
    fixed/.style={
        %y filter/.expression={\thisrow{fixed}==0 ? nan : y},
        point meta={\thisrow{fixed}},
        quiver={u=0, v={\thisrow{fixed}},every arrow/.style={fixedarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\fixedend}{0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={\Couleur}] at (axis cs:\pgfkeysvalueof{/data point/x},\fixedend) {$\FixLabel_{\newindex}$};
            }
        }},
    floating/.style={
        y filter/.expression={\thisrow{floating}==0 ? nan : y},
        point meta=\thisrow{floating},
        quiver={u=0,v=\thisrow{floating},every arrow/.style={floatingarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\floatingend}{0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={\Couleur!50}] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\floatingend) {$\FloatingLabel_{\newindex}$};
            }
        }},
        spread/.style={
        y filter/.expression={\thisrow{spread}==0 ? nan : y},
        point meta={-\SpreadScale*\thisrow{spread}},
        quiver={u=0,v={-\SpreadScale*\thisrow{spread}},every arrow/.style={spreadarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\spreadend}{\pgfkeysvalueof{/data point/y}+0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={gray}] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\spreadend) {\SpreadLabel};
            }
        }},
    fixedConditional/.style={fixed,densely dotted},
    floatingConditional/.style={floating,densely dotted},
    spreadConditional/.style={spread,densely dotted},
    customaxis/.style={
            width=15cm,
            height=10cm,
            axis y line*=box,
            axis x line*=center,
            date coordinates in=x,
            tick align=inside,
            xtick=data,
            enlargelimits = true,
            xticklabel={$d_{\pgfmathprintnumber[/pgf/number format/fixed]{\month}}$},
            xticklabel style={anchor=center,outer sep=0pt, inner sep=0pt,circle,draw=\Couleur,fill=\Couleur!20,thick,text width=1.5em,align=center},
            axis on top=true,
            clip=false,
    }
}

%% for testing
%Table ReceiveFixPayFloating where I receive fix....
\begin{filecontents*}[overwrite]{ReceiveFixPayFloating.dat}
date        fixed    floating  spread
2019-12-28  5       0       0  %Fixed upfront received, no floating but no spread    
2020-02-01  7       -5      0.5
2020-03-01  0       -6      0.5
2020-04-01  5       -1      0.5
2020-05-01  0       -4      0.5
2020-06-01  7       -3      0.5
2020-07-01  0      -4.5     0.5
2020-08-01  6       -1      0.5
2020-09-01  0       -1.     0.5
2020-10-01  0       -5      0   % Floating final payment paid
\end{filecontents*}

%Table ReceiveFloatingPayFix where I receive floating....
\begin{filecontents*}[overwrite]{ReceiveFloatingPayFix.dat}
date        fixed    floating  spread
2019-12-28  -5       0      0  %Fixed upfront received, no floating but no spread    
2020-02-01  -7       5      0.5
2020-03-01  -0       6      0.5
2020-04-01  -5       1      0.5
2020-05-01  -0       4      0.5
2020-06-01  -7       3      0.5
2020-07-01  -0      4.5     0.5
2020-08-01  -6       1      0.5
2020-09-01  -0       1.     0.5
2020-10-01  -0       5      0   % Floating final payment paid
\end{filecontents*}


\begin{document}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFixPayFloating.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[spread] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})*ifthenelse(\thisrow{spread}==0,nan,1)}]  {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFloatingPayFix.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFloatingPayFix.dat};
        \addplot[spread] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})}]  {ReceiveFloatingPayFix.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixedConditional] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[floatingConditional] table [x=date,y expr=0]   {ReceiveFixPayFloating.dat};
        \addplot[spreadConditional] table [x=date,y expr={min(\thisrow{floating},\thisrow{fixed})}]   {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\end{document}

EDIT n°3 : correction of the spread arrows.

\documentclass[tikz,margin=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathmorphing}
\usepgfplotslibrary{dateplot}
\pgfmathsetseed{2}

\newif\ifShowSpread     % Display Spread or not
\ShowSpreadtrue         % Display or not the gray arrow
\def\Couleur{orange}    % Parameter the color
\def\FixLabel{C}        % Label for fixed
\def\FloatingLabel{V}   % Label for Floating
\def\SpreadLabel{$+50$bps} % Label for Spread
\def\SpreadScale{4}


\tikzset{
    fixedarrow/.style={-stealth, color=\Couleur,  thick},
    floatingarrow/.style={-stealth, color=\Couleur!50, thick, decorate,decoration={snake, amplitude=1mm, segment length=3mm, pre length=1mm,post length=1mm}},
    spreadarrow/.style={-stealth, color=gray,  thick},
    labelnode/.style={fill opacity=0.5,text opacity=1,draw opacity=1,fill=#1,draw=none,text=black,inner sep=1pt, outer sep=0pt,font=\small}
}

\pgfplotsset{
    fixed/.style={
        %y filter/.expression={\thisrow{fixed}==0 ? nan : y},
        point meta={\thisrow{fixed}},
        quiver={u=0, v={\thisrow{fixed}},every arrow/.style={fixedarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\fixedend}{0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={\Couleur}] at (axis cs:\pgfkeysvalueof{/data point/x},\fixedend) {$\FixLabel_{\newindex}$};
            }
        }},
    floating/.style={
        y filter/.expression={\thisrow{floating}==0 ? nan : y},
        point meta=\thisrow{floating},
        quiver={u=0,v=\thisrow{floating},every arrow/.style={floatingarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\floatingend}{0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={\Couleur!50}] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\floatingend) {$\FloatingLabel_{\newindex}$};
            }
        }},
        spread/.style={
        y filter/.expression={\thisrow{spread}==0 ? nan : y},
        point meta={-\SpreadScale*\thisrow{spread}},
        quiver={u=0,v={-\SpreadScale*\thisrow{spread}},every arrow/.style={spreadarrow},
        after arrow/.code={
            \pgfplotspointgetcoordinates
            \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
            \pgfmathtruncatemacro{\newindex}{\coordindex+1}
            \pgfmathsetmacro{\spreadend}{\pgfkeysvalueof{/data point/y}+0.5*\pgfkeysvalueof{/data point/meta}}
            \pgfkeys{/pgf/fpu=false}
            \node[labelnode={gray}] (tempnode) at (axis cs:\pgfkeysvalueof{/data point/x},\spreadend) {\SpreadLabel};
            }
        }},
    fixedConditional/.style={fixed,densely dotted},
    floatingConditional/.style={floating,densely dotted},
    spreadConditional/.style={spread,densely dotted},
    customaxis/.style={
            width=15cm,
            height=10cm,
            axis y line*=box,
            axis x line*=center,
            date coordinates in=x,
            tick align=inside,
            xtick=data,
            enlargelimits = true,
            xticklabel={$d_{\pgfmathprintnumber[/pgf/number format/fixed]{\month}}$},
            xticklabel style={anchor=center,outer sep=0pt, inner sep=0pt,circle,draw=\Couleur,fill=\Couleur!20,thick,text width=1.5em,align=center},
            axis on top=true,
            clip=false,
    }
}

%% for testing
%Table ReceiveFixPayFloating where I receive fix....
\begin{filecontents*}[overwrite]{ReceiveFixPayFloating.dat}
date        fixed    floating  spread
2019-12-28  5       0       0  %Fixed upfront received, no floating but no spread    
2020-02-01  7       -5      0.5
2020-03-01  0       -6      0.5
2020-04-01  5       -1      0.5
2020-05-01  0       -4      0.5
2020-06-01  7       -3      0.5
2020-07-01  0      -4.5     0.5
2020-08-01  6       -1      0.5
2020-09-01  0       -1.     0.5
2020-10-01  0       -5      0   % Floating final payment paid
\end{filecontents*}

%Table ReceiveFloatingPayFix where I receive floating....
\begin{filecontents*}[overwrite]{ReceiveFloatingPayFix.dat}
date        fixed    floating  spread
2019-12-28  -5       0      0  %Fixed upfront received, no floating but no spread    
2020-02-01  -7       5      -0.5
2020-03-01  -0       6      -0.5
2020-04-01  -5       1      -0.5
2020-05-01  -0       4      -0.5
2020-06-01  -7       3      -0.5
2020-07-01  -0      4.5     -0.5
2020-08-01  -6       1      -0.5
2020-09-01  -0       1.     -0.5
2020-10-01  -0       5      0   % Floating final payment paid
\end{filecontents*}


\begin{document}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFixPayFloating.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[spread] table [x=date,y expr={\thisrow{floating}*ifthenelse(\thisrow{spread}==0,nan,1)}]  {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixed] table [x=date,y expr=0]     {ReceiveFloatingPayFix.dat};
        \addplot[floating] table [x=date,y expr=0]  {ReceiveFloatingPayFix.dat};
        \addplot[spread] table [x=date,y expr={\thisrow{floating}*ifthenelse(\thisrow{spread}==0,nan,1)}]  {ReceiveFloatingPayFix.dat};
    \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[customaxis]
        \addplot[fixedConditional] table [x=date,y expr=0]  {ReceiveFixPayFloating.dat};
        \addplot[floatingConditional] table [x=date,y expr=0]   {ReceiveFixPayFloating.dat};
        \addplot[spreadConditional] table [x=date,y expr={\thisrow{floating}*ifthenelse(\thisrow{spread}==0,nan,1)}]   {ReceiveFixPayFloating.dat};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

enter image description here

enter image description here

16
  • This is awesome ! I think your answer provides extreme flexibility, in so many ways ! Based on what I've just tried, we can play with the dates, provide exact stream of flows over time, exact stream of dates. With the use of filecontents/table, I actually imagine running the exact pricing of swap on one side and have a very accurate representation of the flows. More comments to come.
    – JeT
    May 3 '20 at 18:43
  • On top of previous, your system of dates enables to handle any singular flow (like an Upfront payment the 1st day or a final payment) autaomatically. If one flow is to be too big vs the rest, automatic rescale making the graph extremely readible. (not done yet :)
    – JeT
    May 3 '20 at 18:50
  • Comments part 3 : the fact we can input the dates solves the problem of discrepancy between floating flows that can be received on monthly, quaterly or any frequency basis vs fix flows that have another timepace.
    – JeT
    May 3 '20 at 19:05
  • What does account3 stand for ? i don't see where the input is used.
    – JeT
    May 3 '20 at 19:12
  • It's useless here, a remainder or the datafile I used as a starting point
    – BambOo
    May 3 '20 at 19:13

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.