21 using System.Collections.Generic;
22 using System.Globalization;
24 using System.IO.Compression;
26 using ZipEntry = Ionic.Zip.ZipEntry;
56 var rawData = GetRawDataStreamFromEntry(zipEntry);
57 return _tickType ==
TickType.Trade ? ParseKaikoTradeFile(rawData) : ParseKaikoQuoteFile(rawData);
65 private IEnumerable<string> GetRawDataStreamFromEntry(ZipEntry zipEntry)
67 using (var outerStream =
new StreamReader(zipEntry.OpenReader()))
68 using (var innerStream =
new GZipStream(outerStream.BaseStream, CompressionMode.Decompress))
69 using (var outputStream =
new StreamReader(innerStream))
72 while ((line = outputStream.ReadLine()) !=
null)
86 private IEnumerable<Tick> ParseKaikoQuoteFile(IEnumerable<string> rawDataLines)
88 var headerLine = rawDataLines.First();
89 var headerCsv = headerLine.ToCsv();
90 var typeColumn = headerCsv.FindIndex(x => x ==
"type");
91 var dateColumn = headerCsv.FindIndex(x => x ==
"date");
92 var priceColumn = headerCsv.FindIndex(x => x ==
"price");
93 var quantityColumn = headerCsv.FindIndex(x => x ==
"amount");
95 long currentEpoch = 0;
96 var currentEpochTicks =
new List<KaikoTick>();
98 foreach (var line
in rawDataLines.Skip(1))
100 if (line ==
null ||
string.IsNullOrEmpty(line))
continue;
102 var lineParts = line.Split(
',');
104 var tickEpoch = Parse.Long(lineParts[dateColumn]);
111 quantity = ParseScientificNotationToDecimal(lineParts, quantityColumn);
112 price = ParseScientificNotationToDecimal(lineParts, priceColumn);
116 Log.
Error($
"KaikoDataConverter.ParseKaikoQuoteFile(): Raw data corrupted. Line {string.Join(" ", lineParts)}, Exception {ex}");
120 var currentTick =
new KaikoTick
123 Time = Time.UnixMillisecondTimeStampToDateTime(tickEpoch),
129 if (currentEpoch != tickEpoch)
131 var quoteTick = CreateQuoteTick(Time.UnixMillisecondTimeStampToDateTime(currentEpoch), currentEpochTicks);
133 if (quoteTick !=
null) yield
return quoteTick;
135 currentEpochTicks.Clear();
136 currentEpoch = tickEpoch;
139 currentEpochTicks.Add(currentTick);
149 private Tick CreateQuoteTick(DateTime date, List<KaikoTick> currentEpcohTicks)
152 var bestAsk = currentEpcohTicks.Where(x => x.OrderDirection ==
"a")
153 .OrderBy(x => x.Value)
157 var bestBid = currentEpcohTicks.Where(x => x.OrderDirection ==
"b")
158 .OrderByDescending(x => x.Value)
161 if (bestAsk ==
null && bestBid ==
null)
167 var tick =
new Tick()
176 tick.BidPrice = bestBid.Price;
177 tick.BidSize = bestBid.Quantity;
182 tick.AskPrice = bestAsk.Price;
183 tick.AskSize = bestAsk.Quantity;
194 private IEnumerable<Tick> ParseKaikoTradeFile(IEnumerable<string> rawDataLines)
196 var headerLine = rawDataLines.First();
197 var headerCsv = headerLine.ToCsv();
198 var dateColumn = headerCsv.FindIndex(x => x ==
"date");
199 var priceColumn = headerCsv.FindIndex(x => x ==
"price");
200 var quantityColumn = headerCsv.FindIndex(x => x ==
"amount");
202 foreach (var line
in rawDataLines.Skip(1))
204 if (line ==
null ||
string.IsNullOrEmpty(line))
continue;
206 var lineParts = line.Split(
',');
213 quantity = ParseScientificNotationToDecimal(lineParts, quantityColumn);
214 price = ParseScientificNotationToDecimal(lineParts, priceColumn);
218 Log.
Error($
"KaikoDataConverter.ParseKaikoTradeFile(): Raw data corrupted. Line {string.Join(" ", lineParts)}, Exception {ex}");
222 yield
return new Tick
226 Time = Time.UnixMillisecondTimeStampToDateTime(Parse.Long(lineParts[dateColumn])),
239 private static decimal ParseScientificNotationToDecimal(
string[] lineParts,
int column)
241 var value = lineParts[column];
242 if (value.Contains(
'e', StringComparison.InvariantCulture))
244 return Parse.Decimal(value, NumberStyles.Float);
247 return lineParts[column].ConvertInvariant<decimal>();
254 private class KaikoTick :
Tick