<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="http://www.r-bloggers.com/using-geom_step/"></div></div><div><a data-url="http://www.r-bloggers.com/using-geom_step/" data-counturl="http://www.r-bloggers.com/using-geom_step/" data-count="horizontal" data-text="Using geom_step" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.win-vector.com/blog/2016/06/using-geom_step/"> R – Win-Vector Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a target="_blank" href="http://docs.ggplot2.org/current/geom_path.html"><code>geom_step</code></a> is an interesting geom supplied by the <a target="_blank" href="https://cran.r-project.orgli/">R</a> package <a target="_blank" href="http://ggplot2.org/">ggplot2</a>. It is an appropriate rendering option for financial market data and we will show how and why to use it in this article.</p>
<p><span></span></p>
<p>Let’s take a simple example of plotting market data. In this case we are plotting the &quot;ask price&quot; (the publicly published price an item is available for purchase at a given time), the &quot;bid price&quot; (the publicly published price an item can be sold for at a given time), and &quot;trades&quot; (past purchases and sales).</p>
<p>Most markets maintain these &quot;quoted&quot; prices as an order book and the public ask price is always greater than the public bid price (else we would have a &quot;crossed market&quot;). We can also track recent transactions or trades. Here is some example (made-up) data.</p>
<div>
<pre><code><span>print</span>(quotes)</code></pre>
</div>
<pre><code>##             quoteTime       date askPrice bidPrice
## 1 2016-01-04 09:14:00 2016-01-04    10.81    10.69
## 2 2016-01-04 11:45:17 2016-01-04    11.09    10.68
## 3 2016-01-04 15:25:00 2016-01-04    12.32    12.03
## 4 2016-01-05 10:12:13 2016-01-05    14.33    13.69
## 5 2016-01-06 09:02:00 2016-01-06    17.17    16.20
## 6 2016-01-06 15:10:00 2016-01-06    18.86    18.35
## 7 2016-01-06 15:27:00 2016-01-06    20.89    20.32</code></pre>
<div>
<pre><code><span>print</span>(trades)</code></pre>
</div>
<pre><code>##             tradeTime       date tradePrice quantity
## 1 2016-01-04 09:14:00 2016-01-04      10.81      600
## 2 2016-01-04 11:45:17 2016-01-04      10.68      500
## 6 2016-01-06 15:10:00 2016-01-06      18.35      200
## 7 2016-01-06 15:27:00 2016-01-06      20.89      200</code></pre>
<p>Notice each revision of the book (notification of a bid price, ask price, or both) happens at a specific time. Ask and bid prices are good until they are revised or withdrawn.</p>
<p>There is some issue as to what is the &quot;price&quot; of a financial instrument (say in this case a stock).</p>
<p>Money only changes hands on trades- so past quotes that were never &quot;hit&quot; or traded against in some sense never happened (in fact this is becoming a problem called &quot;flashing&quot;). So market participants can somewhat manipulate bids and asks as long as they don’t cross. Asks and bids represent risk or a one-sided opinion on price but can not be trusted (especially when the &quot;bid ask gap&quot; is very large).</p>
<p>Trades cost fees and transfer money, so they are evidence of two parties agreeing on price for a moment. But all trades you know about are in the past. Just because somebody purchased some shares of IBM in the past for $120 a share doesn’t mean you can do the same. You could only make such a purchase if there is an appropriate ask price in the market (or you place your own limit order forming a bid that somebody else hits).</p>
<p>What I am trying to say is the classic &quot;ticker tape pattern&quot; graph shown below drawing only trades and connecting them with sloping lines is not appropriate for plotting markets (especially when plotting high frequency or in-day data).</p>
<div>
<pre><code><span>ggplot</span>(<span>data=</span>trades,<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice)) +<span> </span>
<span> </span><span>geom_line</span>() +<span> </span><span>geom_point</span>()</code></pre>
</div>
<div>
<img alt="" src="http://i2.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plottrades-1.png?w=660" data-recalc-dims="1">
</div>
<p>There is a lot wrong with such graphs.</p>
<ul>
<li>We have plotted only past trades, so we have no idea what <em>we</em> would have had to pay to buy stock or gotten to sell stock at any time.</li>
<li>The sloped segments &quot;leak information&quot; from the future as right after the trade the line slope tells you if the next trade in the future is going to be at a higher or lower price than the trade at hand. It is important in graphing financial instruments to have graph of where at each time in the graph we are plotting only things that are known by that time. This is also why we should not use standard smoothing curves such as <a target="_blank" href="http://docs.ggplot2.org/current/geom_smooth.html"><code>geom_smooth</code></a> as the defaults use data from the past and future to perform the smoothing (instead should use a trailing window such as exponential smoothing).</li>
</ul>
<p>(Side note: if anybody has some good code to make <code>geom_smooth</code> perform exponential smoothing in all cases, including grouping and facets I would really like a copy. Right now I have to join in smoothed data as new column as I have never completely grocked all of the implementation interface requirements for new <code>ggplot2</code> statistics in their full production complexity.)</p>
<p>If all that seems complicated, scary, unpleasant and technical: that is the right way to think. Markets are not safe, simple, or pleasant. They can be reasoned about and worked with, but it is wrong to think they are simple or easy.</p>
<p>An (unfortunately) more complicated (and slightly less legible graph) is needed to try and faithfully present the information. Since asks and bids are good until withdrawn and revised we render then with a step shape (such as generated by <code>ggplot2::geom_step</code>) and since trades happen only at a single time (and are not a promise going forward) we render them with points. Such a graph is given below.</p>
<div>
<pre><code><span>ggplot</span>() +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice))) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_y_log10</span>(<span>breaks=</span>breaks)</code></pre>
</div>
<div>
<img alt="" src="http://i1.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plotstep1-1.png?w=660" data-recalc-dims="1">
</div>
<p>The step functions propagate flat lines forward from quote revisions, correctly indicating what ask price and bid price were in effect at all times. Trades are shown as dots since they have no propagation. Each item drawn on the graph at a given time was actually know by that time (so a person or trading strategy would also have access to such information at that time).</p>
<p>Trades that occur nearer the ask price can be considered &quot;buyer initiated&quot; and trades that occur near the bid price are considered can be considered &quot;seller initiated&quot;, which we can indicate through color.</p>
<div>
<pre><code>mids &lt;-<span> </span>(<span>lastKnownValue</span>(<span>NA</span>,quotes$quoteTime,quotes$askPrice,trades$tradeTime)+
<span> </span><span>lastKnownValue</span>(<span>NA</span>,quotes$quoteTime,quotes$bidPrice,trades$tradeTime))/<span>2</span>
trades$type &lt;-<span> </span><span>ifelse</span>(trades$tradePrice>=mids,<span>'buy'</span>,<span>'sell'</span>)

