public static bool HasOption(this TickMask2Flags mask2, TickMask2Flags checkflag)
 {
     return((mask2 & 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));
        }