2121using System . Globalization ;
2222using System . Collections . Generic ;
2323using CsvHelper ;
24+ using CsvHelper . Configuration . Attributes ;
2425using QuantConnect . Data ;
2526using QuantConnect . Data . Market ;
2627using QuantConnect . Util ;
@@ -41,6 +42,7 @@ public class DataBentoDataDownloader : IDataProvider
4142
4243 /// <inheritdoc cref="MarketHoursDatabase" />
4344 private readonly MarketHoursDatabase _marketHoursDatabase ;
45+ private const decimal PriceScaleFactor = 1e-9m ;
4446
4547 /// <summary>
4648 /// Initializes a new instance of the <see cref="DataBentoDataDownloader"/>
@@ -104,32 +106,68 @@ public IEnumerable<BaseData> Get(DataDownloaderGetParameters parameters)
104106 using var reader = new StreamReader ( stream ) ;
105107 using var csv = new CsvReader ( reader , CultureInfo . InvariantCulture ) ;
106108
107- // base data conversion
108- foreach ( var record in csv . GetRecords < DatabentoTrade > ( ) )
109+ if ( tickType == TickType . Trade )
109110 {
110- if ( resolution == Resolution . Tick )
111+ foreach ( var record in csv . GetRecords < DatabentoBar > ( ) )
111112 {
112- yield return new Tick
113+ if ( resolution == Resolution . Tick )
114+ {
115+ yield return new Tick
116+ {
117+ Time = record . Timestamp ,
118+ Symbol = symbol ,
119+ Value = record . Price ,
120+ Quantity = record . Size
121+ } ;
122+ }
123+ else
113124 {
114- Time = record . Timestamp ,
115- Symbol = symbol ,
116- Value = record . Price ,
117- Quantity = record . Size
118- } ;
125+ yield return new TradeBar
126+ {
127+ Symbol = symbol ,
128+ Time = record . Timestamp ,
129+ Open = record . Open ,
130+ High = record . High ,
131+ Low = record . Low ,
132+ Close = record . Close ,
133+ Volume = record . Volume
134+ } ;
135+ }
119136 }
120- else
137+ }
138+ else if ( tickType == TickType . Quote )
139+ {
140+ foreach ( var record in csv . GetRecords < DatabentoQuote > ( ) )
121141 {
122- yield return new DataBentoDataType
142+ var bidPrice = record . BidPrice * PriceScaleFactor ;
143+ var askPrice = record . AskPrice * PriceScaleFactor ;
144+
145+ if ( resolution == Resolution . Tick )
146+ {
147+ yield return new Tick
148+ {
149+ Time = record . Timestamp ,
150+ Symbol = symbol ,
151+ AskPrice = askPrice ,
152+ BidPrice = bidPrice ,
153+ AskSize = record . AskSize ,
154+ BidSize = record . BidSize ,
155+ TickType = TickType . Quote
156+ } ;
157+ }
158+ else
123159 {
124- Symbol = symbol ,
125- Time = record . Timestamp ,
126- Open = record . Open ,
127- High = record . High ,
128- Low = record . Low ,
129- Close = record . Close ,
130- Volume = record . Volume ,
131- Value = record . Close
132- } ;
160+ var bidBar = new Bar ( bidPrice , bidPrice , bidPrice , bidPrice ) ;
161+ var askBar = new Bar ( askPrice , askPrice , askPrice , askPrice ) ;
162+ yield return new QuoteBar (
163+ record . Timestamp ,
164+ symbol ,
165+ bidBar ,
166+ record . BidSize ,
167+ askBar ,
168+ record . AskSize
169+ ) ;
170+ }
133171 }
134172 }
135173 }
@@ -147,31 +185,33 @@ public void Dispose()
147185 /// </summary>
148186 private string GetSchema ( Resolution resolution , TickType tickType )
149187 {
150- if ( resolution == Resolution . Tick && tickType == TickType . Trade )
151- return "trades" ;
152-
153- if ( resolution == Resolution . Tick && tickType == TickType . Quote )
154- return "mbp-1" ; // top of book
155-
156- if ( resolution == Resolution . Second )
157- return "ohlcv-1s" ;
158-
159- if ( resolution == Resolution . Minute )
160- return "ohlcv-1m" ;
161-
162- if ( resolution == Resolution . Hour )
163- return "ohlcv-1h" ;
164-
165- if ( resolution == Resolution . Daily )
166- return "ohlcv-1d" ;
188+ if ( tickType == TickType . Trade )
189+ {
190+ if ( resolution == Resolution . Tick )
191+ return "trades" ;
192+ if ( resolution == Resolution . Second )
193+ return "ohlcv-1s" ;
194+ if ( resolution == Resolution . Minute )
195+ return "ohlcv-1m" ;
196+ if ( resolution == Resolution . Hour )
197+ return "ohlcv-1h" ;
198+ if ( resolution == Resolution . Daily )
199+ return "ohlcv-1d" ;
200+ }
201+ else if ( tickType == TickType . Quote )
202+ {
203+ // top of book
204+ if ( resolution == Resolution . Tick || resolution == Resolution . Second || resolution == Resolution . Minute || resolution == Resolution . Hour || resolution == Resolution . Daily )
205+ return "mbp-1" ;
206+ }
167207
168208 throw new NotSupportedException ( $ "Unsupported resolution { resolution } / { tickType } ") ;
169209 }
170210
171211 /// <summary>
172212 /// Map Lean Symbol to Databento symbol string for continous
173213 /// </summary>
174- private string MapSymbol ( Symbol symbol )
214+ private static string MapSymbol ( Symbol symbol )
175215 {
176216 if ( symbol . SecurityType == SecurityType . Future )
177217 {
@@ -183,7 +223,7 @@ private string MapSymbol(Symbol symbol)
183223
184224
185225 /// Class for parsing trade data from Databento
186- private class DatabentoTrade
226+ private class DatabentoBar
187227 {
188228 public DateTime Timestamp { get ; set ; }
189229 public decimal Price { get ; set ; }
@@ -194,6 +234,19 @@ private class DatabentoTrade
194234 public decimal Close { get ; set ; }
195235 public decimal Volume { get ; set ; }
196236 }
237+
238+ private class DatabentoQuote
239+ {
240+ [ Name ( "ts_event" ) ]
241+ public DateTime Timestamp { get ; set ; }
242+ [ Name ( "bid_px_00" ) ]
243+ public long BidPrice { get ; set ; }
244+ [ Name ( "bid_sz_00" ) ]
245+ public int BidSize { get ; set ; }
246+ [ Name ( "ask_px_00" ) ]
247+ public long AskPrice { get ; set ; }
248+ [ Name ( "ask_sz_00" ) ]
249+ public int AskSize { get ; set ; }
250+ }
197251 }
198252}
199-
0 commit comments