Lean  $LEAN_TAG$
Tick.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 ProtoBuf;
18 using System.IO;
19 using Newtonsoft.Json;
20 using QuantConnect.Util;
21 using QuantConnect.Logging;
22 using System.Globalization;
23 using System.Runtime.CompilerServices;
24 
26 {
27  /// <summary>
28  /// Tick class is the base representation for tick data. It is grouped into a Ticks object
29  /// which implements IDictionary and passed into an OnData event handler.
30  /// </summary>
31  [ProtoContract(SkipConstructor = true)]
32  [ProtoInclude(1000, typeof(OpenInterest))]
33  public class Tick : BaseData
34  {
35  private Exchange _exchange = QuantConnect.Exchange.UNKNOWN;
36  private string _exchangeValue;
37  private uint? _parsedSaleCondition;
38 
39  /// <summary>
40  /// Type of the Tick: Trade or Quote.
41  /// </summary>
42  [ProtoMember(10)]
43  public TickType TickType = TickType.Trade;
44 
45  /// <summary>
46  /// Quantity exchanged in a trade.
47  /// </summary>
48  [ProtoMember(11)]
49  public decimal Quantity = 0;
50 
51  /// <summary>
52  /// Exchange code this tick came from <see cref="Exchanges"/>
53  /// </summary>
54  public string ExchangeCode
55  {
56  get
57  {
58  if (_exchange == null)
59  {
60  _exchange = Symbol != null
61  ? _exchangeValue.GetPrimaryExchange(Symbol.SecurityType, Symbol.ID.Market) : _exchangeValue.GetPrimaryExchange();
62  }
63  return _exchange.Code;
64  }
65  set
66  {
67  _exchangeValue = value;
68  _exchange = null;
69  }
70  }
71 
72  /// <summary>
73  /// Exchange name this tick came from <see cref="Exchanges"/>
74  /// </summary>
75  [ProtoMember(12)]
76  public string Exchange
77  {
78  get
79  {
80  if (_exchange == null)
81  {
82  _exchange = Symbol != null
83  ? _exchangeValue.GetPrimaryExchange(Symbol.SecurityType, Symbol.ID.Market) : _exchangeValue.GetPrimaryExchange();
84  }
85  return _exchange;
86  }
87  set
88  {
89  _exchangeValue = value;
90  _exchange = null;
91  }
92  }
93 
94  /// <summary>
95  /// Sale condition for the tick.
96  /// </summary>
97  public string SaleCondition = "";
98 
99  /// <summary>
100  /// For performance parsed sale condition for the tick.
101  /// </summary>
102  [JsonIgnore]
103  public uint ParsedSaleCondition
104  {
105  get
106  {
107  if (string.IsNullOrEmpty(SaleCondition))
108  {
109  return 0;
110  }
111 
112  if (!_parsedSaleCondition.HasValue)
113  {
114  _parsedSaleCondition = uint.Parse(SaleCondition, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
115  }
116  return _parsedSaleCondition.Value;
117  }
118  set
119  {
120  _parsedSaleCondition = value;
121  }
122  }
123 
124  /// <summary>
125  /// Bool whether this is a suspicious tick
126  /// </summary>
127  [ProtoMember(14)]
128  public bool Suspicious = false;
129 
130  /// <summary>
131  /// Bid Price for Tick
132  /// </summary>
133  [ProtoMember(15)]
134  public decimal BidPrice = 0;
135 
136  /// <summary>
137  /// Asking price for the Tick quote.
138  /// </summary>
139  [ProtoMember(16)]
140  public decimal AskPrice = 0;
141 
142  /// <summary>
143  /// Alias for "Value" - the last sale for this asset.
144  /// </summary>
145  public decimal LastPrice
146  {
147  get
148  {
149  return Value;
150  }
151  }
152 
153  /// <summary>
154  /// Size of bid quote.
155  /// </summary>
156  [ProtoMember(17)]
157  public decimal BidSize = 0;
158 
159  /// <summary>
160  /// Size of ask quote.
161  /// </summary>
162  [ProtoMember(18)]
163  public decimal AskSize = 0;
164 
165  //In Base Class: Alias of Closing:
166  //public decimal Price;
167 
168  //Symbol of Asset.
169  //In Base Class: public Symbol Symbol;
170 
171  //In Base Class: DateTime Of this TradeBar
172  //public DateTime Time;
173 
174  /// <summary>
175  /// Initialize tick class with a default constructor.
176  /// </summary>
177  public Tick()
178  {
179  Value = 0;
180  Time = new DateTime();
181  DataType = MarketDataType.Tick;
182  Symbol = Symbol.Empty;
183  TickType = TickType.Trade;
184  Quantity = 0;
185  _exchange = QuantConnect.Exchange.UNKNOWN;
186  SaleCondition = string.Empty;
187  Suspicious = false;
188  BidSize = 0;
189  AskSize = 0;
190  }
191 
192  /// <summary>
193  /// Cloner constructor for fill forward engine implementation. Clone the original tick into this new tick:
194  /// </summary>
195  /// <param name="original">Original tick we're cloning</param>
196  public Tick(Tick original)
197  {
198  Symbol = original.Symbol;
199  Time = new DateTime(original.Time.Ticks);
200  Value = original.Value;
201  BidPrice = original.BidPrice;
202  AskPrice = original.AskPrice;
203  // directly set privates so we don't parse the exchange
204  _exchange = original._exchange;
205  _exchangeValue = original._exchangeValue;
206  SaleCondition = original.SaleCondition;
207  Quantity = original.Quantity;
208  Suspicious = original.Suspicious;
209  DataType = MarketDataType.Tick;
210  TickType = original.TickType;
211  BidSize = original.BidSize;
212  AskSize = original.AskSize;
213  }
214 
215  /// <summary>
216  /// Constructor for a FOREX tick where there is no last sale price. The volume in FX is so high its rare to find FX trade data.
217  /// To fake this the tick contains bid-ask prices and the last price is the midpoint.
218  /// </summary>
219  /// <param name="time">Full date and time</param>
220  /// <param name="symbol">Underlying currency pair we're trading</param>
221  /// <param name="bid">FX tick bid value</param>
222  /// <param name="ask">FX tick ask value</param>
223  public Tick(DateTime time, Symbol symbol, decimal bid, decimal ask)
224  {
225  DataType = MarketDataType.Tick;
226  Time = time;
227  Symbol = symbol;
228  Value = (bid + ask) / 2;
229  TickType = TickType.Quote;
230  BidPrice = bid;
231  AskPrice = ask;
232  }
233 
234  /// <summary>
235  /// Initializer for a last-trade equity tick with bid or ask prices.
236  /// </summary>
237  /// <param name="time">Full date and time</param>
238  /// <param name="symbol">Underlying equity security symbol</param>
239  /// <param name="bid">Bid value</param>
240  /// <param name="ask">Ask value</param>
241  /// <param name="last">Last trade price</param>
242  public Tick(DateTime time, Symbol symbol, decimal last, decimal bid, decimal ask)
243  {
244  DataType = MarketDataType.Tick;
245  Time = time;
246  Symbol = symbol;
247  Value = last;
248  TickType = TickType.Quote;
249  BidPrice = bid;
250  AskPrice = ask;
251  }
252 
253  /// <summary>
254  /// Trade tick type constructor
255  /// </summary>
256  /// <param name="time">Full date and time</param>
257  /// <param name="symbol">Underlying equity security symbol</param>
258  /// <param name="saleCondition">The ticks sale condition</param>
259  /// <param name="exchange">The ticks exchange</param>
260  /// <param name="quantity">The quantity traded</param>
261  /// <param name="price">The price of the trade</param>
262  public Tick(DateTime time, Symbol symbol, string saleCondition, string exchange, decimal quantity, decimal price)
263  {
264  Value = price;
265  Time = time;
266  DataType = MarketDataType.Tick;
267  Symbol = symbol;
268  TickType = TickType.Trade;
269  Quantity = quantity;
270  Exchange = exchange;
271  SaleCondition = saleCondition;
272  Suspicious = false;
273  }
274 
275  /// <summary>
276  /// Trade tick type constructor
277  /// </summary>
278  /// <param name="time">Full date and time</param>
279  /// <param name="symbol">Underlying equity security symbol</param>
280  /// <param name="saleCondition">The ticks sale condition</param>
281  /// <param name="exchange">The ticks exchange</param>
282  /// <param name="quantity">The quantity traded</param>
283  /// <param name="price">The price of the trade</param>
284  public Tick(DateTime time, Symbol symbol, string saleCondition, Exchange exchange, decimal quantity, decimal price)
285  : this(time, symbol, saleCondition, string.Empty, quantity, price)
286  {
287  // we were giving the exchange, set it directly
288  _exchange = exchange;
289  }
290 
291  /// <summary>
292  /// Quote tick type constructor
293  /// </summary>
294  /// <param name="time">Full date and time</param>
295  /// <param name="symbol">Underlying equity security symbol</param>
296  /// <param name="saleCondition">The ticks sale condition</param>
297  /// <param name="exchange">The ticks exchange</param>
298  /// <param name="bidSize">The bid size</param>
299  /// <param name="bidPrice">The bid price</param>
300  /// <param name="askSize">The ask size</param>
301  /// <param name="askPrice">The ask price</param>
302  public Tick(DateTime time, Symbol symbol, string saleCondition, string exchange, decimal bidSize, decimal bidPrice, decimal askSize, decimal askPrice)
303  {
304  Time = time;
305  DataType = MarketDataType.Tick;
306  Symbol = symbol;
307  TickType = TickType.Quote;
308  Exchange = exchange;
309  SaleCondition = saleCondition;
310  Suspicious = false;
311  AskPrice = askPrice;
312  AskSize = askSize;
313  BidPrice = bidPrice;
314  BidSize = bidSize;
315  }
316 
317  /// <summary>
318  /// Quote tick type constructor
319  /// </summary>
320  /// <param name="time">Full date and time</param>
321  /// <param name="symbol">Underlying equity security symbol</param>
322  /// <param name="saleCondition">The ticks sale condition</param>
323  /// <param name="exchange">The ticks exchange</param>
324  /// <param name="bidSize">The bid size</param>
325  /// <param name="bidPrice">The bid price</param>
326  /// <param name="askSize">The ask size</param>
327  /// <param name="askPrice">The ask price</param>
328  public Tick(DateTime time, Symbol symbol, string saleCondition, Exchange exchange, decimal bidSize, decimal bidPrice, decimal askSize, decimal askPrice)
329  : this(time, symbol, saleCondition, string.Empty, bidSize, bidPrice, askSize, askPrice)
330  {
331  // we were giving the exchange, set it directly
332  _exchange = exchange;
333  }
334 
335  /// <summary>
336  /// Constructor for QuantConnect FXCM Data source:
337  /// </summary>
338  /// <param name="symbol">Symbol for underlying asset</param>
339  /// <param name="line">CSV line of data from FXCM</param>
340  public Tick(Symbol symbol, string line)
341  {
342  var csv = line.Split(',');
343  DataType = MarketDataType.Tick;
344  Symbol = symbol;
345  Time = DateTime.ParseExact(csv[0], DateFormat.Forex, CultureInfo.InvariantCulture);
346  Value = (BidPrice + AskPrice) / 2;
347  TickType = TickType.Quote;
348  BidPrice = Convert.ToDecimal(csv[1], CultureInfo.InvariantCulture);
349  AskPrice = Convert.ToDecimal(csv[2], CultureInfo.InvariantCulture);
350  }
351 
352  /// <summary>
353  /// Constructor for QuantConnect tick data
354  /// </summary>
355  /// <param name="symbol">Symbol for underlying asset</param>
356  /// <param name="line">CSV line of data from QC tick csv</param>
357  /// <param name="baseDate">The base date of the tick</param>
358  public Tick(Symbol symbol, string line, DateTime baseDate)
359  {
360  var csv = line.Split(',');
361  DataType = MarketDataType.Tick;
362  Symbol = symbol;
363  Time = baseDate.Date.AddTicks(Convert.ToInt64(10000 * csv[0].ToDecimal()));
364  Value = csv[1].ToDecimal() / GetScaleFactor(symbol);
365  TickType = TickType.Trade;
366  Quantity = csv[2].ToDecimal();
367  Exchange = csv[3].Trim();
368  SaleCondition = csv[4];
369  Suspicious = csv[5].ToInt32() == 1;
370  }
371 
372  /// <summary>
373  /// Parse a tick data line from quantconnect zip source files.
374  /// </summary>
375  /// <param name="reader">The source stream reader</param>
376  /// <param name="date">Base date for the tick (ticks date is stored as int milliseconds since midnight)</param>
377  /// <param name="config">Subscription configuration object</param>
378  public Tick(SubscriptionDataConfig config, StreamReader reader, DateTime date)
379  {
380  try
381  {
382  DataType = MarketDataType.Tick;
383  Symbol = config.Symbol;
384 
385  // Which security type is this data feed:
386  var scaleFactor = GetScaleFactor(config.Symbol);
387 
388  switch (config.SecurityType)
389  {
390  case SecurityType.Equity:
391  {
392  TickType = config.TickType;
393  Time = date.Date.AddTicks(Convert.ToInt64(10000 * reader.GetDecimal())).ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
394 
395  bool pastLineEnd;
396  if (TickType == TickType.Trade)
397  {
398  Value = reader.GetDecimal() / scaleFactor;
399  Quantity = reader.GetDecimal(out pastLineEnd);
400  if (!pastLineEnd)
401  {
402  Exchange = reader.GetString();
403  SaleCondition = reader.GetString();
404  Suspicious = reader.GetInt32() == 1;
405  }
406  }
407  else if (TickType == TickType.Quote)
408  {
409  BidPrice = reader.GetDecimal() / scaleFactor;
410  BidSize = reader.GetDecimal();
411  AskPrice = reader.GetDecimal() / scaleFactor;
412  AskSize = reader.GetDecimal(out pastLineEnd);
413 
414  SetValue();
415 
416  if (!pastLineEnd)
417  {
418  Exchange = reader.GetString();
419  SaleCondition = reader.GetString();
420  Suspicious = reader.GetInt32() == 1;
421  }
422  }
423  else
424  {
425  throw new InvalidOperationException($"Tick(): Unexpected tick type {TickType}");
426  }
427  break;
428  }
429 
430  case SecurityType.Forex:
431  case SecurityType.Cfd:
432  {
433  TickType = TickType.Quote;
434  Time = date.Date.AddTicks(Convert.ToInt64(10000 * reader.GetDecimal()))
435  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
436  BidPrice = reader.GetDecimal();
437  AskPrice = reader.GetDecimal();
438 
439  SetValue();
440  break;
441  }
442 
443  case SecurityType.CryptoFuture:
444  case SecurityType.Crypto:
445  {
446  TickType = config.TickType;
447  Exchange = config.Market;
448  Time = date.Date.AddTicks(Convert.ToInt64(10000 * reader.GetDecimal()))
449  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
450 
451  if (TickType == TickType.Trade)
452  {
453  Value = reader.GetDecimal();
454  Quantity = reader.GetDecimal(out var endOfLine);
455  Suspicious = !endOfLine && reader.GetInt32() == 1;
456  }
457  else if(TickType == TickType.Quote)
458  {
459  BidPrice = reader.GetDecimal();
460  BidSize = reader.GetDecimal();
461  AskPrice = reader.GetDecimal();
462  AskSize = reader.GetDecimal(out var endOfLine);
463  Suspicious = !endOfLine && reader.GetInt32() == 1;
464 
465  SetValue();
466  }
467  break;
468  }
469  case SecurityType.Future:
470  case SecurityType.Option:
471  case SecurityType.FutureOption:
472  case SecurityType.IndexOption:
473  {
474  TickType = config.TickType;
475  Time = date.Date.AddTicks(Convert.ToInt64(10000 * reader.GetDecimal()))
476  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
477 
478  if (TickType == TickType.Trade)
479  {
480  Value = reader.GetDecimal() / scaleFactor;
481  Quantity = reader.GetDecimal();
482  Exchange = reader.GetString();
483  SaleCondition = reader.GetString();
484  Suspicious = reader.GetInt32() == 1;
485  }
486  else if (TickType == TickType.OpenInterest)
487  {
488  Value = reader.GetDecimal();
489  }
490  else
491  {
492  BidPrice = reader.GetDecimal() / scaleFactor;
493  BidSize = reader.GetDecimal();
494  AskPrice = reader.GetDecimal() / scaleFactor;
495  AskSize = reader.GetDecimal();
496  Exchange = reader.GetString();
497  Suspicious = reader.GetInt32() == 1;
498 
499  SetValue();
500  }
501 
502  break;
503  }
504  }
505  }
506  catch (Exception err)
507  {
508  Log.Error(err);
509  }
510  }
511 
512  /// <summary>
513  /// Parse a tick data line from quantconnect zip source files.
514  /// </summary>
515  /// <param name="line">CSV source line of the compressed source</param>
516  /// <param name="date">Base date for the tick (ticks date is stored as int milliseconds since midnight)</param>
517  /// <param name="config">Subscription configuration object</param>
518  public Tick(SubscriptionDataConfig config, string line, DateTime date)
519  {
520  try
521  {
522  DataType = MarketDataType.Tick;
523  Symbol = config.Symbol;
524 
525  // Which security type is this data feed:
526  var scaleFactor = GetScaleFactor(config.Symbol);
527 
528  switch (config.SecurityType)
529  {
530  case SecurityType.Equity:
531  {
532  var index = 0;
533  TickType = config.TickType;
534  var csv = line.ToCsv(TickType == TickType.Trade ? 6 : 8);
535  Time = date.Date.AddTicks(Convert.ToInt64(10000 * csv[index++].ToDecimal())).ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
536 
537  if (TickType == TickType.Trade)
538  {
539  Value = csv[index++].ToDecimal() / scaleFactor;
540  Quantity = csv[index++].ToDecimal();
541  if (csv.Count > index)
542  {
543  Exchange = csv[index++];
544  SaleCondition = csv[index++];
545  Suspicious = (csv[index++] == "1");
546  }
547  }
548  else if (TickType == TickType.Quote)
549  {
550  BidPrice = csv[index++].ToDecimal() / scaleFactor;
551  BidSize = csv[index++].ToDecimal();
552  AskPrice = csv[index++].ToDecimal() / scaleFactor;
553  AskSize = csv[index++].ToDecimal();
554 
555  SetValue();
556 
557  if (csv.Count > index)
558  {
559  Exchange = csv[index++];
560  SaleCondition = csv[index++];
561  Suspicious = (csv[index++] == "1");
562  }
563  }
564  else
565  {
566  throw new InvalidOperationException($"Tick(): Unexpected tick type {TickType}");
567  }
568  break;
569  }
570 
571  case SecurityType.Forex:
572  case SecurityType.Cfd:
573  {
574  var csv = line.ToCsv(3);
575  TickType = TickType.Quote;
576  var ticks = (long)(csv[0].ToDecimal() * TimeSpan.TicksPerMillisecond);
577  Time = date.Date.AddTicks(ticks)
578  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
579  BidPrice = csv[1].ToDecimal();
580  AskPrice = csv[2].ToDecimal();
581 
582  SetValue();
583  break;
584  }
585 
586  case SecurityType.Crypto:
587  case SecurityType.CryptoFuture:
588  {
589  TickType = config.TickType;
590  Exchange = config.Market;
591 
592  if (TickType == TickType.Trade)
593  {
594  var csv = line.ToCsv(3);
595  Time = date.Date.AddTicks(Convert.ToInt64(10000 * csv[0].ToDecimal()))
596  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
597  Value = csv[1].ToDecimal();
598  Quantity = csv[2].ToDecimal();
599  Suspicious = csv.Count >= 4 && csv[3] == "1";
600  }
601 
602  if (TickType == TickType.Quote)
603  {
604  var csv = line.ToCsv(6);
605  Time = date.Date.AddTicks(Convert.ToInt64(10000 * csv[0].ToDecimal()))
606  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
607  BidPrice = csv[1].ToDecimal();
608  BidSize = csv[2].ToDecimal();
609  AskPrice = csv[3].ToDecimal();
610  AskSize = csv[4].ToDecimal();
611  Suspicious = csv.Count >= 6 && csv[5] == "1";
612 
613  SetValue();
614  }
615  break;
616  }
617  case SecurityType.Future:
618  case SecurityType.Option:
619  case SecurityType.FutureOption:
620  case SecurityType.IndexOption:
621  {
622  var csv = line.ToCsv(7);
623  TickType = config.TickType;
624  Time = date.Date.AddTicks(Convert.ToInt64(10000 * csv[0].ToDecimal()))
625  .ConvertTo(config.DataTimeZone, config.ExchangeTimeZone);
626 
627  if (TickType == TickType.Trade)
628  {
629  Value = csv[1].ToDecimal()/scaleFactor;
630  Quantity = csv[2].ToDecimal();
631  Exchange = csv[3];
632  SaleCondition = csv[4];
633  Suspicious = csv[5] == "1";
634  }
635  else if (TickType == TickType.OpenInterest)
636  {
637  Value = csv[1].ToDecimal();
638  }
639  else
640  {
641  if (csv[1].Length != 0)
642  {
643  BidPrice = csv[1].ToDecimal()/scaleFactor;
644  BidSize = csv[2].ToDecimal();
645  }
646  if (csv[3].Length != 0)
647  {
648  AskPrice = csv[3].ToDecimal()/scaleFactor;
649  AskSize = csv[4].ToDecimal();
650  }
651  Exchange = csv[5];
652  Suspicious = csv[6] == "1";
653 
654  SetValue();
655  }
656 
657  break;
658  }
659  }
660  }
661  catch (Exception err)
662  {
663  Log.Error(err);
664  }
665  }
666 
667  /// <summary>
668  /// Tick implementation of reader method: read a line of data from the source and convert it to a tick object.
669  /// </summary>
670  /// <param name="config">Subscription configuration object for algorithm</param>
671  /// <param name="line">Line from the datafeed source</param>
672  /// <param name="date">Date of this reader request</param>
673  /// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
674  /// <returns>New Initialized tick</returns>
675  public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
676  {
677  if (isLiveMode)
678  {
679  // currently ticks don't come through the reader function
680  return new Tick();
681  }
682 
683  return new Tick(config, line, date);
684  }
685 
686  /// <summary>
687  /// Tick implementation of reader method: read a line of data from the source and convert it to a tick object.
688  /// </summary>
689  /// <param name="config">Subscription configuration object for algorithm</param>
690  /// <param name="reader">The source stream reader</param>
691  /// <param name="date">Date of this reader request</param>
692  /// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
693  /// <returns>New Initialized tick</returns>
694  public override BaseData Reader(SubscriptionDataConfig config, StreamReader reader, DateTime date, bool isLiveMode)
695  {
696  if (isLiveMode)
697  {
698  // currently ticks don't come through the reader function
699  return new Tick();
700  }
701 
702  return new Tick(config, reader, date);
703  }
704 
705 
706  /// <summary>
707  /// Get source for tick data feed - not used with QuantConnect data sources implementation.
708  /// </summary>
709  /// <param name="config">Configuration object</param>
710  /// <param name="date">Date of this source request if source spread across multiple files</param>
711  /// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
712  /// <returns>String source location of the file to be opened with a stream</returns>
713  public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
714  {
715  if (isLiveMode)
716  {
717  // this data type is streamed in live mode
718  return new SubscriptionDataSource(string.Empty, SubscriptionTransportMedium.Streaming);
719  }
720 
721  var source = LeanData.GenerateZipFilePath(Globals.DataFolder, config.Symbol, date, config.Resolution, config.TickType);
722  if (config.SecurityType == SecurityType.Future || config.SecurityType.IsOption())
723  {
724  source += "#" + LeanData.GenerateZipEntryName(config.Symbol, date, config.Resolution, config.TickType);
725  }
726  return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv);
727  }
728 
729  /// <summary>
730  /// Update the tick price information - not used.
731  /// </summary>
732  /// <param name="lastTrade">This trade price</param>
733  /// <param name="bidPrice">Current bid price</param>
734  /// <param name="askPrice">Current asking price</param>
735  /// <param name="volume">Volume of this trade</param>
736  /// <param name="bidSize">The size of the current bid, if available</param>
737  /// <param name="askSize">The size of the current ask, if available</param>
738  [MethodImpl(MethodImplOptions.AggressiveInlining)]
739  public override void Update(decimal lastTrade, decimal bidPrice, decimal askPrice, decimal volume, decimal bidSize, decimal askSize)
740  {
741  Value = lastTrade;
742  BidPrice = bidPrice;
743  AskPrice = askPrice;
744  BidSize = bidSize;
745  AskSize = askSize;
746  Quantity = Convert.ToDecimal(volume);
747  }
748 
749  /// <summary>
750  /// Check if tick contains valid data (either a trade, or a bid or ask)
751  /// </summary>
752  [MethodImpl(MethodImplOptions.AggressiveInlining)]
753  public bool IsValid()
754  {
755  // Indexes have zero volume in live trading, but is still a valid tick.
756  return (TickType == TickType.Trade && (LastPrice > 0.0m && (Quantity > 0 || Symbol.SecurityType == SecurityType.Index))) ||
757  (TickType == TickType.Quote && AskPrice > 0.0m && AskSize > 0) ||
758  (TickType == TickType.Quote && BidPrice > 0.0m && BidSize > 0) ||
759  (TickType == TickType.OpenInterest && Value > 0);
760  }
761 
762  /// <summary>
763  /// Clone implementation for tick class:
764  /// </summary>
765  /// <returns>New tick object clone of the current class values.</returns>
766  public override BaseData Clone()
767  {
768  return new Tick(this);
769  }
770 
771  /// <summary>
772  /// Formats a string with the symbol and value.
773  /// </summary>
774  /// <returns>string - a string formatted as SPY: 167.753</returns>
775  public override string ToString()
776  {
777  switch (TickType)
778  {
779  case TickType.Trade:
780  return $"{Symbol}: Price: {Price} Quantity: {Quantity}";
781 
782  case TickType.Quote:
783  return $"{Symbol}: Bid: {BidSize}@{BidPrice} Ask: {AskSize}@{AskPrice}";
784 
785  case TickType.OpenInterest:
786  return $"{Symbol}: OpenInterest: {Value}";
787 
788  default:
789  throw new ArgumentOutOfRangeException();
790  }
791  }
792 
793  /// <summary>
794  /// Sets the tick Value based on ask and bid price
795  /// </summary>
796  public void SetValue()
797  {
798  Value = BidPrice + AskPrice;
799  if (BidPrice * AskPrice != 0)
800  {
801  Value /= 2m;
802  }
803  }
804 
805  /// <summary>
806  /// Gets the scaling factor according to the <see cref="SecurityType"/> of the <see cref="Symbol"/> provided.
807  /// Non-equity data will not be scaled, including options with an underlying non-equity asset class.
808  /// </summary>
809  /// <param name="symbol">Symbol to get scaling factor for</param>
810  /// <returns>Scaling factor</returns>
811  private static decimal GetScaleFactor(Symbol symbol)
812  {
813  return symbol.SecurityType == SecurityType.Equity || symbol.SecurityType == SecurityType.Option ? 10000m : 1;
814  }
815 
816  }
817 }