6
$\begingroup$

I have a time series sampled at 5-minute frequency for a financial instrument that trades from 08:30 to 15:15 CT. No trading takes place outside those hours.

I want to plot the series with the x-axis showing the series timestamps, but without gaps or interpolation. Neither DateListPlot nor ListLinePlot appears able to accomplish this.

The timeseries looks like this:

enter image description here

On a large enough timescale a DateListPlot looks fine:

enter image description here

However, on a shorter timescale the plot shows gaps that are either filled with (meaningless) interpolated values:

enter image description here

or else are plotted with a large gaps between days:

enter image description here

ListLinePlot offers no improvement:

enter image description here

What I want, of course, is to be able to restrict the plot range to the hours of 08:30 to 15:15, i.e. to redefine a "day" or use "session hours" rather than the standard 24-hour clock times.

I have tried using TimeSeriesResample, EventSeries, TradingChart, and a bunch of other things, but so far there doesn't appear to be a way to accomplish this.

Suggestions gratefully received.

$\endgroup$
1
7
$\begingroup$

First an input dataset with a structure described in OP:

dates = Join @@ Table[DateRange[DateList[{2021, 1, i, 8, 30}], 
     DateList[{2021, 1, i, 17, 30}], Quantity[5, "Minutes"]], {i, 1, 4}];

SeedRandom[1]
data = Transpose[{dates, Accumulate[RandomReal[{-1, 3/2}, Length@dates]]}];

DateListPlot[data, ImageSize -> 600]

enter image description here

Use GroupBy to get a data set for each day:

datasets = Values[GroupBy[data, #[[1, ;; 3]] &]];

1. We can combine the separate DateListPlots for each day using Lukas Lang's ResourceFunction["PlotGrid"].

Use DateListPlot (specifying horizontal FrameTicks explicitly) for each dataset:

ClearAll[dateTicks]
dateTicks = Module[{minmax = MinMax[AbsoluteTime /@ #[[All, 1]]]}, 
    Select[First @ minmax <= #[[1]] <= Last @ minmax &]@
     System`DateListPlotDump`DateTicks[minmax, 6,
   {"YearShort", "/", "MonthShort", "/", "DayShort", " ", "Hour", ":", "Minute"}]] &;

yrange = MinMax @ data[[All, 2]];

dlps = Map[DateListPlot[#, PlotRange -> {Automatic, yrange}, 
     PlotRangePadding -> {Automatic, Scaled[.05]}, 
     FrameTicks -> {{Automatic, Automatic},
       {MapAt[Rotate[#, Pi/2] &, #, {All, 2}] & @ dateTicks @ #, 
        MapAt["" &, #, {All, 2}] & @ dateTicks @ #}}] &, datasets];

Combine the plots dlps with Lukas Lang's ResourceFunction["PlotGrid"]:

ResourceFunction["PlotGrid"][{dlps}, "MergeAxes" -> "Cut", 
 Spacings -> 10, ImageSize -> 600, AspectRatio -> 1/GoldenRatio]

enter image description here

2. Alternatively, we can use the function rowLayout from this answer:

ClearAll[rowLayout]
rowLayout[pad_: 0.02][opts : OptionsPattern[]] := 
  Module[{trFs, gridlines, xticks, 
     plts = Show[#, PlotRangePadding -> {Scaled[pad], Scaled[pad]}] & /@ #, 
     paddings = pad {-1, 1}.# & /@ (First /@ PlotRange /@ #), 
     shifts = {1., -1}.# & /@ Partition[Rest@Flatten[First /@ PlotRange /@ #], 2]}, 
    trFs = TranslationTransform[{#, 0}] & /@ 
      Accumulate[2 paddings + Prepend[shifts, 0]];
    gridlines = Most @ MapThread[#[{#2 + #3, 0}] &, {trFs, 
         PlotRange[#][[1, 2]] & /@ plts, paddings}][[All, 1]];
    xticks = Join @@ Table[MapAt[trFs[[i]][{#, 0}][[1]] &, (FrameTicks /. 
           Options[plts[[i]], FrameTicks])[[2, 1]], {All, 1}], {i,  Length@plts}];
    Graphics[MapThread[GeometricTransformation[#[[1]], #2] &, {plts, trFs}], 
     FrameTicks -> {{Automatic, All}, {xticks, MapAt["" &, xticks, {All, 2}]}}, opts, 
     GridLines -> {gridlines, None}, Frame -> True, 
     AspectRatio -> 1/3/GoldenRatio, ImageSize -> 800]] &;

rowLayout[][ImageSize -> 600, AspectRatio -> 1/GoldenRatio] @ dlps

enter image description here

3. We can use TimeSeriesShift to shift the dates for each series in dataset and to construct custom date ticks:

gap = DateDifference[datasets[[1, -1, 1]], datasets[[2, 1, 1]], 
    "Minutes"] - Quantity[60, "Minutes"];

shiftedseries = Table[TimeSeriesShift[datasets[[i]], -(i - 1) gap], {i, 1, 4}];

ticks = TimeSeries[dateTicks @ #] & /@ datasets;

dticks = MapAt[Rotate[#, Pi/2] &, #, {All, 2}] &[
  Join @@ Table[TimeSeriesShift[ticks[[i]], -(i - 1) gap]["Path"], {i, 1, 4}]];

DateListPlot[shiftedseries, FrameTicks -> {{Automatic, Automatic}, {dticks, Automatic}}]

enter image description here

$\endgroup$
4
  • $\begingroup$ Note: all three methods work in version 11.3.0 (windows 10-64b). $\endgroup$
    – kglr
    May 7 at 12:27
  • $\begingroup$ Three great solutions! $\endgroup$ May 8 at 9:03
  • $\begingroup$ @kglr nice, +1 ! Are you on Community? It'd be great to add your answer HERE $\endgroup$ May 10 at 22:35
  • 1
    $\begingroup$ Thank you @VitaliyKaurov. I am not on Community. Jonathan already added the answer to his post there. $\endgroup$
    – kglr
    May 11 at 4:47

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.