├── .gitignore ├── App.xaml ├── App.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── QScalp ├── DataTypes.cs ├── Internals │ ├── DateTimeHelper.cs │ ├── Flags.cs │ ├── Leb128.cs │ ├── QshFile.cs │ ├── StreamType.cs │ └── ULeb128.cs ├── RawQuotes.cs ├── Reader │ ├── IQshStream.cs │ ├── QshReader.cs │ └── V4 │ │ ├── AuxInfoStream.cs │ │ ├── DataReader.cs │ │ ├── DealsStream.cs │ │ ├── MessagesStream.cs │ │ ├── OrdLogStream.cs │ │ ├── OwnOrdersStream.cs │ │ ├── OwnTradesStream.cs │ │ ├── QshReaderImpl.cs │ │ ├── QshStream.cs │ │ └── QuotesStream.cs ├── Security.cs └── Writer │ ├── AuxInfoStream.cs │ ├── DataWriter.cs │ ├── DealsStream.cs │ ├── MessagesStream.cs │ ├── OrdLogStream.cs │ ├── OwnOrdersStream.cs │ ├── OwnTradesStream.cs │ ├── QshWriter.cs │ └── QuotesStream.cs ├── Qsh2StockSharp.csproj ├── Qsh2StockSharp.sln ├── README.md ├── app.config └── stocksharp.ico /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /obj 3 | /*.user 4 | /*.suo 5 | *.suo 6 | /packages/ 7 | /TestData/ 8 | /.vs/ 9 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 |  7 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace StockSharp.Qsh2StockSharp 2 | { 3 | public partial class App 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | QSH: 34 | 35 | 36 | S#: 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Board code: 59 | 60 | 61 | Security Code Masks: 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Output format: 99 | 100 | 101 | Multi thread convertion 102 | 103 | OL -> Стакан 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace StockSharp.Qsh2StockSharp 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | 11 | using DevExpress.Xpf.Core; 12 | 13 | using Ecng.Common; 14 | using Ecng.Collections; 15 | using Ecng.Serialization; 16 | using Ecng.Xaml; 17 | 18 | using MoreLinq; 19 | 20 | using QScalp; 21 | using QScalp.History; 22 | using QScalp.History.Reader; 23 | 24 | using StockSharp.Algo; 25 | using StockSharp.Algo.Storages; 26 | using StockSharp.BusinessEntities; 27 | using StockSharp.Localization; 28 | using StockSharp.Logging; 29 | using StockSharp.Messages; 30 | using StockSharp.Plaza; 31 | using StockSharp.Xaml; 32 | 33 | public partial class MainWindow 34 | { 35 | private class Settings 36 | { 37 | public string QshFolder { get; set; } 38 | public string StockSharpFolder { get; set; } 39 | public StorageFormats Format { get; set; } 40 | public string Board { get; set; } 41 | public string SecurityLike { get; set; } 42 | public bool MultiThread { get; set; } 43 | public bool OrderLog2OrderBook { get; set; } 44 | public int OrderBookMaxDepth { get; set; } = 5; 45 | public string TimeStampZone { get; set; } 46 | public string MarketDataZone { get; set; } 47 | } 48 | 49 | private readonly LogManager _logManager = new LogManager(); 50 | 51 | private bool _isStarted; 52 | 53 | private DateTimeOffset _startConvertTime; 54 | 55 | private const string _settingsDir = "Settings"; 56 | 57 | private static readonly string _settingsFile = Path.Combine(_settingsDir, "settings.xml"); 58 | private static readonly string _convertedFilesFile = Path.Combine(_settingsDir, "converted_files.txt"); 59 | 60 | private readonly HashSet _convertedFiles = new HashSet(StringComparer.InvariantCultureIgnoreCase); 61 | private readonly HashSet _convertedPerTaskPoolFiles = new HashSet(StringComparer.InvariantCultureIgnoreCase); 62 | 63 | public MainWindow() 64 | { 65 | InitializeComponent(); 66 | 67 | Title = TypeHelper.ApplicationNameWithVersion; 68 | 69 | ApplicationThemeHelper.ApplicationThemeName = ThemeExtensions.DefaultTheme; 70 | 71 | Directory.CreateDirectory(_settingsDir); 72 | 73 | TimeStampZone.TimeZone = TimeZoneInfo.Utc; 74 | MarketDataZone.TimeZone = TimeHelper.Moscow; 75 | 76 | _logManager.Application.LogLevel = LogLevels.Verbose; 77 | 78 | _logManager.Listeners.Add(new GuiLogListener(LogControl)); 79 | _logManager.Listeners.Add(new FileLogListener { LogDirectory = "Logs", SeparateByDates = SeparateByDateModes.FileName }); 80 | 81 | Format.SetDataSource(); 82 | Format.SetSelectedValue(StorageFormats.Binary); 83 | 84 | Board.Boards.AddRange(ExchangeBoard.EnumerateExchangeBoards().Where(b => b.Exchange == Exchange.Moex)); 85 | Board.SelectedBoard = ExchangeBoard.Forts; 86 | 87 | try 88 | { 89 | if (File.Exists(_settingsFile)) 90 | { 91 | var settings = new XmlSerializer().Deserialize(_settingsFile); 92 | 93 | QshFolder.Folder = settings.QshFolder; 94 | StockSharpFolder.Folder = settings.StockSharpFolder; 95 | Format.SetSelectedValue(settings.Format); 96 | SecurityLike.Text = settings.SecurityLike; 97 | MultiThread.IsChecked = settings.MultiThread; 98 | OrderLog2OrderBook.IsChecked = settings.OrderLog2OrderBook; 99 | 100 | Board.SelectedBoard = 101 | settings.Board.IsEmpty() 102 | ? ExchangeBoard.Forts 103 | : Board.Boards.FirstOrDefault(b => b.Code.CompareIgnoreCase(settings.Board)) ?? ExchangeBoard.Forts; 104 | 105 | if (!settings.TimeStampZone.IsEmpty()) 106 | TimeStampZone.TimeZone = TimeZoneInfo.FindSystemTimeZoneById(settings.TimeStampZone); 107 | 108 | if (!settings.MarketDataZone.IsEmpty()) 109 | MarketDataZone.TimeZone = TimeZoneInfo.FindSystemTimeZoneById(settings.MarketDataZone); 110 | } 111 | 112 | if (File.Exists(_convertedFilesFile)) 113 | { 114 | _convertedFiles.AddRange(File.ReadAllLines(_convertedFilesFile)); 115 | } 116 | } 117 | catch (Exception ex) 118 | { 119 | ex.LogError(); 120 | } 121 | } 122 | 123 | protected override void OnClosed(EventArgs e) 124 | { 125 | SaveSettings(); 126 | base.OnClosed(e); 127 | } 128 | 129 | private Settings SaveSettings() 130 | { 131 | var settings = new Settings 132 | { 133 | QshFolder = QshFolder.Folder, 134 | StockSharpFolder = StockSharpFolder.Folder, 135 | Format = Format.GetSelectedValue() ?? StorageFormats.Binary, 136 | SecurityLike = SecurityLike.Text, 137 | Board = Board.SelectedBoard?.Code, 138 | MultiThread = MultiThread.IsChecked == true, 139 | OrderLog2OrderBook = OrderLog2OrderBook.IsEnabled && OrderLog2OrderBook.IsChecked == true, 140 | TimeStampZone = TimeStampZone.TimeZone.Id, 141 | MarketDataZone = MarketDataZone.TimeZone.Id, 142 | }; 143 | 144 | try 145 | { 146 | new XmlSerializer().Serialize(settings, _settingsFile); 147 | } 148 | catch (Exception ex) 149 | { 150 | ex.LogError(); 151 | } 152 | 153 | return settings; 154 | } 155 | 156 | private void LockControls(bool isEnabled) 157 | { 158 | FoldersGrid.IsEnabled = StorageSettingsBox.IsEnabled = SecSettingsBox.IsEnabled = isEnabled; 159 | } 160 | 161 | private void Convert_OnClick(object sender, RoutedEventArgs e) 162 | { 163 | Convert.IsEnabled = false; 164 | 165 | if (_isStarted) 166 | { 167 | _logManager.Application.AddInfoLog("Остановка конвертации."); 168 | _isStarted = false; 169 | return; 170 | } 171 | 172 | LockControls(false); 173 | 174 | _logManager.Application.AddInfoLog("Запуск конвертации."); 175 | _isStarted = true; 176 | 177 | var settings = SaveSettings(); 178 | var board = Board.SelectedBoard; 179 | 180 | var orderLog2OrderBookBuilders = settings.OrderLog2OrderBook ? new Dictionary() : null; 181 | var tz = TimeStampZone.TimeZone; 182 | var mz = MarketDataZone.TimeZone; 183 | 184 | Task.Factory.StartNew(() => 185 | { 186 | var registry = new StorageRegistry(); 187 | ((LocalMarketDataDrive)registry.DefaultDrive).Path = settings.StockSharpFolder; 188 | 189 | this.GuiAsync(() => 190 | { 191 | Convert.Content = LocalizedStrings.Str2890; 192 | Convert.IsEnabled = true; 193 | }); 194 | 195 | _startConvertTime = DateTimeOffset.Now; 196 | 197 | ConvertDirectory(settings.QshFolder, registry, settings.Format, board, settings.SecurityLike, settings.MultiThread, orderLog2OrderBookBuilders, settings.OrderBookMaxDepth, tz, mz); 198 | }) 199 | .ContinueWith(t => 200 | { 201 | Convert.Content = LocalizedStrings.Str2932; 202 | Convert.IsEnabled = true; 203 | 204 | LockControls(true); 205 | 206 | if (t.IsFaulted) 207 | { 208 | t.Exception.LogError(); 209 | 210 | new MessageBoxBuilder() 211 | .Text("В процессе конвертации произошла ошибка. Ошибка записана в лог.") 212 | .Error() 213 | .Owner(this) 214 | .Show(); 215 | 216 | return; 217 | } 218 | 219 | var text = "Конвертация {0} {1}.".Put(_isStarted ? "выполнена за" : "остановлена через", 220 | (DateTimeOffset.Now - _startConvertTime).ToString("g")); 221 | 222 | _logManager.Application.AddInfoLog(text); 223 | 224 | new MessageBoxBuilder() 225 | .Text(text) 226 | .Owner(this) 227 | .Show(); 228 | 229 | _isStarted = false; 230 | 231 | }, TaskScheduler.FromCurrentSynchronizationContext()); 232 | } 233 | 234 | private void ConvertDirectory(string path, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike, bool multithread, Dictionary orderLog2OrderBookBuilders, int orderBookMaxDepth, TimeZoneInfo tz, TimeZoneInfo mz) 235 | { 236 | if (!_isStarted) 237 | return; 238 | 239 | var files = Directory.GetFiles(path, "*.qsh"); 240 | 241 | if (!multithread) 242 | files.ForEach(f => ConvertFile(f, registry, format, board, securityLike, orderLog2OrderBookBuilders, orderBookMaxDepth, tz, mz)); 243 | else 244 | { 245 | Parallel.ForEach(files, file => ConvertFile(file, registry, format, board, securityLike, orderLog2OrderBookBuilders, orderBookMaxDepth, tz, mz)); 246 | } 247 | 248 | //пишем имена сконвертированных в деректории файлов qsh, в файл 249 | File.AppendAllLines(_convertedFilesFile, _convertedPerTaskPoolFiles); 250 | _convertedPerTaskPoolFiles.Clear(); 251 | 252 | Directory.GetDirectories(path).ForEach(d => ConvertDirectory(d, registry, format, board, securityLike, multithread, orderLog2OrderBookBuilders, orderBookMaxDepth, tz, mz)); 253 | } 254 | 255 | private void TryFlushData(IStorageRegistry registry, SecurityId securityId, StorageFormats format, object arg, List messages, QshReader reader) 256 | where TMessage : Messages.Message 257 | { 258 | const int maxBufCount = 1000; 259 | 260 | if (messages.Count <= maxBufCount) 261 | return; 262 | 263 | _logManager.Application.AddDebugLog("Файл прочитан на {1}%.", messages.Count, (reader.FilePosition * 100) / reader.FileSize); 264 | 265 | registry.GetStorage(securityId, typeof(TMessage), arg, null, format).Save(messages); 266 | messages.Clear(); 267 | } 268 | 269 | private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike, Dictionary orderLog2OrderBookBuilders, int orderBookMaxDepth, TimeZoneInfo tz, TimeZoneInfo mz) 270 | { 271 | if (!_isStarted) 272 | return; 273 | 274 | var fileNameKey = format + "_" + fileName; 275 | 276 | if (_convertedFiles.Contains(fileNameKey)) 277 | return; 278 | 279 | _logManager.Application.AddInfoLog("Начата конвертация файла {0}.", fileName); 280 | 281 | var securitiesStrings = securityLike.Split(","); 282 | 283 | var data = new Dictionary, List, List, List>>(); 284 | 285 | DateTimeOffset ToLocalDto(DateTime dt) => dt.ApplyTimeZone(tz); 286 | DateTimeOffset ToServerDto(DateTime dt) => dt.ApplyTimeZone(mz); 287 | 288 | using (var qr = QshReader.Open(fileName)) 289 | { 290 | var reader = qr; 291 | 292 | for (var i = 0; i < qr.StreamCount; i++) 293 | { 294 | var stream = (ISecurityStream)qr[i]; 295 | var securityId = GetSecurityId(stream.Security, board.Code); 296 | var priceStep = (decimal)stream.Security.Step; 297 | var lastTransactionId = 0L; 298 | var builder = orderLog2OrderBookBuilders?.SafeAdd(securityId, key => new PlazaOrderLogMarketDepthBuilder(key)); 299 | 300 | if (securitiesStrings.Length > 0) 301 | { 302 | var secCode = securityId.SecurityCode; 303 | 304 | var streamContainsSecurityFromMask = securitiesStrings.Any(mask => 305 | { 306 | var isEndMulti = mask.EndsWith("*"); 307 | var isStartMulti = mask.StartsWith("*"); 308 | 309 | if (isStartMulti) 310 | mask = mask.Substring(1); 311 | 312 | if (isEndMulti) 313 | mask = mask.Substring(0, mask.Length - 1); 314 | 315 | if (isEndMulti) 316 | { 317 | if (isStartMulti) 318 | return secCode.ContainsIgnoreCase(mask); 319 | else 320 | return secCode.StartsWith(mask, StringComparison.InvariantCultureIgnoreCase); 321 | } 322 | else if (isStartMulti) 323 | return secCode.EndsWith(mask, StringComparison.InvariantCultureIgnoreCase); 324 | else 325 | return secCode.CompareIgnoreCase(mask); 326 | }); 327 | 328 | if (!streamContainsSecurityFromMask) 329 | continue; 330 | } 331 | 332 | var secData = data.SafeAdd(securityId, key => Tuple.Create(new List(), new List(), new List(), new List())); 333 | 334 | switch (stream.Type) 335 | { 336 | case StreamType.Quotes: 337 | { 338 | ((IQuotesStream)stream).Handler += quotes => 339 | { 340 | var bids = new List(); 341 | var asks = new List(); 342 | 343 | foreach (var q in quotes) 344 | { 345 | switch (q.Type) 346 | { 347 | //case QuoteType.Unknown: 348 | //case QuoteType.Free: 349 | //case QuoteType.Spread: 350 | // throw new ArgumentException(q.Type.ToString()); 351 | case QuoteType.Ask: 352 | case QuoteType.BestAsk: 353 | asks.Add(new QuoteChange(priceStep * q.Price, q.Volume)); 354 | break; 355 | case QuoteType.Bid: 356 | case QuoteType.BestBid: 357 | bids.Add(new QuoteChange(priceStep * q.Price, q.Volume)); 358 | break; 359 | default: 360 | { 361 | continue; 362 | //throw new ArgumentException(q.Type.ToString()); 363 | } 364 | } 365 | } 366 | 367 | var md = new QuoteChangeMessage 368 | { 369 | LocalTime = ToLocalDto(reader.CurrentDateTime), 370 | SecurityId = securityId, 371 | ServerTime = ToLocalDto(reader.CurrentDateTime), 372 | Bids = bids.ToArray(), 373 | Asks = asks.ToArray(), 374 | }; 375 | 376 | //if (md.Verify()) 377 | //{ 378 | secData.Item1.Add(md); 379 | 380 | TryFlushData(registry, securityId, format, null, secData.Item1, reader); 381 | 382 | //} 383 | //else 384 | // _logManager.Application.AddErrorLog("Стакан для {0} в момент {1} не прошел валидацию. Лучший бид {2}, Лучший офер {3}.", security, qr.CurrentDateTime, md.BestBid, md.BestAsk); 385 | }; 386 | break; 387 | } 388 | case StreamType.Deals: 389 | { 390 | ((IDealsStream)stream).Handler += deal => 391 | { 392 | secData.Item2.Add(new ExecutionMessage 393 | { 394 | LocalTime = ToLocalDto(reader.CurrentDateTime), 395 | HasTradeInfo = true, 396 | ExecutionType = ExecutionTypes.Tick, 397 | SecurityId = securityId, 398 | OpenInterest = deal.OI == 0 ? (long?)null : deal.OI, 399 | ServerTime = ToServerDto(deal.DateTime), 400 | TradeVolume = deal.Volume, 401 | TradeId = deal.Id == 0 ? (long?)null : deal.Id, 402 | TradePrice = deal.Price * priceStep, 403 | OriginSide = 404 | deal.Type == DealType.Buy 405 | ? Sides.Buy 406 | : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null) 407 | }); 408 | 409 | TryFlushData(registry, securityId, format, ExecutionTypes.Tick, secData.Item2, reader); 410 | }; 411 | break; 412 | } 413 | case StreamType.OrdLog: 414 | { 415 | ((IOrdLogStream)stream).Handler += ol => 416 | { 417 | var currTransactionId = ol.DateTime.Ticks; 418 | 419 | if (lastTransactionId < currTransactionId) 420 | lastTransactionId = currTransactionId; 421 | else if (lastTransactionId >= currTransactionId) 422 | lastTransactionId++; 423 | 424 | var msg = new ExecutionMessage 425 | { 426 | LocalTime = ToLocalDto(reader.CurrentDateTime), 427 | ExecutionType = ExecutionTypes.OrderLog, 428 | SecurityId = securityId, 429 | OpenInterest = ol.OI == 0 ? (long?)null : ol.OI, 430 | OrderId = ol.OrderId, 431 | OrderPrice = priceStep * ol.Price, 432 | ServerTime = ToServerDto(ol.DateTime), 433 | OrderVolume = ol.Amount, 434 | Balance = ol.AmountRest, 435 | TradeId = ol.DealId == 0 ? (long?)null : ol.DealId, 436 | TradePrice = ol.DealPrice == 0 ? (decimal?)null : priceStep * ol.DealPrice, 437 | TransactionId = lastTransactionId 438 | }; 439 | 440 | var status = 0; 441 | 442 | if (ol.Flags.Contains(OrdLogFlags.Add)) 443 | { 444 | msg.OrderState = OrderStates.Active; 445 | } 446 | else if (ol.Flags.Contains(OrdLogFlags.Fill)) 447 | { 448 | msg.OrderState = OrderStates.Done; 449 | } 450 | else if (ol.Flags.Contains(OrdLogFlags.Canceled)) 451 | { 452 | msg.OrderState = OrderStates.Done; 453 | status |= 0x200000; 454 | } 455 | else if (ol.Flags.Contains(OrdLogFlags.CanceledGroup)) 456 | { 457 | msg.OrderState = OrderStates.Done; 458 | status |= 0x400000; 459 | } 460 | else if (ol.Flags.Contains(OrdLogFlags.Moved)) 461 | { 462 | status |= 0x100000; 463 | } 464 | 465 | if (ol.Flags.Contains(OrdLogFlags.Buy)) 466 | { 467 | msg.Side = Sides.Buy; 468 | } 469 | else if (ol.Flags.Contains(OrdLogFlags.Sell)) 470 | { 471 | msg.Side = Sides.Sell; 472 | } 473 | 474 | if (ol.Flags.Contains(OrdLogFlags.FillOrKill)) 475 | { 476 | msg.TimeInForce = TimeInForce.MatchOrCancel; 477 | status |= 0x00080000; 478 | } 479 | 480 | if (ol.Flags.Contains(OrdLogFlags.Quote)) 481 | { 482 | msg.TimeInForce = TimeInForce.PutInQueue; 483 | status |= 0x01; 484 | } 485 | 486 | if (ol.Flags.Contains(OrdLogFlags.Counter)) 487 | { 488 | status |= 0x02; 489 | } 490 | 491 | if (ol.Flags.Contains(OrdLogFlags.CrossTrade)) 492 | { 493 | status |= 0x20000000; 494 | } 495 | 496 | if (ol.Flags.Contains(OrdLogFlags.NonSystem)) 497 | { 498 | msg.IsSystem = false; 499 | status |= 0x04; 500 | } 501 | 502 | if (ol.Flags.Contains(OrdLogFlags.EndOfTransaction)) 503 | { 504 | status |= 0x1000; 505 | } 506 | 507 | msg.OrderStatus = status; 508 | 509 | if (builder == null) 510 | { 511 | secData.Item4.Add(msg); 512 | 513 | TryFlushData(registry, securityId, format, ExecutionTypes.OrderLog, secData.Item4, reader); 514 | } 515 | else 516 | { 517 | //if (builder.Depth.Bids.Any() || builder.Depth.Asks.Any() || msg.ServerTime.TimeOfDay >= new TimeSpan(0, 18, 45, 00, 1)) 518 | { 519 | QuoteChangeMessage updated; 520 | 521 | try 522 | { 523 | updated = builder.Update(msg); 524 | } 525 | catch 526 | { 527 | updated = null; 528 | } 529 | 530 | if (updated != null) 531 | { 532 | secData.Item1.Add(updated); 533 | 534 | TryFlushData(registry, securityId, format, null, secData.Item1, reader); 535 | } 536 | } 537 | } 538 | }; 539 | break; 540 | } 541 | case StreamType.AuxInfo: 542 | { 543 | ((IAuxInfoStream)stream).Handler += info => 544 | { 545 | var l1Msg = new Level1ChangeMessage 546 | { 547 | LocalTime = ToLocalDto(reader.CurrentDateTime), 548 | SecurityId = securityId, 549 | ServerTime = ToLocalDto(reader.CurrentDateTime), 550 | } 551 | .TryAdd(Level1Fields.LastTradePrice, priceStep * info.Price) 552 | .TryAdd(Level1Fields.BidsVolume, (decimal)info.BidTotal) 553 | .TryAdd(Level1Fields.AsksVolume, (decimal)info.AskTotal) 554 | .TryAdd(Level1Fields.HighPrice, priceStep * info.HiLimit) 555 | .TryAdd(Level1Fields.LowPrice, priceStep * info.LoLimit) 556 | .TryAdd(Level1Fields.StepPrice, (decimal)info.Rate) 557 | .TryAdd(Level1Fields.OperatingMargin, (decimal)info.Deposit) 558 | .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI); 559 | 560 | if (l1Msg.Changes.Count == 0) 561 | return; 562 | 563 | secData.Item3.Add(l1Msg); 564 | 565 | TryFlushData(registry, securityId, format, null, secData.Item3, reader); 566 | }; 567 | break; 568 | } 569 | case StreamType.OwnOrders: 570 | case StreamType.OwnTrades: 571 | case StreamType.Messages: 572 | case StreamType.None: 573 | { 574 | continue; 575 | } 576 | default: 577 | throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type)); 578 | } 579 | } 580 | 581 | if (data.Count > 0) 582 | { 583 | while (qr.CurrentDateTime != DateTime.MaxValue && _isStarted) 584 | qr.Read(true); 585 | } 586 | } 587 | 588 | if (!_isStarted) 589 | return; 590 | 591 | foreach (var pair in data) 592 | { 593 | if (pair.Value.Item1.Any()) 594 | { 595 | registry.GetQuoteMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item1); 596 | } 597 | 598 | if (pair.Value.Item2.Any()) 599 | { 600 | registry.GetTickMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item2); 601 | } 602 | 603 | if (pair.Value.Item3.Any()) 604 | { 605 | registry.GetLevel1MessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item3); 606 | } 607 | 608 | if (pair.Value.Item4.Any()) 609 | { 610 | registry.GetOrderLogMessageStorage(pair.Key, registry.DefaultDrive, format).Save(pair.Value.Item4); 611 | } 612 | } 613 | 614 | if (data.Count > 0) 615 | { 616 | //File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey }); 617 | _convertedFiles.Add(fileNameKey); 618 | _convertedPerTaskPoolFiles.Add(fileNameKey); 619 | } 620 | 621 | _logManager.Application.AddInfoLog("Завершена конвертация файла {0}.", fileName); 622 | } 623 | 624 | private static SecurityId GetSecurityId(QScalp.Security security, string boardCode) 625 | { 626 | return new SecurityId 627 | { 628 | SecurityCode = security.Ticker, 629 | BoardCode = boardCode, 630 | }; 631 | } 632 | 633 | private void TryEnable() 634 | { 635 | Convert.IsEnabled = !QshFolder.Folder.IsEmpty() && !StockSharpFolder.Folder.IsEmpty() && Board.SelectedBoard != null; 636 | } 637 | 638 | private void Board_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 639 | { 640 | TryEnable(); 641 | } 642 | 643 | private void OnFolderChanged(string folder) 644 | { 645 | TryEnable(); 646 | } 647 | } 648 | } -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | 5 | using StockSharp.Localization; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Qsh2Bin")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("StockSharp")] 14 | [assembly: AssemblyProduct("Qsh2Bin")] 15 | [assembly: AssemblyCopyright("Copyright © StockSharp 2015")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion(ProjectDescriptions.Version)] 55 | [assembly: AssemblyFileVersion(ProjectDescriptions.Version)] 56 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace StockSharp.Qsh2StockSharp.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StockSharp.Qsh2StockSharp.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace StockSharp.Qsh2StockSharp.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /QScalp/DataTypes.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp 15 | { 16 | // ************************************************************************ 17 | 18 | enum QuoteType { Unknown, Free, Spread, Ask, Bid, BestAsk, BestBid } 19 | enum DealType { Unknown, Buy, Sell } 20 | enum OwnOrderType { None, Regular, Stop } 21 | enum OwnTradeSource { Unknown, Real, Emulator, Manual, History } 22 | enum MessageType { None, Info, Warning, Error } 23 | 24 | // ************************************************************************ 25 | 26 | struct Quote 27 | { 28 | public int Price; 29 | public int Volume; 30 | public QuoteType Type; 31 | 32 | public Quote(int price, int volume, QuoteType type) 33 | { 34 | this.Price = price; 35 | this.Volume = volume; 36 | this.Type = type; 37 | } 38 | } 39 | 40 | // ************************************************************************ 41 | 42 | sealed class Deal 43 | { 44 | public DateTime DateTime; 45 | public long Id; 46 | public long OrderId; 47 | public DealType Type; 48 | public int Price; 49 | public int Volume; 50 | public int OI; 51 | } 52 | 53 | // ************************************************************************ 54 | 55 | struct OwnOrder 56 | { 57 | public readonly OwnOrderType Type; 58 | 59 | public readonly long Id; 60 | public readonly int Price; 61 | public readonly int Quantity; 62 | 63 | public OwnOrder(long id, int price) 64 | { 65 | this.Type = OwnOrderType.None; 66 | this.Id = id; 67 | this.Price = price; 68 | this.Quantity = 0; 69 | } 70 | 71 | public OwnOrder(OwnOrderType type, long id, int price, int quantity) 72 | { 73 | this.Type = type; 74 | this.Id = id; 75 | this.Price = price; 76 | this.Quantity = quantity; 77 | } 78 | } 79 | 80 | // ************************************************************************ 81 | 82 | sealed class OwnTrade 83 | { 84 | public readonly OwnTradeSource Source; 85 | public readonly DateTime DateTime; 86 | public readonly long TradeId; 87 | public readonly long OrderId; 88 | public readonly int Price; 89 | public readonly int Quantity; 90 | 91 | public OwnTrade(OwnTradeSource source, DateTime dateTime, 92 | long tradeId, long orderId, int price, int quantity) 93 | { 94 | this.Source = source; 95 | this.DateTime = dateTime; 96 | this.TradeId = tradeId; 97 | this.OrderId = orderId; 98 | this.Price = price; 99 | this.Quantity = quantity; 100 | } 101 | } 102 | 103 | // ************************************************************************ 104 | 105 | struct Message 106 | { 107 | public readonly DateTime DateTime; 108 | public readonly MessageType Type; 109 | public readonly string Text; 110 | 111 | public Message(DateTime dateTime, MessageType type, string text) 112 | { 113 | this.DateTime = dateTime; 114 | this.Type = type; 115 | this.Text = text; 116 | } 117 | } 118 | 119 | // ************************************************************************ 120 | 121 | sealed class AuxInfo 122 | { 123 | public readonly DateTime DateTime; 124 | public readonly int Price; 125 | 126 | public readonly int AskTotal; 127 | public readonly int BidTotal; 128 | public readonly int OI; 129 | 130 | public readonly int HiLimit; 131 | public readonly int LoLimit; 132 | public readonly double Deposit; 133 | 134 | public readonly double Rate; 135 | public readonly string Message; 136 | 137 | public AuxInfo(DateTime dateTime, int price, int askTotal, int bidTotal, 138 | int oi, int hiLimit, int loLimit, double deposit, double rate, string message) 139 | { 140 | this.DateTime = dateTime; 141 | this.Price = price; 142 | 143 | this.AskTotal = askTotal; 144 | this.BidTotal = bidTotal; 145 | this.OI = oi; 146 | 147 | this.HiLimit = hiLimit; 148 | this.LoLimit = loLimit; 149 | this.Deposit = deposit; 150 | 151 | this.Rate = rate; 152 | this.Message = message; 153 | } 154 | } 155 | 156 | // ************************************************************************ 157 | 158 | [Flags] 159 | enum OrdLogFlags 160 | { 161 | NonZeroReplAct = 1 << 0, 162 | FlowStart = 1 << 1, 163 | 164 | Add = 1 << 2, 165 | Fill = 1 << 3, 166 | 167 | Buy = 1 << 4, 168 | Sell = 1 << 5, 169 | 170 | Snapshot = 1 << 6, 171 | 172 | Quote = 1 << 7, // Котировочная 173 | Counter = 1 << 8, // Встречная 174 | NonSystem = 1 << 9, // Внесистемная 175 | EndOfTransaction = 1 << 10, // Запись является последней в транзакции 176 | FillOrKill = 1 << 11, // Заявка Fill-or-kill 177 | Moved = 1 << 12, // Запись является результатом операции перемещения заявки 178 | Canceled = 1 << 13, // Запись является результатом операции удаления заявки 179 | CanceledGroup = 1 << 14, // Запись является результатом группового удаления 180 | CrossTrade = 1 << 15, // Признак удаления остатка заявки по причине кросс-сделки 181 | 182 | None = 0 183 | } 184 | 185 | // ************************************************************************ 186 | 187 | sealed class OrdLogEntry 188 | { 189 | public readonly OrdLogFlags Flags; 190 | 191 | public readonly DateTime DateTime; 192 | public readonly long OrderId; 193 | 194 | public readonly int Price; 195 | 196 | public readonly int Amount; 197 | public readonly int AmountRest; 198 | 199 | public readonly long DealId; 200 | public readonly int DealPrice; 201 | public readonly int OI; 202 | 203 | public OrdLogEntry(OrdLogFlags flags, DateTime dateTime, long orderId, 204 | int price, int amount, int amountRest, long dealId, int dealPrice, int oi) 205 | { 206 | this.Flags = flags; 207 | this.DateTime = dateTime; 208 | this.OrderId = orderId; 209 | this.Price = price; 210 | this.Amount = amount; 211 | this.AmountRest = amountRest; 212 | this.DealId = dealId; 213 | this.DealPrice = dealPrice; 214 | this.OI = oi; 215 | } 216 | } 217 | 218 | // ************************************************************************ 219 | } 220 | -------------------------------------------------------------------------------- /QScalp/Internals/DateTimeHelper.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp.History.Internals 15 | { 16 | static class DateTimeHelper 17 | { 18 | // ********************************************************************** 19 | 20 | public static long ToMs(DateTime dateTime) 21 | { 22 | return dateTime.Ticks / TimeSpan.TicksPerMillisecond; 23 | } 24 | 25 | // ********************************************************************** 26 | 27 | public static DateTime FromMs(long milliseconds) 28 | { 29 | return new DateTime(milliseconds * TimeSpan.TicksPerMillisecond); 30 | } 31 | 32 | // ********************************************************************** 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /QScalp/Internals/Flags.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp.History.Internals 15 | { 16 | // ************************************************************************ 17 | 18 | [Flags] 19 | enum DealFlags 20 | { 21 | Type = 0x03, 22 | 23 | DateTime = 0x04, 24 | Id = 0x08, 25 | OrderId = 0x10, 26 | Price = 0x20, 27 | Volume = 0x40, 28 | OI = 0x80, 29 | 30 | None = 0 31 | } 32 | 33 | // ********************************************************************** 34 | 35 | [Flags] 36 | enum OrderFlags 37 | { 38 | DropAll = 0x01, 39 | Active = 0x02, 40 | External = 0x04, 41 | Stop = 0x08, 42 | 43 | None = 0 44 | } 45 | 46 | // ********************************************************************** 47 | 48 | [Flags] 49 | enum AuxInfoFlags 50 | { 51 | DateTime = 0x01, 52 | 53 | AskTotal = 0x02, 54 | BidTotal = 0x04, 55 | OI = 0x08, 56 | Price = 0x10, 57 | 58 | SessionInfo = 0x20, 59 | Rate = 0x40, 60 | Message = 0x80, 61 | 62 | None = 0 63 | } 64 | 65 | // ************************************************************************ 66 | 67 | [Flags] 68 | enum OrdLogEntryFlags 69 | { 70 | DateTime = 0x01, 71 | OrderId = 0x02, 72 | Price = 0x04, 73 | 74 | Amount = 0x08, 75 | AmountRest = 0x10, 76 | 77 | DealId = 0x20, 78 | DealPrice = 0x40, 79 | OI = 0x80, 80 | 81 | None = 0 82 | } 83 | 84 | // ************************************************************************ 85 | } 86 | -------------------------------------------------------------------------------- /QScalp/Internals/Leb128.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System.IO; 13 | 14 | namespace QScalp.History.Internals 15 | { 16 | static class Leb128 17 | { 18 | // ********************************************************************** 19 | 20 | public const int Min1BValue = -64; 21 | public const int Max1BValue = -Min1BValue - 1; 22 | 23 | public const int Min2BValue = -8192; 24 | public const int Max2BValue = -Min2BValue - 1; 25 | 26 | public const int Min3BValue = -1048576; 27 | public const int Max3BValue = -Min3BValue - 1; 28 | 29 | public const int Min4BValue = -134217728; 30 | public const int Max4BValue = -Min4BValue - 1; 31 | 32 | public const long Min5BValue = -17179869184; 33 | public const long Max5BValue = -Min5BValue - 1; 34 | 35 | public const long Min6BValue = -2199023255552; 36 | public const long Max6BValue = -Min6BValue - 1; 37 | 38 | public const long Min7BValue = -281474976710656; 39 | public const long Max7BValue = -Min7BValue - 1; 40 | 41 | public const long Min8BValue = -36028797018963968; 42 | public const long Max8BValue = -Min8BValue - 1; 43 | 44 | public const long Min9BValue = -4611686018427387904; 45 | public const long Max9BValue = -Min9BValue - 1; 46 | 47 | // ********************************************************************** 48 | 49 | public static void Write(Stream stream, long value) 50 | { 51 | if(value >= 0) 52 | for(; ; ) 53 | { 54 | int b = (int)(value & 0x7f); 55 | value >>= 7; 56 | 57 | if(value == 0 && (b & 0x40) == 0) 58 | { 59 | stream.WriteByte((byte)b); 60 | return; 61 | } 62 | 63 | stream.WriteByte((byte)(b | 0x80)); 64 | } 65 | else 66 | for(; ; ) 67 | { 68 | int b = (int)(value & 0x7f); 69 | value >>= 7; 70 | 71 | if(value == -1 && (b & 0x40) != 0) 72 | { 73 | stream.WriteByte((byte)b); 74 | return; 75 | } 76 | 77 | stream.WriteByte((byte)(b | 0x80)); 78 | } 79 | } 80 | 81 | // ********************************************************************** 82 | 83 | public static long Read(Stream stream) 84 | { 85 | long value = 0; 86 | int shift = 0; 87 | 88 | for(; ; ) 89 | { 90 | int b = stream.ReadByte(); 91 | 92 | if(b == -1) 93 | throw new EndOfStreamException(); 94 | 95 | value |= (long)(b & 0x7f) << shift; 96 | shift += 7; 97 | 98 | if((b & 0x80) == 0) 99 | { 100 | if(shift < sizeof(long) * 8 && (b & 0x40) != 0) 101 | value |= -(1L << shift); 102 | 103 | return value; 104 | } 105 | } 106 | } 107 | 108 | // ********************************************************************** 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /QScalp/Internals/QshFile.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.IO; 14 | using System.IO.Compression; 15 | using System.Text; 16 | 17 | namespace QScalp.History.Internals 18 | { 19 | static class QshFile 20 | { 21 | // ********************************************************************** 22 | 23 | static readonly byte[] prefix = Encoding.ASCII.GetBytes("QScalp History Data"); 24 | 25 | // ********************************************************************** 26 | 27 | public static Stream Create(string path, bool compress, byte version) 28 | { 29 | Stream stm = new FileStream(path, FileMode.Create, FileAccess.Write); 30 | 31 | if(compress) 32 | stm = new GZipStream(stm, CompressionMode.Compress); 33 | 34 | stm.Write(prefix, 0, prefix.Length); 35 | stm.WriteByte(version); 36 | 37 | return stm; 38 | } 39 | 40 | // ********************************************************************** 41 | 42 | static bool CheckPrefix(Stream stream, byte[] buffer) 43 | { 44 | if(stream.Read(buffer, 0, buffer.Length) != prefix.Length) 45 | return false; 46 | 47 | for(int i = 0; i < buffer.Length; i++) 48 | if(buffer[i] != prefix[i]) 49 | return false; 50 | 51 | return true; 52 | } 53 | 54 | // ********************************************************************** 55 | 56 | public static Stream GetDataStream(FileStream fs) 57 | { 58 | byte[] buffer = new byte[prefix.Length]; 59 | 60 | if(CheckPrefix(fs, buffer)) 61 | return fs; 62 | 63 | Stream stream = null; 64 | 65 | try 66 | { 67 | fs.Position = 0; 68 | stream = new GZipStream(fs, CompressionMode.Decompress, true); 69 | 70 | if(CheckPrefix(stream, buffer)) 71 | return stream; 72 | } 73 | catch { } 74 | 75 | if(stream != null) 76 | { 77 | stream.Dispose(); 78 | stream = null; 79 | } 80 | 81 | try 82 | { 83 | fs.Position = 0; 84 | stream = new DeflateStream(fs, CompressionMode.Decompress, true); 85 | 86 | if(CheckPrefix(stream, buffer)) 87 | return stream; 88 | } 89 | catch { } 90 | 91 | if(stream != null) 92 | { 93 | stream.Dispose(); 94 | stream = null; 95 | } 96 | 97 | throw new FormatException("Неверный формат файла"); 98 | } 99 | 100 | // ********************************************************************** 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /QScalp/Internals/StreamType.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | namespace QScalp.History 13 | { 14 | // ************************************************************************ 15 | 16 | enum StreamType 17 | { 18 | Quotes = 0x10, 19 | Deals = 0x20, 20 | OwnOrders = 0x30, 21 | OwnTrades = 0x40, 22 | Messages = 0x50, 23 | AuxInfo = 0x60, 24 | OrdLog = 0x70, 25 | None = 0 26 | } 27 | 28 | // ************************************************************************ 29 | } 30 | -------------------------------------------------------------------------------- /QScalp/Internals/ULeb128.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System.IO; 13 | 14 | namespace QScalp.History.Internals 15 | { 16 | static class ULeb128 17 | { 18 | // ********************************************************************** 19 | 20 | public const uint Max1BValue = 127; 21 | public const uint Max2BValue = 16383; 22 | public const uint Max3BValue = 2097151; 23 | public const uint Max4BValue = 268435455; 24 | 25 | // ********************************************************************** 26 | 27 | public static void Write(Stream stream, uint value) 28 | { 29 | while(value > 127) 30 | { 31 | stream.WriteByte((byte)(value | 0x80)); 32 | value >>= 7; 33 | } 34 | 35 | stream.WriteByte((byte)value); 36 | } 37 | 38 | // ********************************************************************** 39 | 40 | public static uint Read(Stream stream) 41 | { 42 | uint value = 0; 43 | int shift = 0; 44 | 45 | for(; ; ) 46 | { 47 | uint b = (uint)stream.ReadByte(); 48 | 49 | if(b == 0xffffffff) 50 | throw new EndOfStreamException(); 51 | 52 | value |= (b & 0x7f) << shift; 53 | 54 | if((b & 0x80) == 0) 55 | return value; 56 | 57 | shift += 7; 58 | } 59 | } 60 | 61 | // ********************************************************************** 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /QScalp/RawQuotes.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System.Collections.Generic; 13 | 14 | namespace QScalp.Shared 15 | { 16 | sealed class RawQuotes : SortedDictionary 17 | { 18 | // ********************************************************************** 19 | 20 | sealed class PriceComparer : IComparer 21 | { 22 | int IComparer.Compare(int x, int y) 23 | { 24 | if(x > y) 25 | return -1; 26 | 27 | if(x < y) 28 | return 1; 29 | 30 | return 0; 31 | } 32 | } 33 | 34 | // ********************************************************************** 35 | 36 | public RawQuotes() : base(new PriceComparer()) { } 37 | 38 | // ********************************************************************** 39 | 40 | public Quote[] GetQuotes() 41 | { 42 | Quote[] quotes = new Quote[this.Count]; 43 | 44 | SortedDictionary.Enumerator enumerator = this.GetEnumerator(); 45 | int index = -1; 46 | 47 | while(enumerator.MoveNext()) 48 | { 49 | KeyValuePair kvp = enumerator.Current; 50 | 51 | if(kvp.Value > 0) 52 | { 53 | index++; 54 | quotes[index] = new Quote(kvp.Key, kvp.Value, QuoteType.Ask); 55 | } 56 | else if(kvp.Value < 0) 57 | { 58 | if(index >= 0) 59 | quotes[index].Type = QuoteType.BestAsk; 60 | 61 | index++; 62 | quotes[index] = new Quote(kvp.Key, -kvp.Value, QuoteType.BestBid); 63 | 64 | while(enumerator.MoveNext()) 65 | { 66 | kvp = enumerator.Current; 67 | 68 | if(kvp.Value < 0) 69 | { 70 | index++; 71 | quotes[index] = new Quote(kvp.Key, -kvp.Value, QuoteType.Bid); 72 | } 73 | } 74 | 75 | return quotes; 76 | } 77 | } 78 | 79 | if(index >= 0) 80 | quotes[index].Type = QuoteType.BestAsk; 81 | 82 | return quotes; 83 | } 84 | 85 | // ********************************************************************** 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /QScalp/Reader/IQshStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp.History.Reader 15 | { 16 | // ************************************************************************ 17 | 18 | interface IQshStream { StreamType Type { get; } } 19 | interface ISecurityStream : IQshStream { Security Security { get; } } 20 | 21 | interface IQuotesStream : ISecurityStream { event Action Handler; } 22 | interface IDealsStream : ISecurityStream { event Action Handler; } 23 | interface IOwnOrdersStream : ISecurityStream { event Action Handler; } 24 | interface IOwnTradesStream : ISecurityStream { event Action Handler; } 25 | interface IMessagesStream : IQshStream { event Action Handler; } 26 | interface IAuxInfoStream : ISecurityStream { event Action Handler; } 27 | interface IOrdLogStream : ISecurityStream { event Action Handler; } 28 | 29 | // ************************************************************************ 30 | } 31 | -------------------------------------------------------------------------------- /QScalp/Reader/QshReader.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.IO; 14 | 15 | using QScalp.History.Internals; 16 | 17 | namespace QScalp.History.Reader 18 | { 19 | abstract class QshReader : IDisposable 20 | { 21 | // ********************************************************************** 22 | 23 | public static QshReader Open(string path) 24 | { 25 | FileStream fs = null; 26 | 27 | try 28 | { 29 | fs = new FileStream(path, FileMode.Open, FileAccess.Read); 30 | 31 | Stream ds = QshFile.GetDataStream(fs); 32 | int version = ds.ReadByte(); 33 | 34 | switch(version) 35 | { 36 | case 4: return new V4.QshReaderImpl(fs, ds); 37 | 38 | default: 39 | throw new FormatException("Неподдерживаемая версия файла (" + version + ")"); 40 | } 41 | } 42 | catch 43 | { 44 | if(fs != null) 45 | fs.Dispose(); 46 | 47 | throw; 48 | } 49 | } 50 | 51 | // ********************************************************************** 52 | 53 | readonly FileStream fs; 54 | 55 | // ********************************************************************** 56 | 57 | public long FileSize { get { return fs.Length; } } 58 | public long FilePosition { get { return fs.Position; } } 59 | 60 | public string AppName { get; protected set; } 61 | public string Comment { get; protected set; } 62 | public DateTime RecDateTime { get; protected set; } 63 | 64 | public abstract int StreamCount { get; } 65 | public abstract IQshStream this[int i] { get; } 66 | 67 | public DateTime CurrentDateTime { get; protected set; } 68 | public int CurrentStreamIndex { get; protected set; } 69 | 70 | // ********************************************************************** 71 | 72 | protected QshReader(FileStream fs) 73 | { 74 | this.fs = fs; 75 | } 76 | 77 | // ********************************************************************** 78 | 79 | public virtual void Dispose() 80 | { 81 | if(fs != null) 82 | fs.Dispose(); 83 | } 84 | 85 | // ********************************************************************** 86 | 87 | public abstract void Read(bool push); 88 | 89 | // ********************************************************************** 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/AuxInfoStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class AuxInfoStream : QshStream, IAuxInfoStream 18 | { 19 | // ********************************************************************** 20 | 21 | long lastMilliseconds; 22 | int lastAskTotal; 23 | int lastBidTotal; 24 | int lastOI; 25 | int lastPrice; 26 | int lastHiLimit; 27 | int lastLoLimit; 28 | double lastDeposit; 29 | double lastRate; 30 | 31 | // ********************************************************************** 32 | 33 | public Security Security { get; private set; } 34 | public event Action Handler; 35 | 36 | // ********************************************************************** 37 | 38 | public AuxInfoStream(DataReader dr) 39 | : base(StreamType.AuxInfo, dr) 40 | { 41 | Security = new Security(dr.ReadString()); 42 | } 43 | 44 | // ********************************************************************** 45 | 46 | public override void Read(bool push) 47 | { 48 | AuxInfoFlags flags = (AuxInfoFlags)dr.ReadByte(); 49 | string message; 50 | 51 | // ------------------------------------------------------------ 52 | 53 | if((flags & AuxInfoFlags.DateTime) != 0) 54 | lastMilliseconds = dr.ReadGrowing(lastMilliseconds); 55 | 56 | if((flags & AuxInfoFlags.AskTotal) != 0) 57 | lastAskTotal += (int)dr.ReadLeb128(); 58 | 59 | if((flags & AuxInfoFlags.BidTotal) != 0) 60 | lastBidTotal += (int)dr.ReadLeb128(); 61 | 62 | if((flags & AuxInfoFlags.OI) != 0) 63 | lastOI += (int)dr.ReadLeb128(); 64 | 65 | if((flags & AuxInfoFlags.Price) != 0) 66 | lastPrice += (int)dr.ReadLeb128(); 67 | 68 | if((flags & AuxInfoFlags.SessionInfo) != 0) 69 | { 70 | lastHiLimit = (int)dr.ReadLeb128(); 71 | lastLoLimit = (int)dr.ReadLeb128(); 72 | lastDeposit = dr.ReadDouble(); 73 | } 74 | 75 | if((flags & AuxInfoFlags.Rate) != 0) 76 | lastRate = dr.ReadDouble(); 77 | 78 | if((flags & AuxInfoFlags.Message) != 0) 79 | message = dr.ReadString(); 80 | else 81 | message = null; 82 | 83 | // ------------------------------------------------------------ 84 | 85 | if(push && Handler != null) 86 | Handler(new AuxInfo( 87 | DateTimeHelper.FromMs(lastMilliseconds), 88 | lastPrice, lastAskTotal, lastBidTotal, 89 | lastOI, lastHiLimit, lastLoLimit, 90 | lastDeposit, lastRate, message)); 91 | } 92 | 93 | // ********************************************************************** 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/DataReader.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System.IO; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class DataReader : BinaryReader 18 | { 19 | // ********************************************************************** 20 | 21 | public DataReader(Stream stream) : base(stream) { } 22 | 23 | // ********************************************************************** 24 | 25 | public long ReadGrowing(long lastValue) 26 | { 27 | uint offset = ULeb128.Read(BaseStream); 28 | 29 | if(offset == ULeb128.Max4BValue) 30 | return lastValue + Leb128.Read(BaseStream); 31 | else 32 | return lastValue + offset; 33 | } 34 | 35 | // ********************************************************************** 36 | 37 | public long ReadLeb128() { return Leb128.Read(BaseStream); } 38 | 39 | // ********************************************************************** 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/DealsStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class DealsStream : QshStream, IDealsStream 18 | { 19 | // ********************************************************************** 20 | 21 | long lastMilliseconds; 22 | long lastId; 23 | long lastOrderId; 24 | int lastPrice; 25 | int lastVolume; 26 | int lastOI; 27 | 28 | // ********************************************************************** 29 | 30 | public Security Security { get; private set; } 31 | public event Action Handler; 32 | 33 | // ********************************************************************** 34 | 35 | public DealsStream(DataReader dr) 36 | : base(StreamType.Deals, dr) 37 | { 38 | Security = new Security(dr.ReadString()); 39 | } 40 | 41 | // ********************************************************************** 42 | 43 | public override void Read(bool push) 44 | { 45 | DealFlags flags = (DealFlags)dr.ReadByte(); 46 | 47 | // ------------------------------------------------------------ 48 | 49 | if((flags & DealFlags.DateTime) != 0) 50 | lastMilliseconds = dr.ReadGrowing(lastMilliseconds); 51 | 52 | if((flags & DealFlags.Id) != 0) 53 | lastId = dr.ReadGrowing(lastId); 54 | 55 | if((flags & DealFlags.OrderId) != 0) 56 | lastOrderId += dr.ReadLeb128(); 57 | 58 | if((flags & DealFlags.Price) != 0) 59 | lastPrice += (int)dr.ReadLeb128(); 60 | 61 | if((flags & DealFlags.Volume) != 0) 62 | lastVolume = (int)dr.ReadLeb128(); 63 | 64 | if((flags & DealFlags.OI) != 0) 65 | lastOI += (int)dr.ReadLeb128(); 66 | 67 | // ------------------------------------------------------------ 68 | 69 | if(push && Handler != null) 70 | Handler(new Deal() 71 | { 72 | DateTime = DateTimeHelper.FromMs(lastMilliseconds), 73 | Id = lastId, 74 | OrderId = lastOrderId, 75 | Type = (DealType)(flags & DealFlags.Type), 76 | Price = lastPrice, 77 | Volume = lastVolume, 78 | OI = lastOI 79 | }); 80 | } 81 | 82 | // ********************************************************************** 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/MessagesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp.History.Reader.V4 15 | { 16 | sealed class MessagesStream : QshStream, IMessagesStream 17 | { 18 | // ********************************************************************** 19 | 20 | public event Action Handler; 21 | 22 | // ********************************************************************** 23 | 24 | public MessagesStream(DataReader dr) : base(StreamType.Messages, dr) { } 25 | 26 | // ********************************************************************** 27 | 28 | public override void Read(bool push) 29 | { 30 | Message msg = new Message(new DateTime(dr.ReadInt64()), 31 | (MessageType)dr.ReadByte(), dr.ReadString()); 32 | 33 | if(push && Handler != null) 34 | Handler(msg); 35 | } 36 | 37 | // ********************************************************************** 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/OrdLogStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2018 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | using QScalp.History.Internals; 16 | using QScalp.Shared; 17 | 18 | namespace QScalp.History.Reader.V4 19 | { 20 | sealed class OrdLogStream : QshStream, IOrdLogStream, IQuotesStream, IDealsStream, IAuxInfoStream 21 | { 22 | // ********************************************************************** 23 | 24 | readonly RawQuotes rawQuotes; 25 | 26 | Action quotesHandler; 27 | Action dealHandler; 28 | Action auxInfoHandler; 29 | 30 | long lastPushedDealId; 31 | 32 | // ********************************************************************** 33 | 34 | long lastMilliseconds; 35 | long lastOrderId; 36 | 37 | int lastPrice; 38 | 39 | int lastAmount; 40 | int lastAmountRest; 41 | 42 | long lastDealId; 43 | int lastDealPrice; 44 | int lastOI; 45 | 46 | // ********************************************************************** 47 | 48 | public Security Security { get; private set; } 49 | public event Action Handler; 50 | 51 | // ********************************************************************** 52 | 53 | event Action IQuotesStream.Handler 54 | { 55 | add { quotesHandler += value; } 56 | remove { quotesHandler -= value; } 57 | } 58 | 59 | event Action IDealsStream.Handler 60 | { 61 | add { dealHandler += value; } 62 | remove { dealHandler -= value; } 63 | } 64 | 65 | event Action IAuxInfoStream.Handler 66 | { 67 | add { auxInfoHandler += value; } 68 | remove { auxInfoHandler -= value; } 69 | } 70 | 71 | // ********************************************************************** 72 | 73 | public OrdLogStream(DataReader dr) 74 | : base(StreamType.OrdLog, dr) 75 | { 76 | Security = new Security(dr.ReadString()); 77 | rawQuotes = new RawQuotes(); 78 | } 79 | 80 | // ********************************************************************** 81 | 82 | public override void Read(bool push) 83 | { 84 | DateTime dateTime; 85 | long orderId; 86 | int amountRest; 87 | long dealId; 88 | int dealPrice; 89 | int oi; 90 | 91 | // ------------------------------------------------------------ 92 | 93 | OrdLogEntryFlags flags = (OrdLogEntryFlags)dr.ReadByte(); 94 | OrdLogFlags ordLogFlags = (OrdLogFlags)dr.ReadUInt16(); 95 | 96 | bool isAdd = (ordLogFlags & OrdLogFlags.Add) != 0; 97 | bool isFill = (ordLogFlags & OrdLogFlags.Fill) != 0; 98 | 99 | bool isBuy = (ordLogFlags & OrdLogFlags.Buy) != 0; 100 | bool isSell = (ordLogFlags & OrdLogFlags.Sell) != 0; 101 | 102 | // ------------------------------------------------------------ 103 | 104 | if((flags & OrdLogEntryFlags.DateTime) != 0) 105 | lastMilliseconds = dr.ReadGrowing(lastMilliseconds); 106 | 107 | dateTime = DateTimeHelper.FromMs(lastMilliseconds); 108 | 109 | if((flags & OrdLogEntryFlags.OrderId) == 0) 110 | orderId = lastOrderId; 111 | else if(isAdd) 112 | orderId = lastOrderId = dr.ReadGrowing(lastOrderId); 113 | else 114 | orderId = lastOrderId + dr.ReadLeb128(); 115 | 116 | if((flags & OrdLogEntryFlags.Price) != 0) 117 | lastPrice += (int)dr.ReadLeb128(); 118 | 119 | if((flags & OrdLogEntryFlags.Amount) != 0) 120 | lastAmount = (int)dr.ReadLeb128(); 121 | 122 | if(isFill) 123 | { 124 | if((flags & OrdLogEntryFlags.AmountRest) != 0) 125 | amountRest = lastAmountRest = (int)dr.ReadLeb128(); 126 | else 127 | amountRest = lastAmountRest; 128 | 129 | if((flags & OrdLogEntryFlags.DealId) != 0) 130 | dealId = lastDealId = dr.ReadGrowing(lastDealId); 131 | else 132 | dealId = lastDealId; 133 | 134 | if((flags & OrdLogEntryFlags.DealPrice) != 0) 135 | dealPrice = lastDealPrice += (int)dr.ReadLeb128(); 136 | else 137 | dealPrice = lastDealPrice; 138 | 139 | if((flags & OrdLogEntryFlags.OI) != 0) 140 | oi = lastOI += (int)dr.ReadLeb128(); 141 | else 142 | oi = lastOI; 143 | } 144 | else 145 | { 146 | amountRest = isAdd ? lastAmount : 0; 147 | dealId = 0; 148 | dealPrice = 0; 149 | oi = 0; 150 | } 151 | 152 | // ------------------------------------------------------------ 153 | 154 | if(Handler != null && push) 155 | Handler(new OrdLogEntry( 156 | ordLogFlags, dateTime, orderId, lastPrice, 157 | lastAmount, amountRest, dealId, dealPrice, oi)); 158 | 159 | // ------------------------------------------------------------ 160 | 161 | if((ordLogFlags & OrdLogFlags.FlowStart) != 0) 162 | rawQuotes.Clear(); 163 | 164 | if(!(isBuy ^ isSell) 165 | || (ordLogFlags & OrdLogFlags.NonSystem) != 0 166 | || (ordLogFlags & OrdLogFlags.NonZeroReplAct) != 0) 167 | { 168 | return; 169 | } 170 | 171 | // ------------------------------------------------------------ 172 | 173 | int quantity; 174 | rawQuotes.TryGetValue(lastPrice, out quantity); 175 | 176 | if(isAdd ? isSell : isBuy) 177 | quantity += lastAmount; 178 | else 179 | quantity -= lastAmount; 180 | 181 | if(quantity == 0) 182 | rawQuotes.Remove(lastPrice); 183 | else 184 | rawQuotes[lastPrice] = quantity; 185 | 186 | // ------------------------------------------------------------ 187 | 188 | if(push) 189 | { 190 | if((ordLogFlags & OrdLogFlags.EndOfTransaction) != 0) 191 | { 192 | // В большинстве случаев нет необходимости делать все, 193 | // что в этом блоке, на каждый тик. Целесообразнее 194 | // отправлять эти данные по таймеру, раз в 5-15 мс. 195 | 196 | if(quotesHandler != null) 197 | quotesHandler(rawQuotes.GetQuotes()); 198 | 199 | if(auxInfoHandler != null) 200 | { 201 | int askTotal = 0; 202 | int bidTotal = 0; 203 | 204 | foreach(KeyValuePair kvp in rawQuotes) 205 | if(kvp.Value > 0) 206 | askTotal += kvp.Value; 207 | else 208 | bidTotal -= kvp.Value; 209 | 210 | auxInfoHandler(new AuxInfo( 211 | dateTime, lastDealPrice, askTotal, 212 | bidTotal, lastOI, 0, 0, 0, 0, null)); 213 | } 214 | } 215 | 216 | if(lastPushedDealId < dealId) 217 | { 218 | if(dealHandler != null) 219 | dealHandler(new Deal() 220 | { 221 | Type = isSell ? DealType.Sell : DealType.Buy, 222 | Id = dealId, 223 | DateTime = dateTime, 224 | Price = dealPrice, 225 | Volume = lastAmount, 226 | OI = oi 227 | }); 228 | 229 | lastPushedDealId = dealId; 230 | } 231 | } 232 | } 233 | 234 | // ********************************************************************** 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/OwnOrdersStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class OwnOrdersStream : QshStream, IOwnOrdersStream 18 | { 19 | // ********************************************************************** 20 | 21 | public Security Security { get; private set; } 22 | public event Action Handler; 23 | 24 | // ********************************************************************** 25 | 26 | public OwnOrdersStream(DataReader dr) 27 | : base(StreamType.OwnOrders, dr) 28 | { 29 | Security = new Security(dr.ReadString()); 30 | } 31 | 32 | // ********************************************************************** 33 | 34 | public override void Read(bool push) 35 | { 36 | OrderFlags flags = (OrderFlags)dr.ReadByte(); 37 | OwnOrder order; 38 | 39 | if((flags & OrderFlags.DropAll) != 0) 40 | order = new OwnOrder(); 41 | else 42 | { 43 | OwnOrderType type; 44 | 45 | if((flags & OrderFlags.Active) != 0) 46 | { 47 | if((flags & OrderFlags.Stop) != 0) 48 | type = OwnOrderType.Stop; 49 | else 50 | type = OwnOrderType.Regular; 51 | } 52 | else 53 | type = OwnOrderType.None; 54 | 55 | order = new OwnOrder(type, dr.ReadLeb128(), 56 | (int)dr.ReadLeb128(), (int)dr.ReadLeb128()); 57 | } 58 | 59 | if(push && Handler != null) 60 | Handler(order); 61 | } 62 | 63 | // ********************************************************************** 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/OwnTradesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class OwnTradesStream : QshStream, IOwnTradesStream 18 | { 19 | // ********************************************************************** 20 | 21 | long lastMilliseconds; 22 | long lastTradeId; 23 | long lastOrderId; 24 | int lastPrice; 25 | 26 | // ********************************************************************** 27 | 28 | public Security Security { get; private set; } 29 | public event Action Handler; 30 | 31 | // ********************************************************************** 32 | 33 | public OwnTradesStream(DataReader dr) 34 | : base(StreamType.OwnTrades, dr) 35 | { 36 | Security = new Security(dr.ReadString()); 37 | } 38 | 39 | // ********************************************************************** 40 | 41 | public override void Read(bool push) 42 | { 43 | lastMilliseconds = dr.ReadGrowing(lastMilliseconds); 44 | 45 | lastTradeId += dr.ReadLeb128(); 46 | lastOrderId += dr.ReadLeb128(); 47 | lastPrice += (int)dr.ReadLeb128(); 48 | 49 | int quantity = (int)dr.ReadLeb128(); 50 | 51 | if(push && Handler != null) 52 | Handler(new OwnTrade( 53 | OwnTradeSource.History, DateTimeHelper.FromMs(lastMilliseconds), 54 | lastTradeId, lastOrderId, lastPrice, quantity)); 55 | } 56 | 57 | // ********************************************************************** 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/QshReaderImpl.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.IO; 14 | 15 | using QScalp.History.Internals; 16 | 17 | namespace QScalp.History.Reader.V4 18 | { 19 | sealed class QshReaderImpl : QshReader 20 | { 21 | // ********************************************************************** 22 | 23 | readonly DataReader dr; 24 | readonly QshStream[] streams; 25 | 26 | QshStream currentStream; 27 | long lastMilliseconds; 28 | 29 | // ********************************************************************** 30 | 31 | public override int StreamCount { get { return streams.Length; } } 32 | public override IQshStream this[int i] { get { return streams[i]; } } 33 | 34 | // ********************************************************************** 35 | 36 | public QshReaderImpl(FileStream fs, Stream ds) 37 | : base(fs) 38 | { 39 | dr = new DataReader(ds); 40 | 41 | AppName = dr.ReadString(); 42 | Comment = dr.ReadString(); 43 | RecDateTime = new DateTime(dr.ReadInt64(), DateTimeKind.Utc); 44 | 45 | lastMilliseconds = DateTimeHelper.ToMs(RecDateTime); 46 | 47 | int streamCount = dr.ReadByte(); 48 | 49 | if(streamCount == 0) 50 | throw new Exception("Нет потоков данных"); 51 | 52 | streams = new QshStream[streamCount]; 53 | 54 | for(int i = 0; i < streams.Length; i++) 55 | { 56 | StreamType st = (StreamType)dr.ReadByte(); 57 | 58 | switch(st) 59 | { 60 | case StreamType.Quotes: 61 | streams[i] = new QuotesStream(dr); 62 | break; 63 | 64 | case StreamType.Deals: 65 | streams[i] = new DealsStream(dr); 66 | break; 67 | 68 | case StreamType.OwnOrders: 69 | streams[i] = new OwnOrdersStream(dr); 70 | break; 71 | 72 | case StreamType.OwnTrades: 73 | streams[i] = new OwnTradesStream(dr); 74 | break; 75 | 76 | case StreamType.Messages: 77 | streams[i] = new MessagesStream(dr); 78 | break; 79 | 80 | case StreamType.AuxInfo: 81 | streams[i] = new AuxInfoStream(dr); 82 | break; 83 | 84 | case StreamType.OrdLog: 85 | streams[i] = new OrdLogStream(dr); 86 | break; 87 | 88 | default: 89 | throw new FormatException("Неизвестный тип данных: " + st); 90 | } 91 | } 92 | 93 | if(streams.Length == 1) 94 | currentStream = streams[0]; 95 | 96 | ReadNextRecordHeader(); 97 | } 98 | 99 | // ********************************************************************** 100 | 101 | void ReadNextRecordHeader() 102 | { 103 | try 104 | { 105 | lastMilliseconds = dr.ReadGrowing(lastMilliseconds); 106 | CurrentDateTime = DateTimeHelper.FromMs(lastMilliseconds); 107 | 108 | if(streams.Length > 1) 109 | { 110 | CurrentStreamIndex = dr.ReadByte(); 111 | currentStream = streams[CurrentStreamIndex]; 112 | } 113 | } 114 | catch(EndOfStreamException) 115 | { 116 | CurrentDateTime = DateTime.MaxValue; 117 | } 118 | } 119 | 120 | // ********************************************************************** 121 | 122 | public override void Read(bool push) 123 | { 124 | currentStream.Read(push); 125 | ReadNextRecordHeader(); 126 | } 127 | 128 | // ********************************************************************** 129 | 130 | public override void Dispose() 131 | { 132 | if(dr != null) 133 | dr.Dispose(); 134 | 135 | base.Dispose(); 136 | } 137 | 138 | // ********************************************************************** 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/QshStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | namespace QScalp.History.Reader.V4 13 | { 14 | abstract class QshStream : IQshStream 15 | { 16 | // ********************************************************************** 17 | 18 | public StreamType Type { get; private set; } 19 | 20 | // ********************************************************************** 21 | 22 | protected readonly DataReader dr; 23 | 24 | // ********************************************************************** 25 | 26 | protected QshStream(StreamType type, DataReader dr) 27 | { 28 | this.Type = type; 29 | this.dr = dr; 30 | } 31 | 32 | // ********************************************************************** 33 | 34 | public abstract void Read(bool push); 35 | 36 | // ********************************************************************** 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /QScalp/Reader/V4/QuotesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.Shared; 14 | 15 | namespace QScalp.History.Reader.V4 16 | { 17 | sealed class QuotesStream : QshStream, IQuotesStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly RawQuotes rawQuotes; 22 | int lastPrice; 23 | 24 | // ********************************************************************** 25 | 26 | public Security Security { get; private set; } 27 | public event Action Handler; 28 | 29 | // ********************************************************************** 30 | 31 | public QuotesStream(DataReader dr) 32 | : base(StreamType.Quotes, dr) 33 | { 34 | Security = new Security(dr.ReadString()); 35 | rawQuotes = new RawQuotes(); 36 | } 37 | 38 | // ********************************************************************** 39 | 40 | public override void Read(bool push) 41 | { 42 | int n = (int)dr.ReadLeb128(); 43 | 44 | for(int i = 0; i < n; i++) 45 | { 46 | lastPrice += (int)dr.ReadLeb128(); 47 | int v = (int)dr.ReadLeb128(); 48 | 49 | if(v == 0) 50 | rawQuotes.Remove(lastPrice); 51 | else 52 | rawQuotes[lastPrice] = v; 53 | } 54 | 55 | if(push && Handler != null) 56 | Handler(rawQuotes.GetQuotes()); 57 | } 58 | 59 | // ********************************************************************** 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /QScalp/Security.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.Globalization; 14 | 15 | namespace QScalp 16 | { 17 | sealed class Security 18 | { 19 | // ********************************************************************** 20 | 21 | const int stepRoundDigits = 14; 22 | static readonly char[] sep = new char[] { ':' }; 23 | 24 | double step, inverseStep; 25 | 26 | NumberFormatInfo priceFormat; 27 | 28 | // ********************************************************************** 29 | 30 | public string Entry { get; private set; } 31 | 32 | public string CName { get; private set; } 33 | public string Ticker { get; private set; } 34 | public string AuxCode { get; private set; } 35 | public int Id { get; private set; } 36 | 37 | public double Step 38 | { 39 | get { return step; } 40 | 41 | private set 42 | { 43 | if(value > 0) 44 | step = Math.Round(value, stepRoundDigits); 45 | else 46 | step = 1; 47 | 48 | inverseStep = 1 / step; 49 | 50 | double d = step; 51 | int precision = 0; 52 | 53 | while(d != (int)(d) && precision <= stepRoundDigits) 54 | { 55 | d = Math.Round(d * 10, stepRoundDigits); 56 | precision++; 57 | } 58 | 59 | priceFormat.NumberDecimalDigits = precision; 60 | } 61 | } 62 | 63 | // ********************************************************************** 64 | 65 | public Security(string entry) 66 | { 67 | priceFormat = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone(); 68 | 69 | if(string.IsNullOrEmpty(entry)) 70 | { 71 | this.Entry = string.Empty; 72 | Reset(string.Empty); 73 | return; 74 | } 75 | 76 | this.Entry = entry; 77 | 78 | string[] s = entry.Split(sep); 79 | 80 | if(s.Length == 5) 81 | { 82 | CName = s[0]; 83 | Ticker = s[1]; 84 | AuxCode = s[2]; 85 | 86 | int id = 0; 87 | 88 | bool error = s[3].Length > 0 && !int.TryParse(s[3], 89 | NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out id); 90 | 91 | Id = id; 92 | 93 | if(double.TryParse(s[4], NumberStyles.Float, 94 | NumberFormatInfo.InvariantInfo, out step)) 95 | { 96 | Step = step; 97 | } 98 | else 99 | { 100 | Step = 1; 101 | error = true; 102 | } 103 | 104 | if(error) 105 | Ticker = "{" + Ticker + "}"; 106 | } 107 | else 108 | Reset("{err}"); 109 | } 110 | 111 | // ********************************************************************** 112 | 113 | void Reset(string state) 114 | { 115 | CName = Ticker = state; 116 | AuxCode = string.Empty; 117 | Id = 0; 118 | Step = 1; 119 | } 120 | 121 | // ********************************************************************** 122 | 123 | public override string ToString() 124 | { 125 | if(Entry.Length == 0) 126 | return string.Empty; 127 | 128 | return CName + " / " + Ticker 129 | + (AuxCode.Length == 0 ? string.Empty : " " + AuxCode) 130 | + (Id == 0 ? string.Empty : " " + Id) + ", " 131 | + GetPrice(1).ToString("N", priceFormat) + " пт"; 132 | } 133 | 134 | // ********************************************************************** 135 | 136 | public int GetTicks(double price) 137 | { 138 | return (int)Math.Round(price * inverseStep); 139 | } 140 | 141 | // ********************************************************************** 142 | 143 | public double GetPrice(double ticks) { return ticks * Step; } 144 | 145 | // ********************************************************************** 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /QScalp/Writer/AuxInfoStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class AuxInfoStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly DataWriter dw; 22 | readonly int sid; 23 | 24 | // ********************************************************************** 25 | 26 | long lastMilliseconds; 27 | int lastAskTotal; 28 | int lastBidTotal; 29 | int lastOI; 30 | int lastPrice; 31 | int lastHiLimit; 32 | int lastLoLimit; 33 | double lastDeposit; 34 | double lastRate; 35 | 36 | // ********************************************************************** 37 | 38 | public AuxInfoStream(DataWriter dw, int sid, Security s) 39 | { 40 | this.dw = dw; 41 | this.sid = sid; 42 | 43 | dw.Write((byte)StreamType.AuxInfo); 44 | dw.Write(s.Entry); 45 | } 46 | 47 | // ********************************************************************** 48 | 49 | public void Write(DateTime dateTime, AuxInfo auxInfo) 50 | { 51 | dw.WriteRecHeader(sid, dateTime); 52 | 53 | // -------------------------------------------------- 54 | 55 | long milliseconds = DateTimeHelper.ToMs(auxInfo.DateTime); 56 | AuxInfoFlags flags = AuxInfoFlags.None; 57 | 58 | // -------------------------------------------------- 59 | 60 | if(lastMilliseconds != milliseconds) 61 | flags |= AuxInfoFlags.DateTime; 62 | 63 | if(lastAskTotal != auxInfo.AskTotal) 64 | flags |= AuxInfoFlags.AskTotal; 65 | 66 | if(lastBidTotal != auxInfo.BidTotal) 67 | flags |= AuxInfoFlags.BidTotal; 68 | 69 | if(lastOI != auxInfo.OI) 70 | flags |= AuxInfoFlags.OI; 71 | 72 | if(lastPrice != auxInfo.Price) 73 | flags |= AuxInfoFlags.Price; 74 | 75 | if(lastHiLimit != auxInfo.HiLimit 76 | || lastLoLimit != auxInfo.LoLimit 77 | || lastDeposit != auxInfo.Deposit) 78 | { 79 | flags |= AuxInfoFlags.SessionInfo; 80 | } 81 | 82 | if(lastRate != auxInfo.Rate) 83 | flags |= AuxInfoFlags.Rate; 84 | 85 | if(auxInfo.Message != null) 86 | flags |= AuxInfoFlags.Message; 87 | 88 | // -------------------------------------------------- 89 | 90 | dw.Write((byte)flags); 91 | 92 | // -------------------------------------------------- 93 | 94 | if((flags & AuxInfoFlags.DateTime) != 0) 95 | dw.WriteGrowing(milliseconds, ref lastMilliseconds); 96 | 97 | if((flags & AuxInfoFlags.AskTotal) != 0) 98 | { 99 | dw.WriteLeb128(auxInfo.AskTotal - lastAskTotal); 100 | lastAskTotal = auxInfo.AskTotal; 101 | } 102 | 103 | if((flags & AuxInfoFlags.BidTotal) != 0) 104 | { 105 | dw.WriteLeb128(auxInfo.BidTotal - lastBidTotal); 106 | lastBidTotal = auxInfo.BidTotal; 107 | } 108 | 109 | if((flags & AuxInfoFlags.OI) != 0) 110 | { 111 | dw.WriteLeb128(auxInfo.OI - lastOI); 112 | lastOI = auxInfo.OI; 113 | } 114 | 115 | if((flags & AuxInfoFlags.Price) != 0) 116 | { 117 | dw.WriteLeb128(auxInfo.Price - lastPrice); 118 | lastPrice = auxInfo.Price; 119 | } 120 | 121 | if((flags & AuxInfoFlags.SessionInfo) != 0) 122 | { 123 | dw.WriteLeb128(auxInfo.HiLimit); 124 | dw.WriteLeb128(auxInfo.LoLimit); 125 | dw.Write(auxInfo.Deposit); 126 | 127 | lastHiLimit = auxInfo.HiLimit; 128 | lastLoLimit = auxInfo.LoLimit; 129 | lastDeposit = auxInfo.Deposit; 130 | } 131 | 132 | if((flags & AuxInfoFlags.Rate) != 0) 133 | { 134 | dw.Write(auxInfo.Rate); 135 | lastRate = auxInfo.Rate; 136 | } 137 | 138 | if((flags & AuxInfoFlags.Message) != 0) 139 | dw.Write(auxInfo.Message); 140 | 141 | // -------------------------------------------------- 142 | } 143 | 144 | // ********************************************************************** 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /QScalp/Writer/DataWriter.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.IO; 14 | 15 | using QScalp.History.Internals; 16 | 17 | namespace QScalp.History.Writer 18 | { 19 | sealed class DataWriter : BinaryWriter 20 | { 21 | // ********************************************************************** 22 | 23 | readonly bool multistreamed; 24 | long lastMilliseconds; 25 | 26 | // ********************************************************************** 27 | 28 | public int RecordCount { get; private set; } 29 | 30 | // ********************************************************************** 31 | 32 | public DataWriter(Stream output, DateTime recDateTime, bool multistreamed) 33 | : base(output) 34 | { 35 | this.lastMilliseconds = DateTimeHelper.ToMs(recDateTime); 36 | this.multistreamed = multistreamed; 37 | } 38 | 39 | // ********************************************************************** 40 | 41 | public void WriteRecHeader(int sid, DateTime dateTime) 42 | { 43 | WriteGrowing(DateTimeHelper.ToMs(dateTime), ref lastMilliseconds); 44 | 45 | if(multistreamed) 46 | Write((byte)sid); 47 | 48 | RecordCount++; 49 | } 50 | 51 | // ********************************************************************** 52 | 53 | public void WriteLeb128(long value) { Leb128.Write(BaseStream, value); } 54 | 55 | // ********************************************************************** 56 | 57 | public void WriteGrowing(long value, ref long lastValue) 58 | { 59 | long offset = value - lastValue; 60 | 61 | if(offset >= ULeb128.Max4BValue || offset < 0) 62 | { 63 | ULeb128.Write(BaseStream, ULeb128.Max4BValue); 64 | Leb128.Write(BaseStream, offset); 65 | } 66 | else 67 | ULeb128.Write(BaseStream, (uint)offset); 68 | 69 | lastValue = value; 70 | } 71 | 72 | // ********************************************************************** 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /QScalp/Writer/DealsStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class DealsStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly DataWriter dw; 22 | readonly int sid; 23 | readonly Security s; 24 | 25 | long lastMilliseconds; 26 | long lastId; 27 | long lastOrderId; 28 | int lastPrice; 29 | int lastVolume; 30 | int lastOI; 31 | 32 | // ********************************************************************** 33 | 34 | public DealsStream(DataWriter dw, int sid, Security s) 35 | { 36 | this.dw = dw; 37 | this.sid = sid; 38 | this.s = s; 39 | 40 | dw.Write((byte)StreamType.Deals); 41 | dw.Write(s.Entry); 42 | } 43 | 44 | // ********************************************************************** 45 | 46 | public void Write(DateTime dateTime, Deal deal) 47 | { 48 | dw.WriteRecHeader(sid, dateTime); 49 | 50 | // ------------------------------------------------------------ 51 | 52 | long milliseconds = DateTimeHelper.ToMs(deal.DateTime); 53 | DealFlags flags = (DealFlags)deal.Type & DealFlags.Type; 54 | 55 | if(lastMilliseconds != milliseconds) 56 | flags |= DealFlags.DateTime; 57 | 58 | if(deal.Id != 0) 59 | flags |= DealFlags.Id; 60 | 61 | if(lastOrderId != deal.OrderId) 62 | flags |= DealFlags.OrderId; 63 | 64 | if(lastPrice != deal.Price) 65 | flags |= DealFlags.Price; 66 | 67 | if(lastVolume != deal.Volume) 68 | flags |= DealFlags.Volume; 69 | 70 | if(lastOI != deal.OI) 71 | flags |= DealFlags.OI; 72 | 73 | // ------------------------------------------------------------ 74 | 75 | dw.Write((byte)flags); 76 | 77 | // ------------------------------------------------------------ 78 | 79 | if((flags & DealFlags.DateTime) != 0) 80 | dw.WriteGrowing(milliseconds, ref lastMilliseconds); 81 | 82 | if((flags & DealFlags.Id) != 0) 83 | dw.WriteGrowing(deal.Id, ref lastId); 84 | 85 | if((flags & DealFlags.OrderId) != 0) 86 | { 87 | dw.WriteLeb128(deal.OrderId - lastOrderId); 88 | lastOrderId = deal.OrderId; 89 | } 90 | 91 | if((flags & DealFlags.Price) != 0) 92 | { 93 | dw.WriteLeb128(deal.Price - lastPrice); 94 | lastPrice = deal.Price; 95 | } 96 | 97 | if((flags & DealFlags.Volume) != 0) 98 | { 99 | dw.WriteLeb128(deal.Volume); 100 | lastVolume = deal.Volume; 101 | } 102 | 103 | if((flags & DealFlags.OI) != 0) 104 | { 105 | dw.WriteLeb128(deal.OI - lastOI); 106 | lastOI = deal.OI; 107 | } 108 | 109 | // ------------------------------------------------------------ 110 | } 111 | 112 | // ********************************************************************** 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /QScalp/Writer/MessagesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | 14 | namespace QScalp.History.Writer 15 | { 16 | sealed class MessagesStream 17 | { 18 | // ********************************************************************** 19 | 20 | readonly DataWriter dw; 21 | readonly int sid; 22 | 23 | // ********************************************************************** 24 | 25 | public MessagesStream(DataWriter dw, int sid) 26 | { 27 | this.dw = dw; 28 | this.sid = sid; 29 | 30 | dw.Write((byte)StreamType.Messages); 31 | } 32 | 33 | // ********************************************************************** 34 | 35 | public void Write(DateTime dateTime, Message msg) 36 | { 37 | dw.WriteRecHeader(sid, dateTime); 38 | 39 | dw.Write(msg.DateTime.Ticks); 40 | dw.Write((byte)msg.Type); 41 | dw.Write(msg.Text); 42 | } 43 | 44 | // ********************************************************************** 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /QScalp/Writer/OrdLogStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class OrdLogStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly DataWriter dw; 22 | readonly int sid; 23 | readonly Security s; 24 | 25 | long lastMilliseconds; 26 | long lastOrderId; 27 | 28 | int lastPrice; 29 | 30 | int lastAmount; 31 | int lastAmountRest; 32 | 33 | long lastDealId; 34 | int lastDealPrice; 35 | int lastOI; 36 | 37 | // ********************************************************************** 38 | 39 | public OrdLogStream(DataWriter dw, int sid, Security s) 40 | { 41 | this.dw = dw; 42 | this.sid = sid; 43 | this.s = s; 44 | 45 | dw.Write((byte)StreamType.OrdLog); 46 | dw.Write(s.Entry); 47 | } 48 | 49 | // ********************************************************************** 50 | 51 | public void Write(DateTime dateTime, OrdLogEntry entry) 52 | { 53 | dw.WriteRecHeader(sid, dateTime); 54 | 55 | // ------------------------------------------------------------ 56 | 57 | long milliseconds = DateTimeHelper.ToMs(entry.DateTime); 58 | OrdLogEntryFlags flags = OrdLogEntryFlags.None; 59 | 60 | // ------------------------------------------------------------ 61 | 62 | if(lastMilliseconds != milliseconds) 63 | flags |= OrdLogEntryFlags.DateTime; 64 | 65 | if(lastOrderId != entry.OrderId) 66 | flags |= OrdLogEntryFlags.OrderId; 67 | 68 | if(lastPrice != entry.Price) 69 | flags |= OrdLogEntryFlags.Price; 70 | 71 | if(lastAmount != entry.Amount) 72 | flags |= OrdLogEntryFlags.Amount; 73 | 74 | if((entry.Flags & OrdLogFlags.Fill) != 0) 75 | { 76 | if(lastAmountRest != entry.AmountRest) 77 | flags |= OrdLogEntryFlags.AmountRest; 78 | 79 | if(lastDealId != entry.DealId) 80 | flags |= OrdLogEntryFlags.DealId; 81 | 82 | if(lastDealPrice != entry.DealPrice) 83 | flags |= OrdLogEntryFlags.DealPrice; 84 | 85 | if(lastOI != entry.OI) 86 | flags |= OrdLogEntryFlags.OI; 87 | } 88 | 89 | // ------------------------------------------------------------ 90 | 91 | dw.Write((byte)flags); 92 | 93 | // ------------------------------------------------------------ 94 | 95 | dw.Write((ushort)entry.Flags); 96 | 97 | if((flags & OrdLogEntryFlags.DateTime) != 0) 98 | dw.WriteGrowing(milliseconds, ref lastMilliseconds); 99 | 100 | if((flags & OrdLogEntryFlags.OrderId) != 0) 101 | { 102 | if((entry.Flags & OrdLogFlags.Add) != 0) 103 | dw.WriteGrowing(entry.OrderId, ref lastOrderId); 104 | else 105 | dw.WriteLeb128(entry.OrderId - lastOrderId); 106 | } 107 | 108 | if((flags & OrdLogEntryFlags.Price) != 0) 109 | { 110 | dw.WriteLeb128(entry.Price - lastPrice); 111 | lastPrice = entry.Price; 112 | } 113 | 114 | if((flags & OrdLogEntryFlags.Amount) != 0) 115 | { 116 | dw.WriteLeb128(entry.Amount); 117 | lastAmount = entry.Amount; 118 | } 119 | 120 | if((flags & OrdLogEntryFlags.AmountRest) != 0) 121 | { 122 | dw.WriteLeb128(entry.AmountRest); 123 | lastAmountRest = entry.AmountRest; 124 | } 125 | 126 | if((flags & OrdLogEntryFlags.DealId) != 0) 127 | dw.WriteGrowing(entry.DealId, ref lastDealId); 128 | 129 | if((flags & OrdLogEntryFlags.DealPrice) != 0) 130 | { 131 | dw.WriteLeb128(entry.DealPrice - lastDealPrice); 132 | lastDealPrice = entry.DealPrice; 133 | } 134 | 135 | if((flags & OrdLogEntryFlags.OI) != 0) 136 | { 137 | dw.WriteLeb128(entry.OI - lastOI); 138 | lastOI = entry.OI; 139 | } 140 | 141 | // ------------------------------------------------------------ 142 | } 143 | 144 | // ********************************************************************** 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /QScalp/Writer/OwnOrdersStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class OwnOrdersStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly DataWriter dw; 22 | readonly int sid; 23 | 24 | // ********************************************************************** 25 | 26 | public OwnOrdersStream(DataWriter dw, int sid, Security s) 27 | { 28 | this.dw = dw; 29 | this.sid = sid; 30 | 31 | dw.Write((byte)StreamType.OwnOrders); 32 | dw.Write(s.Entry); 33 | } 34 | 35 | // ********************************************************************** 36 | 37 | public void Write(DateTime dateTime, OwnOrder order) 38 | { 39 | dw.WriteRecHeader(sid, dateTime); 40 | 41 | if(order.Id == 0 && order.Price == 0) 42 | dw.Write((byte)OrderFlags.DropAll); 43 | else 44 | { 45 | OrderFlags flags; 46 | 47 | switch(order.Type) 48 | { 49 | case OwnOrderType.Regular: 50 | flags = OrderFlags.Active; 51 | break; 52 | 53 | case OwnOrderType.Stop: 54 | flags = OrderFlags.Active | OrderFlags.Stop; 55 | break; 56 | 57 | default: 58 | flags = OrderFlags.None; 59 | break; 60 | } 61 | 62 | if(order.Id > 0) 63 | flags |= OrderFlags.External; 64 | 65 | dw.Write((byte)flags); 66 | dw.WriteLeb128(order.Id); 67 | dw.WriteLeb128(order.Price); 68 | dw.WriteLeb128(order.Quantity); 69 | } 70 | } 71 | 72 | // ********************************************************************** 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /QScalp/Writer/OwnTradesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using QScalp.History.Internals; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class OwnTradesStream 18 | { 19 | // ********************************************************************** 20 | 21 | readonly DataWriter dw; 22 | readonly int sid; 23 | 24 | long lastMilliseconds; 25 | long lastTradeId; 26 | long lastOrderId; 27 | int lastPrice; 28 | 29 | // ********************************************************************** 30 | 31 | public OwnTradesStream(DataWriter dw, int sid, Security s) 32 | { 33 | this.dw = dw; 34 | this.sid = sid; 35 | 36 | dw.Write((byte)StreamType.OwnTrades); 37 | dw.Write(s.Entry); 38 | } 39 | 40 | // ********************************************************************** 41 | 42 | public void Write(DateTime dateTime, OwnTrade trade) 43 | { 44 | dw.WriteRecHeader(sid, dateTime); 45 | 46 | dw.WriteGrowing(DateTimeHelper.ToMs(trade.DateTime), ref lastMilliseconds); 47 | 48 | dw.WriteLeb128(trade.TradeId - lastTradeId); 49 | lastTradeId = trade.TradeId; 50 | 51 | dw.WriteLeb128(trade.OrderId - lastOrderId); 52 | lastOrderId = trade.OrderId; 53 | 54 | dw.WriteLeb128(trade.Price - lastPrice); 55 | lastPrice = trade.Price; 56 | 57 | dw.WriteLeb128(trade.Quantity); 58 | } 59 | 60 | // ********************************************************************** 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /QScalp/Writer/QshWriter.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.IO; 14 | 15 | using QScalp.History.Internals; 16 | 17 | namespace QScalp.History.Writer 18 | { 19 | sealed class QshWriter : IDisposable 20 | { 21 | // ********************************************************************** 22 | 23 | const byte fileVersion = 4; 24 | 25 | readonly Stream fs; 26 | readonly DataWriter dw; 27 | 28 | int streamCount; 29 | 30 | // ********************************************************************** 31 | 32 | public int RecordCount { get { return dw.RecordCount; } } 33 | public long FileSize { get { return fs.Length; } } 34 | 35 | // ********************************************************************** 36 | 37 | public QshWriter(string path, bool compress, string appName, 38 | string comment, DateTime recDateTime, int streamCount) 39 | { 40 | if(streamCount < 0) 41 | throw new ArgumentOutOfRangeException("streamCount"); 42 | 43 | if(streamCount > byte.MaxValue) 44 | throw new OverflowException("Слишком много потоков для записи"); 45 | 46 | fs = QshFile.Create(path, compress, fileVersion); 47 | dw = new DataWriter(fs, recDateTime, streamCount > 1); 48 | 49 | dw.Write(appName); 50 | dw.Write(comment); 51 | dw.Write(recDateTime.Ticks); 52 | dw.Write((byte)streamCount); 53 | } 54 | 55 | // ********************************************************************** 56 | 57 | public void Dispose() 58 | { 59 | if(dw != null) 60 | dw.Dispose(); 61 | 62 | if(fs != null) 63 | fs.Dispose(); 64 | } 65 | 66 | // ********************************************************************** 67 | 68 | public QuotesStream CreateQuotesStream(Security s) 69 | { 70 | return new QuotesStream(dw, streamCount++, s); 71 | } 72 | 73 | public DealsStream CreateDealsStream(Security s) 74 | { 75 | return new DealsStream(dw, streamCount++, s); 76 | } 77 | 78 | public OwnOrdersStream CreateOwnOrdersStream(Security s) 79 | { 80 | return new OwnOrdersStream(dw, streamCount++, s); 81 | } 82 | 83 | public OwnTradesStream CreateOwnTradesStream(Security s) 84 | { 85 | return new OwnTradesStream(dw, streamCount++, s); 86 | } 87 | 88 | public MessagesStream CreateMessagesStream() 89 | { 90 | return new MessagesStream(dw, streamCount++); 91 | } 92 | 93 | public AuxInfoStream CreateAuxInfoStream(Security s) 94 | { 95 | return new AuxInfoStream(dw, streamCount++, s); 96 | } 97 | 98 | public OrdLogStream CreateOrdLogStream(Security s) 99 | { 100 | return new OrdLogStream(dw, streamCount++, s); 101 | } 102 | 103 | // ********************************************************************** 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /QScalp/Writer/QuotesStream.cs: -------------------------------------------------------------------------------- 1 | #region Copyright (c) 2011-2016 Николай Морошкин, http://www.moroshkin.com/ 2 | /* 3 | 4 | Настоящий исходный код является частью приложения «Торговый привод QScalp» 5 | (http://www.qscalp.ru) и предоставлен исключительно в ознакомительных 6 | целях. Какое-либо коммерческое использование данного кода без письменного 7 | разрешения автора запрещено. 8 | 9 | */ 10 | #endregion 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | namespace QScalp.History.Writer 16 | { 17 | sealed class QuotesStream 18 | { 19 | // ********************************************************************** 20 | 21 | Quote[] lastQuotes = new Quote[0]; 22 | readonly List diffQuotes = new List(100); 23 | 24 | int lastPrice; 25 | 26 | readonly DataWriter dw; 27 | readonly int sid; 28 | 29 | // ********************************************************************** 30 | 31 | public QuotesStream(DataWriter dw, int sid, Security s) 32 | { 33 | this.dw = dw; 34 | this.sid = sid; 35 | 36 | dw.Write((byte)StreamType.Quotes); 37 | dw.Write(s.Entry); 38 | } 39 | 40 | // ********************************************************************** 41 | 42 | static bool QuoteTypeEquals(QuoteType qt1, QuoteType qt2) 43 | { 44 | switch(qt1) 45 | { 46 | case QuoteType.Ask: 47 | case QuoteType.BestAsk: 48 | return qt2 == QuoteType.Ask || qt2 == QuoteType.BestAsk; 49 | 50 | case QuoteType.Bid: 51 | case QuoteType.BestBid: 52 | return qt2 == QuoteType.Bid || qt2 == QuoteType.BestBid; 53 | 54 | default: 55 | return qt1 == qt2; 56 | } 57 | } 58 | 59 | // ********************************************************************** 60 | 61 | public void Write(DateTime dateTime, Quote[] quotes) 62 | { 63 | // ------------------------------------------------------------ 64 | 65 | diffQuotes.Clear(); 66 | 67 | int i = 0; 68 | 69 | foreach(Quote lq in lastQuotes) 70 | { 71 | while(i < quotes.Length && lq.Price < quotes[i].Price) 72 | diffQuotes.Add(quotes[i++]); 73 | 74 | if(i < quotes.Length && quotes[i].Price == lq.Price) 75 | { 76 | if(!QuoteTypeEquals(lq.Type, quotes[i].Type) || lq.Volume != quotes[i].Volume) 77 | diffQuotes.Add(quotes[i]); 78 | 79 | i++; 80 | } 81 | else 82 | diffQuotes.Add(new Quote(lq.Price, 0, QuoteType.Unknown)); 83 | } 84 | 85 | while(i < quotes.Length) 86 | diffQuotes.Add(quotes[i++]); 87 | 88 | lastQuotes = quotes; 89 | 90 | // ------------------------------------------------------------ 91 | 92 | if(diffQuotes.Count > 0) 93 | { 94 | dw.WriteRecHeader(sid, dateTime); 95 | dw.WriteLeb128(diffQuotes.Count); 96 | 97 | foreach(Quote q in diffQuotes) 98 | { 99 | dw.WriteLeb128(q.Price - lastPrice); 100 | lastPrice = q.Price; 101 | 102 | switch(q.Type) 103 | { 104 | case QuoteType.Ask: 105 | case QuoteType.BestAsk: 106 | dw.WriteLeb128(q.Volume); 107 | break; 108 | 109 | case QuoteType.Bid: 110 | case QuoteType.BestBid: 111 | dw.WriteLeb128(-q.Volume); 112 | break; 113 | 114 | default: 115 | dw.WriteLeb128(0); 116 | break; 117 | } 118 | } 119 | } 120 | 121 | // ------------------------------------------------------------ 122 | } 123 | 124 | // ********************************************************************** 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Qsh2StockSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {5B24FB13-5B07-4E9B-8C2E-02297BC1196E} 4 | WinExe 5 | StockSharp.Qsh2StockSharp 6 | netcoreapp3.1 7 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | false 9 | bin\$(Configuration)\ 10 | true 11 | stocksharp.ico 12 | 13 | 14 | full 15 | 16 | 17 | none 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Qsh2StockSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qsh2StockSharp", "Qsh2StockSharp.csproj", "{5B24FB13-5B07-4E9B-8C2E-02297BC1196E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5B24FB13-5B07-4E9B-8C2E-02297BC1196E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5B24FB13-5B07-4E9B-8C2E-02297BC1196E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5B24FB13-5B07-4E9B-8C2E-02297BC1196E}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5B24FB13-5B07-4E9B-8C2E-02297BC1196E}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qsh -> StockSharp 2 | Программа конвертации маркет данных (стаканы, тики, ордер лог) из формата QScalp в формат StockSharp (bin или csv). 3 | 4 | Полученный формат поддерживается всеми программами, представленных на [сайте StockSharp](https://stocksharp.ru/products/). 5 | 6 | На текущий момент исходные данные доступны на сайте брокеров [ITInvest](https://iticapital.ru/software/additional-software/qscalp/) и [Церих](ftp://athistory.zerich.com/). 7 | 8 | Инструкция использования и обсуждение утилиты доступно на [форуме](https://stocksharp.ru/articles/322/konvertatsiya-istoricheskih-failov-qscalp-v-format-stocksharp/). 9 | -------------------------------------------------------------------------------- /app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /stocksharp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StockSharp/Qsh2Bin/86e5cabed567664d187ef1aac85ab2f06887a61d/stocksharp.ico --------------------------------------------------------------------------------