<span>ggplot</span>() +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice,<span>color=</span>type))) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_y_log10</span>(<span>breaks=</span>breaks) +
<span> </span><span>scale_color_brewer</span>(<span>palette =</span> <span>'Dark2'</span>)</code></pre>
</div>
<div>
<img alt="" src="http://i2.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plotstep2-1.png?w=660" data-recalc-dims="1">
</div>
<p>This is a good time to point out a problem in these graphs. We are mostly plotting times when the market is closed. Most of the space is wasted. In the graph below we indicate (fictitious) market hours by shading the &quot;market open hours&quot; to illustrate the issue.</p>
<div>
<pre><code><span>print</span>(openClose)</code></pre>
</div>
<pre><code>##         date                time  what askPrice bidPrice
## 1 2016-01-04 2016-01-04 09:00:00  open       NA       NA
## 2 2016-01-04 2016-01-04 15:30:00 close    12.32    12.03
## 3 2016-01-05 2016-01-05 09:00:00  open    12.32    12.03
## 4 2016-01-05 2016-01-05 15:30:00 close    14.33    13.69
## 5 2016-01-06 2016-01-06 09:00:00  open    14.33    13.69
## 6 2016-01-06 2016-01-06 15:30:00 close    20.89    20.32</code></pre>
<div>
<pre><code>openClose %>%<span> </span><span>select</span>(date,time,what) %>%<span> </span><span>spread</span>(what,time) -><span> </span>marketHours

<span>ggplot</span>() +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice,<span>color=</span>type))) +
<span> </span><span>geom_rect</span>(<span>data=</span>marketHours,
            <span>mapping=</span><span>aes</span>(<span>xmin=</span>open,<span>xmax=</span>close,<span>ymin=</span><span>0</span>,<span>ymax=</span><span>Inf</span>),
            <span>fill=</span><span>'blue'</span>,<span>alpha=</span><span>0.3</span>) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_y_log10</span>(<span>breaks=</span>breaks) +
