12
$\begingroup$

Since this question was not answered, I would like to ask again with some additional information. I have a trading chart saved as chart1 as follows.

ohlcv = FinancialData["SPY","OHLCV", {DatePlus[Today, -300], Yesterday}];
chart1 = TradingChart[ohlcv, {"Volume", "BollingerBands"}];

I have created the following indicator (myindts).

myind = Accumulate /@ SplitBy[Differences[
      Log[QuantityMagnitude[ohlcv["Values"][[All, 4]]]]], Sign] //Flatten;
myindts = TimeSeries[myind, {Most[ohlcv["Dates"]]}];
chart2 = DateListPlot[myindts];

I want to plot my indicator below the main trading chart. How can I achieve it? Show, Overlay, GraphicsGrid etc would not be appropriate. Just for illustration,

{chart1, chart2} 

would give the following output.

enter image description here

But, I would like to produce my graph with the same x-axis in the middle, the trading chart above the x-axis, and my indicator below the x-axis, similar to TradingChart[ohlcv, {"Volume", "BollingerBands", "RelativeStrengthIndex"}] but "RelativeStrengthIndex" would be replaced by my indicator, "myindts". Any help would be appreciated.

Update: I have created Awesome Oscillator following notes here as follows:

midPrice = 
  TimeSeriesThread[(First[#] + Last[#])/2 &, {ohlcv["PathComponent", 
     2], ohlcv["PathComponent", 3]}];
awesomeOscillator = 
  DeleteMissing[
   TimeSeriesThread[
    First[#] - Last[#] &, {MovingMap[Mean, midPrice, 
      Quantity[5, "Days"]], 
     MovingMap[Mean, midPrice, Quantity[34, "Days"]]}, 
    ResamplingMethod -> Missing[]]];
awesomeOscillatormv = 
  MovingMap[Mean, awesomeOscillator, Quantity[10, "Days"]];

I want to plot the Awesome Oscillator below the chart produced by Trading Chart.

Column[{TradingChart[ohlcv, {"Volume", "BollingerBands"}], 
  Show[{DateListPlot[awesomeOscillatormv], 
    DateListPlot[awesomeOscillator, Filling -> 0, Joined -> False]}]}]

gives me the following chart: enter image description here

This chart is not what I am looking for. I want to have the same x-axis. Any help would be greatly appreciated.

$\endgroup$
9
+400
$\begingroup$

