Lean  $LEAN_TAG$
Chart.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Data;
19 using System.Drawing;
20 using Newtonsoft.Json;
21 using Newtonsoft.Json.Serialization;
22 using QuantConnect.Logging;
23 
24 namespace QuantConnect
25 {
26  /// <summary>
27  /// Single Parent Chart Object for Custom Charting
28  /// </summary>
29  public class Chart
30  {
31  /// <summary>
32  /// Name of the Chart
33  /// </summary>
34  public string Name { get; set; } = string.Empty;
35 
36  /// Type of the Chart, Overlayed or Stacked.
37  [Obsolete("ChartType is now obsolete. Please use Series indexes instead by setting index in the series constructor.")]
38  public ChartType ChartType { get; set; } = ChartType.Overlay;
39 
40  /// List of Series Objects for this Chart:
41  [JsonConverter(typeof(ChartSeriesJsonConverter))]
42  public Dictionary<string, BaseSeries> Series { get; set; } = new();
43 
44  /// <summary>
45  /// Associated symbol if any, making this an asset plot
46  /// </summary>
47  [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
48  public Symbol Symbol { get; set; }
49 
50  /// <summary>
51  /// True to hide this series legend from the chart
52  /// </summary>
53  [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
54  public bool LegendDisabled { get; set; }
55 
56  /// <summary>
57  /// Default constructor for chart:
58  /// </summary>
59  public Chart() { }
60 
61  /// <summary>
62  /// Chart Constructor:
63  /// </summary>
64  /// <param name="name">Name of the Chart</param>
65  /// <param name="type"> Type of the chart</param>
66  [Obsolete("ChartType is now obsolete and ignored in charting. Please use Series indexes instead by setting index in the series constructor.")]
67  public Chart(string name, ChartType type = ChartType.Overlay)
68  {
69  Name = name;
70  Series = new Dictionary<string, BaseSeries>();
71  ChartType = type;
72  }
73 
74  /// <summary>
75  /// Constructor for a chart
76  /// </summary>
77  /// <param name="name">String name of the chart</param>
78  public Chart(string name) : this(name, null)
79  {
80  }
81 
82  /// <summary>
83  /// Constructor for a chart
84  /// </summary>
85  /// <param name="name">String name of the chart</param>
86  /// <param name="symbol">Associated symbol if any</param>
87  public Chart(string name, Symbol symbol)
88  {
89  Name = name;
90  Symbol = symbol;
91  Series = new Dictionary<string, BaseSeries>();
92  }
93 
94  /// <summary>
95  /// Add a reference to this chart series:
96  /// </summary>
97  /// <param name="series">Chart series class object</param>
98  public void AddSeries(BaseSeries series)
99  {
100  //If we dont already have this series, add to the chrt:
101  if (!Series.ContainsKey(series.Name))
102  {
103  Series.Add(series.Name, series);
104  }
105  else
106  {
107  throw new DuplicateNameException($"Chart.AddSeries(): ${Messages.Chart.ChartSeriesAlreadyExists}");
108  }
109  }
110 
111  /// <summary>
112  /// Gets Series if already present in chart, else will add a new series and return it
113  /// </summary>
114  /// <param name="name">Name of the series</param>
115  /// <param name="type">Type of the series</param>
116  /// <param name="index">Index position on the chart of the series</param>
117  /// <param name="unit">Unit for the series axis</param>
118  /// <param name="color">Color of the series</param>
119  /// <param name="symbol">Symbol for the marker in a scatter plot series</param>
120  /// <param name="forceAddNew">True will always add a new Series instance, stepping on existing if any</param>
121  public Series TryAddAndGetSeries(string name, SeriesType type, int index, string unit,
122  Color color, ScatterMarkerSymbol symbol, bool forceAddNew = false)
123  {
124  BaseSeries series;
125  if (forceAddNew || !Series.TryGetValue(name, out series))
126  {
127  series = new Series(name, type, index, unit)
128  {
129  Color = color,
130  ScatterMarkerSymbol = symbol
131  };
132  Series[name] = series;
133  }
134 
135  return (Series)series;
136  }
137 
138  /// <summary>
139  /// Gets Series if already present in chart, else will add a new series and return it
140  /// </summary>
141  /// <param name="name">Name of the series</param>
142  /// <param name="templateSeries">Series to be used as a template. It will be clone without values if the series is added to the chart</param>
143  /// <param name="forceAddNew">True will always add a new Series instance, stepping on existing if any</param>
144  public BaseSeries TryAddAndGetSeries(string name, BaseSeries templateSeries, bool forceAddNew = false)
145  {
146  BaseSeries chartSeries;
147  if (forceAddNew || !Series.TryGetValue(name, out chartSeries))
148  {
149  Series[name] = chartSeries = templateSeries.Clone(empty: true);
150  }
151 
152  return chartSeries;
153  }
154 
155  /// <summary>
156  /// Fetch a chart with only the updates since the last request,
157  /// Underlying series will save the index position.
158  /// </summary>
159  /// <returns></returns>
160  public Chart GetUpdates()
161  {
162  var copy = CloneEmpty();
163  try
164  {
165  foreach (var series in Series.Values)
166  {
167  copy.AddSeries(series.GetUpdates());
168  }
169  }
170  catch (Exception err)
171  {
172  Log.Error(err);
173  }
174  return copy;
175  }
176 
177  /// <summary>
178  /// Return a new instance clone of this object
179  /// </summary>
180  /// <returns></returns>
181  public virtual Chart Clone()
182  {
183  var chart = CloneEmpty();
184 
185  foreach (var kvp in Series)
186  {
187  chart.Series.Add(kvp.Key, kvp.Value.Clone());
188  }
189 
190  return chart;
191  }
192 
193  /// <summary>
194  /// Return a new empty instance clone of this object
195  /// </summary>
196  public virtual Chart CloneEmpty()
197  {
198  return new Chart(Name) { LegendDisabled = LegendDisabled, Symbol = Symbol };
199  }
200  }
201 
202  /// <summary>
203  /// Type of chart - should we draw the series as overlayed or stacked
204  /// </summary>
205  public enum ChartType
206  {
207  /// Overlayed stacked (0)
208  Overlay,
209  /// Stacked series on top of each other. (1)
210  Stacked
211  }
212 }