public static bool HasOption(this TickMask1Flags mask1, TickMask1Flags checkflag) { return((mask1 & checkflag) == checkflag); }
private TickRecord ReadNextTickRecord() { TickMask1Flags mask1 = (TickMask1Flags)_br.ReadByte(); TickMask2Flags mask2 = (TickMask2Flags)_br.ReadByte(); // Inputs UInt64 timeDelta; uint priceDelta = 0; UInt64 volumeDelta; uint priceDeltaOffset = 0; // Outputs DateTime barDateTime; Double barPrice; Double barBid; Double barAsk; long barVolume; // // check the Time flag // if (mask1.HasOption(TickMask1Flags.Time1Secs)) { timeDelta = _br.ReadByte(); barDateTime = _lastDateTime.AddTicks((long)(timeDelta * 10000000)); } else if (mask1.HasOption(TickMask1Flags.Time8)) { long bigTimeDelta = (long)_br.ReadUInt64BE(); barDateTime = _lastDateTime.AddTicks(bigTimeDelta); } else { if (mask1.HasOption(TickMask1Flags.Time4)) { timeDelta = /*(int)*/ _br.ReadUInt32BE(); } else if (mask1.HasOption(TickMask1Flags.Time2)) { timeDelta = _br.ReadUInt16BE(); } else if (mask1.HasOption(TickMask1Flags.Time1)) { timeDelta = _br.ReadByte(); } else if (mask1.HasOption(TickMask1Flags.NoTime)) { timeDelta = 0; } else { throw new Exception($"Unrecognized Time Flag in Mask1: {Convert.ToString((short)mask1, 2)}\n" + $"Mask2: {Convert.ToString((short)mask2, 2)}\n" + $"FileName: {FileName}\n" + $"Position: {_br.BaseStream.Position}"); } barDateTime = _lastDateTime.AddTicks((long)timeDelta); } // // check the Price flag // // There are two price markers in the top two high order bits in Mask1. // If either is set then a price must be calculated because it's not the same as the previous bar otherwise there is no price // change and the price is the same as the previous bar. // // There are three options... // // (1) If only the first bit is set then the Price Delta must be read as a single byte following the Time Delta if applicable and // an offset of 128 applied. // // b10xxxxxx // // (2) If both are set the Price Delta must be read as a 4 byte unsigned integer following the Time Delta if applicable and // an offset of 0x80000000 applied. // // b11xxxxxx // // (3) If only the 2nd bit is set then the Price Delta is embedded in the 4 low order bits of Mask2. // // If a value exists within the low 4 bits of Mask2 then you may use Mask 2 as the Price Delta. // // b01xxxxxx // // Mask2 - bxxxxpppp // Price delta = b0000pppp // Price delta Offset = bxxxx0000 // if (mask1.HasOption(TickMask1Flags.Price4)) { priceDelta = _br.ReadUInt32BE(); priceDeltaOffset = 2147483648; // 0x80000000 } else if (mask1.HasOption(TickMask1Flags.Price1)) { priceDelta = _br.ReadByte(); priceDeltaOffset = 128; // 0x80 } else if (mask1.HasOption(TickMask1Flags.PriceEmbeddedInMask2)) { if (mask2.HasOption(TickMask2Flags.PriceDeltaBit1) || mask2.HasOption(TickMask2Flags.PriceDeltaBit2) || mask2.HasOption(TickMask2Flags.PriceDeltaBit3) || mask2.HasOption(TickMask2Flags.PriceDeltaBit4)) { priceDelta = (byte)mask2; if (mask2.HasOption(TickMask2Flags.Volume8)) { priceDeltaOffset = 240; } else if (mask2.HasOption(TickMask2Flags.Volume4)) { priceDeltaOffset = 208; } else if (mask2.HasOption(TickMask2Flags.Volume2)) { priceDeltaOffset = 176; } else if (mask2.HasOption(TickMask2Flags.Volume1X1000)) { priceDeltaOffset = 142; } else if (mask2.HasOption(TickMask2Flags.Volume1X500)) { priceDeltaOffset = 112; } else if (mask2.HasOption(TickMask2Flags.Volume1)) { priceDeltaOffset = 48; } else if (mask2.HasOption(TickMask2Flags.Volume1X100)) { priceDeltaOffset = 80; // x30 } else { throw new Exception($"Unknown Volume Flag in Mask2: {Convert.ToString((short)mask2, 2)}\n" + $"Mask1: {Convert.ToString((short)mask1, 2)}\n" + $"FileName: {FileName}\n" + $"Position: {_br.BaseStream.Position}"); } } else { throw new Exception($"No expected Price Delta embedded in Mask2: {Convert.ToString((short)mask2, 2)}\n" + $"Mask1: {Convert.ToString((short)mask1, 2)}\n" + $"FileName: {FileName}\n" + $"Position: {_br.BaseStream.Position}"); } } else if (mask2.HasOption(TickMask2Flags.PriceDeltaBit1) || mask2.HasOption(TickMask2Flags.PriceDeltaBit2) || mask2.HasOption(TickMask2Flags.PriceDeltaBit3) || mask2.HasOption(TickMask2Flags.PriceDeltaBit4)) { throw new Exception($"Price Delta embedded in Mask2 where none expected: {Convert.ToString((short)mask2, 2)}\n" + $"Mask1: {Convert.ToString((short)mask1, 2)}\n" + $"FileName: {FileName}\n" + $"Position: {_br.BaseStream.Position}"); } barPrice = Math.Round(_lastPrice + ((int)(priceDelta - priceDeltaOffset) * _tickSizePrice), 2); // // check the Bid/Ask flag // int spreadMultiplier; bool bidTrade; if (mask1.HasOption(TickMask1Flags.Spread2)) { spreadMultiplier = _br.ReadUInt16BE(); if (spreadMultiplier < 256) { bidTrade = true; } else { bidTrade = false; spreadMultiplier /= 256; } } else if (mask1.HasOption(TickMask1Flags.Spread1)) { spreadMultiplier = _br.ReadByte(); if (spreadMultiplier < 16) { bidTrade = true; } else { bidTrade = false; spreadMultiplier /= 16; } } else { if (mask1.HasOption(TickMask1Flags.DefaultSpreadX3)) { spreadMultiplier = 3; } else if (mask1.HasOption(TickMask1Flags.DefaultSpreadX2)) { spreadMultiplier = 2; } else { spreadMultiplier = 1; } if (mask1.HasOption(TickMask1Flags.Ask)) { bidTrade = false; } else { bidTrade = true; } } if (bidTrade) { barBid = barPrice; barAsk = barBid + (spreadMultiplier * _defaultSpread); } else { barAsk = barPrice; barBid = barAsk - (spreadMultiplier * _defaultSpread); } // // check the Volume flag // int volumeMultiplier = 1; if (mask2.HasOption(TickMask2Flags.Volume8)) { volumeDelta = _br.ReadUInt64BE(); } else if (mask2.HasOption(TickMask2Flags.Volume4)) { volumeDelta = _br.ReadUInt32BE(); } else if (mask2.HasOption(TickMask2Flags.Volume2)) { volumeDelta = _br.ReadUInt16BE(); } else if (mask2.HasOption(TickMask2Flags.Volume1X1000)) { volumeDelta = _br.ReadByte(); volumeMultiplier = 1000; } else if (mask2.HasOption(TickMask2Flags.Volume1X500)) { volumeDelta = _br.ReadByte(); volumeMultiplier = 500; } else if (mask2.HasOption(TickMask2Flags.Volume1)) { volumeDelta = _br.ReadByte(); } else if (mask2.HasOption(TickMask2Flags.Volume1X100)) { volumeDelta = _br.ReadByte(); volumeMultiplier = 100; } else { throw new Exception($"Unknown Volume Flag in Mask2: {Convert.ToString((short)mask2, 2)}\n" + $"Mask1: {Convert.ToString((short)mask1, 2)}\n" + $"FileName: {FileName}\n" + $"Position: {_br.BaseStream.Position}"); } barVolume = (long)volumeDelta * volumeMultiplier; _lastDateTime = barDateTime; _lastPrice = barPrice; _lastBid = barBid; _lastAsk = barAsk; _lastVolume = barVolume; _lastMask1 = mask1; _lastMask2 = mask2; return(new TickRecord(barDateTime, barPrice, barBid, barAsk, barVolume)); }