<span> </span><span>scale_color_brewer</span>(<span>palette =</span> <span>'Dark2'</span>)</code></pre>
</div>
<div>
<img alt="" src="http://i2.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plot2-1.png?w=660" data-recalc-dims="1">
</div>
<p>The easiest way to fix this in <code>ggplot2</code> would be to use <code>facet_wrap</code>, but this crashes (at least for <code>ggplot2</code> version <code>2.1.0</code> current on Cran 2016-06-03) with the very cryptic error message as shown below.</p>
<div>
<pre><code><span>ggplot</span>() +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice,<span>color=</span>type))) +
<span> </span><span>facet_wrap</span>(~date,<span>scale=</span><span>'free_x'</span>) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_color_brewer</span>(<span>palette =</span> <span>'Dark2'</span>)</code></pre>
</div>
<pre><code>## Error in grid.Call.graphics(L_lines, x$x, x$y, index, x$arrow): invalid line type</code></pre>
<div>
<img alt="" src="http://i2.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/ploterror-1.png?w=660" data-recalc-dims="1">
</div>
<p>Despite the message &quot;invalid line type&quot; the error is not the user’s selection of linetype. It is easier to see what is going on if we replace <code>geom_step</code> with <code>geom_line</code> as we show below.</p>
<div>
<pre><code><span>ggplot</span>() +<span> </span>
<span> </span><span>geom_line</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_line</span>(<span>data=</span>quotes,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice,<span>color=</span>type))) +
<span> </span><span>facet_wrap</span>(~date,<span>scale=</span><span>'free_x'</span>) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_y_log10</span>(<span>breaks=</span>breaks) +
<span> </span><span>scale_color_brewer</span>(<span>palette =</span> <span>'Dark2'</span>)</code></pre>
</div>
<pre><code>## geom_path: Each group consists of only one observation. Do you need to
## adjust the group aesthetic?
## geom_path: Each group consists of only one observation. Do you need to
## adjust the group aesthetic?</code></pre>
<div>
<img alt="" src="http://i0.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plotlineq-1.png?w=660" data-recalc-dims="1">
</div>
<p>The above graph is now using sloped lines to connect ask price and bid price revisions (given the false impression that these intermediate prices were ever available and essentially &quot;leaking information from the future&quot; into the visual presentation). However, we get a graph and a more reasonable warning message: &quot;geom_path: Each group consists of only one observation.&quot; There was only one quote revision on 2016-01-05 so as <code>facet_wrap</code> treats each facet as sub-graph (and not as a portal into a single larger graph): days with fewer than 2 quote revisions have trouble drawing paths. The trouble causes the (deceptive) blank facet for 2016-01-05 if we are using simple sloped lines (<code>geom_line</code>) and seems to error out on the more complicated <code>geom_step</code>.</p>
<p>In my opinion <code>geom_step</code> should &quot;fail a bit gentler&quot; on this example (as <code>geom_line</code> already does). In any case the correct domain specific fix is to regularize the data a bit by adding market open and close information. In many markets the open and closing prices are set by specific mechanisms (such as an opening auction and a closing volume or time weighted average). For our example we will just use last known price (which we have already prepared).</p>
<div>
<pre><code>openClose %>%<span> </span><span>mutate</span>(<span>quoteTime=</span>time) %>%<span> </span>
<span> </span><span>bind_rows</span>(quotes) %>%
<span> </span><span>arrange</span>(time) %>%<span> </span>
<span> </span><span>select</span>(date,askPrice,bidPrice,quoteTime) -><span> </span>joinedData

<span>ggplot</span>() +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>joinedData,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>askPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#1b9e77'</span>,<span>alpha=</span><span>0.5</span>) +<span> </span>
<span> </span><span>geom_step</span>(<span>data=</span>joinedData,<span>mapping=</span><span>aes</span>(<span>x=</span>quoteTime,<span>y=</span>bidPrice),
            <span>linetype=</span><span>2</span>,<span>color=</span><span>'#d95f02'</span>,<span>alpha=</span><span>0.5</span>) +
<span> </span><span>geom_point</span>(<span>data=</span>trades,<span>mapping=</span>(<span>aes</span>(<span>x=</span>tradeTime,<span>y=</span>tradePrice,<span>color=</span>type))) +
<span> </span><span>facet_wrap</span>(~date,<span>scale=</span><span>'free_x'</span>) +
<span> </span><span>ylab</span>(<span>'price'</span>) +<span> </span><span>xlab</span>(<span>'time'</span>) +<span> </span><span>scale_y_log10</span>(<span>breaks=</span>breaks) +
<span> </span><span>scale_color_brewer</span>(<span>palette =</span> <span>'Dark2'</span>)</code></pre>
</div>
<pre><code>## Warning: Removed 1 rows containing missing values (geom_path).

## Warning: Removed 1 rows containing missing values (geom_path).</code></pre>
<div>
<img alt="" src="http://i0.wp.com/www.win-vector.com/dfiles/UsingGeomStep_files/figure-markdown_github/plotfixed-1.png?w=660" data-recalc-dims="1">
</div>
<p>The above graph is pretty good. In fact easily producing a graph like this in R using <a target="_blank" href="https://github.com/rstudio/dygraphs"><code>dygraphs</code></a> is <a target="_blank" href="https://github.com/rstudio/dygraphs/issues/70">currently an open issue</a>.</p>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="http://www.r-bloggers.com/using-geom_step/"></div></div><div><a data-url="http://www.r-bloggers.com/using-geom_step/" data-counturl="http://www.r-bloggers.com/using-geom_step/" data-count="vertical" data-text="Using geom_step" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.win-vector.com/blog/2016/06/using-geom_step/"> R – Win-Vector Blog</a></strong>.</div>
<hr>
<a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="http://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="http://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="http://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="http://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="http://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="http://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="http://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="http://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="http://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="http://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="http://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="http://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="http://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="http://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="http://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="http://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/vbGXCOvC0Uc"></a></div>