It appears you can define your own indicators to be used with TradingChart (this doesn't seem to be documented though):

myIndicator[data_, OptionsPattern[]] := Module[
  {myind},
  myind = 
   Accumulate /@ 
    SplitBy[Differences[Log[QuantityMagnitude[data[[4]]["Values"]]]], Sign] // 
     Flatten;
  {TimeSeries[myind, {Most[data[[4]]["Dates"]]}]}
 ]

This is essentially the code from your question put into a function, with two changes: First, we accept options via OptionsPattern[] (only needed when using something like "IndicatorLayout"->"Overlay", or custom options, supplied via FinancialIndicator[myIndicator, opts]). Second, we get a list 5 TimeSeries objects as data instead of one TimeSeries with 5 entries, so we need to extract the 4th value differently.

Now, to use it, simply wrap the function in FinancialIndicator:

ohlcv = FinancialData["SPY", "OHLCV", {DatePlus[Today, -300], Yesterday}];
TradingChart[ohlcv, {"Volume", FinancialIndicator[myIndicator]}]

enter image description here

We can also add it as an overlay to the main plot:

enter image description here

As you can see, this doesn't make a lot of sense here since the y-values are very different (note the almost flat blue line at the bottom)

Update

Here's an approach to get something similar to the plot in your updated question:

TradingChart[
  ohlcv, {
   "Volume", "BollingerBands",
   FinancialIndicator[
    QuantityMagnitude[{awesomeOscillator, awesomeOscillatormv}, "Dollars"] &,
    "Filling" -> {1 -> 0},
    "RenderingElement" -> {"Dot", "Line"},
    "LineStyle" -> ColorData[91][1]]
   },
  AspectRatio -> 1
  ] /. Inset[pre___, HoldPattern@{w_, h : System`TradingChartDump`$aspectratio 100}] :> Inset[pre, {w, h/4}]

enter image description here

Some notes:

  • In this example, I have used a financial indicator of the form FinancialIndicator[data&, ...], where the indicator "function" is an explicit Function expression that simply returns the desired data. As you can see, the name in the indicator label is a bit ugly this way, you can simply use the method with a user-defined function if you want to change it.
  • The two data sets are plotted together by grouping them into a single FinancialIndicator
  • The styles "RenderingElement" and "LineStyle" can be specified separately per line, the setting for "Filling" works as documented for Filling.
  • As you can see, the filling is not a perfect match of the example in your question. This is due to two things: TradingChart seems to resample the data, so the data points are regularly spaced. The filling is generated from a ListLinePlot, so there's no way to get the per-point filling this way.
  • The /. Inset[...] part is used to change the aspect ratio of the main plot in relation to the indicator plots. It works by identifying all the insets responsible for the main plot, and dividing their height by 4 (which is the default ration between the heights) to make them all the same height.
$\endgroup$
5
  • $\begingroup$ @ Lukas Thank you for your time and answer. Interestingly, I did try to use my indicator directly with FinancialIndicator without any function: TradingChart[ohlcv, {"Volume", FinancialIndicator[TimeSeries[myind, {Most[ohlcv["Dates"]]}]]}], but it did not work. Your trick of inserting function as an argument of FinancialIndicator did the work. Excellent!! – $\endgroup$
    – DLT
    Oct 14 '20 at 14:14
  • $\begingroup$ @DLT Looking at the relevant definitions of FinancialIndicator, it looks like custom indicators can be of the form _Symbol|_Function, i.e. you need to either supply a (custom) function name (as is done in my answer), or you need to supply an explicit Function[...]/...& expression, so TradingChart[ohlcv, {"Volume", FinancialIndicator[myindts &]}] (using the definition from your question) would also work, but the name of the indicator is then less readable $\endgroup$
    – Lukas Lang
    Oct 14 '20 at 18:16
  • $\begingroup$ @ Lukas, since I updated the question to address my real need, any update on your answer would be really appreciated. Thank you. $\endgroup$
    – DLT
    Oct 19 '20 at 1:40
  • $\begingroup$ @DLT I have updated the answer with an attempt to reproduce what you want $\endgroup$
    – Lukas Lang
    Oct 20 '20 at 10:51
  • $\begingroup$ @ Lukas, thank you for this update. It helps to get started but it seems that the task is a bit more difficult than I think. I really appreciate the time you spent in responding to this question. Thank you. $\endgroup$
    – DLT
    Oct 20 '20 at 12:41
4
$\begingroup$

Start:

ohlcv = FinancialData["SPY", 
   "OHLCV", {DatePlus[Today, -300], Yesterday}];
chart1 = TradingChart[ohlcv, {"Volume", "BollingerBands"}, 
   ImageSize -> {700, 500}];

myind = Accumulate /@ 
    SplitBy[Differences[
      Log[QuantityMagnitude[ohlcv["Values"][[All, 4]]]]], Sign] // 
   Flatten;
myindts = TimeSeries[myind, {Most[ohlcv["Dates"]]}];
chart2 = DateListPlot[myindts, 
  Frame -> {{False, True}, {True, False}}, 
  GridLines -> {{{2020, 1}, {2020, 2}, {2020, 3}, {2020, 4}, {2020, 
      5}, {2020, 6}, {2020, 7}, {2020, 8}, {2020, 9}, {2020, 
      10}}, {-.15, -.10, -0.05, 0, 0.05, 0.10, 0.15}}, 
  GridLinesStyle -> Directive[Lighter@Gray], AspectRatio -> 135/769, 
  ImageSize -> {769, 135}(*,DateTicksFormat\[Rule]{"Month"}*), 
  FrameTicks -> {{{2020, 1}, {2020, 2}, {2020, 3}, {2020, 4}, {2020, 
      5}, {2020, 6}, {2020, 7}, {2020, 8}, {2020, 9}}, {-0.15, -.1, 
     0, .1, 0.15}}, ImagePadding -> {{0, 94}, {25, 0}}, 
  PlotRangePadding -> None, 
  PlotRange -> {{First@Most[ohlcv["Dates"]], 
     Last@Most[ohlcv["Dates"]]}, {-0.175, 0.175}}]

adopted DateListPlot

DateListPlot adds a zone at the start and end of the TimeSeries per default.

Column[{chart1, chart2}, Left]

the style is transfered

DateListPlot blocks a lot of Options that need to be modified together. The top level problem is match the ImageSize. This only works in combination with AspectRatio due to presettings of DateListPlot.

Next problem is Ticks and Tickslabels.

Next problem is getting the axis from the left to the right for general TimeSeries this works, but the one of the question is trickier.

Seems that the TimeSeries either has different date on pupose or accident. It is easily possible to extend the TimeSeries to the time inteval under purpose in this fashion but the DateListPlot given is the fashion.

My remaining problem is the PlotRangePadding. I have no example or idea on how to do this in a DateListPlot. But I will work on that.

Some further improvement is this:

values = {200, 225, 250, 275, 300, 325, 350};dateslist1 = Prepend[{2020, #} & /@ Range[1, 9], {2019, 12}];
dateslist15 = Append[#, 15] & /@ dateslist;
dateslist = Riffle[dateslist1, dateslist15];
month = Table[AbsoluteTime@dateslist[[i]], {i, 1, Length@dateslist}];
chart3 = TradingChart[
  ohlcv, {"BollingerBands", FinancialIndicator@AccLogDiffs}, 
  PlotRange -> All, 
  FrameTicks -> {{{All, Automatic}, {Automatic, 
      Join[{-.15, 0, .15}, values]}}}, 
  GridLines -> {Automatic, Join[{-.15, 0, .15, .2}, values]}, 
  DisplayFunction -> Identity, ImageSize -> Large]

improvement on GridLines

ohlcv1 = FinancialData["SPY", 
   "OHLCV", {DatePlus[Today, -300], DatePlus[Today, -265]}];
chart3 = TradingChart[
  ohlcv1, {"BollingerBands", FinancialIndicator@AccLogDiffs}, 
  PlotRange -> All, AspectRatio -> 580/350, ImageSize -> {580, 350}, 
  FrameTicks -> {{None, Automatic}, {None, None}}, 
  GridLines -> {Automatic, Join[{-.15, 0, .15, .2}, values]}, 
  DisplayFunction -> Identity]

The time series length is of great importance to TradingChart.

The time series length is of great importance to TradingChart. It is is spread over two years as in the question the "Month" is internally replace with "Year" and that is very hard to change. It does take GridLines, but not FrameTicks. The change is "Year" and "Month" is really great and instructive.

Thanks to the answer Extracting financial indicator data from trading chart of @kuba we get further to

chart1 = TradingChart[ohlcv, {"Volume", "BollingerBands"}, 
   Appearance -> "Line", PerformanceGoal :> "Speed"];    
Cases[chart2, _Graphics, Infinity][[5]]

part 5 of the TradingChart

So for the Options Appearance and Performance with the shown methods gives the conformation the process is the correct way. All that is in need to be done place the fifth part of it with the axis You will like to have.

The interactive cursor is a problem but this can be added the same way as this in a second step:

ohlcv = FinancialData["SPY", 
   "OHLCV", {DatePlus[Today, -300], Yesterday}];
chart11 = TradingChart[ohlcv, {"Volume", "BollingerBands"}, 
   Appearance -> "Line", PerformanceGoal :> "Speed"];

dateslist=myindts[[2, 11, 2, 2, 1, 2, 1, 2]];
monthsmy=myindts[[2, 11, 2, 2, 1, 2, 2, 2]];
labels = Partition[
  Riffle[monthsmy[[1]], (12.5 + 
      185.5 (%289 - Min[dateslist])/((Max[dateslist] - Min[dateslist])))[[1]]], 2]

12.5 is the offset of the position of `19 and 185.5 is an estimate for the position of the Sep in the new graph.

With this, we can define a replacement rule for the Graphics displaying the unwanted Years.

InputForm@(Cases[chart1, _Graphics, \[Infinity]][[5]])[[1, 6, 1, 3, 1, 2, 1, 3, 1, 1 ;; 2]] /. 
 listts : {_Text, _Text} :> (texts /@ labels)

Plug it into the inactive TradingChart:

chart11 /. listts : {_Text, _Text} :> (texts /@ labels)

TradingChart with the Month as axis labels

$\endgroup$
1
  • $\begingroup$ @ Steffen, thank you for this update. Since I updated the question, I am going to leave this question for a couple of days. Thank you. $\endgroup$
    – DLT
    Oct 19 '20 at 1:39

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.