8

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}
JeT
  • 3,020
  • 1
    Before digging deeply into this: you got already [this nice solution] (https://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? –  May 03 '20 at 01:45
  • @Schrödinger'scat I did not think of pgf TBH. I thought straight away of a tikz solution with chain. – JeT May 03 '20 at 02: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. –  May 03 '20 at 03: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 03 '20 at 12:03
  • @BambOo You're right. I used the wrong tag. I update that. – JeT May 03 '20 at 12:04

1 Answers1

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

BambOo
  • 8,801
  • 2
  • 20
  • 47
  • 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 03 '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 03 '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 03 '20 at 19:05
  • What does account3 stand for ? i don't see where the input is used. – JeT May 03 '20 at 19:12
  • It's useless here, a remainder or the datafile I used as a starting point – BambOo May 03 '20 at 19:13
  • ah right :) After interesting 30 mins of testing... what a fantastic and flexible answer... Really. – JeT May 03 '20 at 19:14
  • 1- When i reverse the flows as here \begin{filecontents*}[overwrite]{test.dat} date fixed floating account3 2020-01-01 -15 5 200 2020-01-01 0 5 200 2021-02-01 -5 5 410 2022-03-01 0 6 410 2023-04-01 -5 1 410 2024-05-01 0 1 410 2025-06-01 -5 3 410 2026-07-01 0 4.5 400 2027-08-01 -5 1.0 410 2028-09-01 0 1.5 410 2029-10-01 -5 4.0 410 2032-10-01 15 4.0 410 \end{filecontents*} the labels are off. (question of above and below) – JeT May 03 '20 at 19:20
  • @Julien-ElieTaieb, if you could precise the expected behavior for different cases, I could provide more styling options. But basically you could reproduce what I do with the opacity test : define an option based on the value of point meta. – BambOo May 03 '20 at 20:05
  • time for me to write something sure! – JeT May 03 '20 at 20:06
  • Floating and spread always go together (in the business you never talk about fixed + spread since it comes back to just... fixed...). As a result, when floating is upward, spread is necessarily upward too and the label placement should be adjusted from \draw[gray,-stealth,thick] (tempnode) --++ (0pt,-20pt) node[at end,below,font=\itshape] {\SpreadLabel}; to \draw[gray,-stealth,thick] (tempnode) --++ (0pt,-20pt) node[at end,**above**,font=\itshape] {\SpreadLabel} whether it's upward or not. Same question of label positionning for fixed coupon. – JeT May 03 '20 at 20:41
  • Where shall I send you snapshots ? I think spreads values should come from a "spread" column in your file. If not, the case of a singular fixed flow generates a spread like here : \begin{filecontents*}[overwrite]{test.dat} date fixed floating 2019-12-28 12 0 %Fixed upfront received 2020-02-01 7 -5 2020-03-01 0 -6 2020-04-01 5 -1 2020-05-01 0 -4 2020-06-01 7 -3 2020-07-01 0 -4.5 2020-08-01 6 -1 2020-09-01 0 -1.5 2020-10-01 5 -11 % Floating final payment paid \end{filecontents*} – JeT May 03 '20 at 20:59
  • With this spread column your code handles 90% of cases !!!! \begin{filecontents*}[overwrite]{test.dat} date fixed floating spread 2019-12-28 12 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 -11 0 % Floating final payment paid \end{filecontents*} – JeT May 03 '20 at 21:01
  • I think we can paramater few things \newif\ifShowSpread % Display Spread or not \ShowSpreadtrue % Display or not the gray arrow \def\Couleur{orange} % Color \def\FixLabel{C} % Label for fixed \def\FloatingLabel{V} % Label for Floating \def\SpreadLabel{$+50$bps} % Label for Spread

    Resulting in `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`

    – JeT May 03 '20 at 21:06
  • @Julien-ElieTaieb You should edit your question to provide the additional information, it will be much easier to manipulate the code, for the both of us – BambOo May 03 '20 at 21:08
  • Merci encore ! Great code, extremely easy to use, students loved it. – JeT Jan 14 '21 at 19:41