Search code examples
c#.netdecimalfinancetrading

Incorrect decimal placement in financial application


I'm fairly new to programming and started learning C# and this is my first project. I'm struggling to figure out why strange and seemingly random issue is occurring. This is a fairly simple trading application. Basically it connects to a websocket stream and receives live price data from the exchange and then evaluates the price in real time and performs some actions. The price is updated hundreds of times per second and operates without issues and then all of a sudden, I will get a price value that is thousands of dollars off the actual price that was sent from the exchange. I finally caught this occurring in real time. The app had been running for 11 hours or so without issue, then the bad value came through.

Here is the code in question:

public static decimal CurrentPrice;
// ...
if (BitmexTickerStreamIsConnected)
{
    bitmexApiSocketService.Subscribe(BitmetSocketSubscriptions.CreateInstrumentSubsription(
        message =>
        {
            foreach (var instrumentDto in message.Data)
            {
                if (instrumentDto.Symbol == "XBTUSD")
                {
                    BitmexTickerStreamLastMessageReceived = DateTime.Now;
                    decimal LastPrice = instrumentDto.LastPrice.HasValue ? Convert.ToDecimal(instrumentDto.LastPrice) : CurrentPrice;
                    CurrentPrice = LastPrice;
                }
            }
        }));
}

These are the values from the debug after a breakpoint was hit further down:

instrumentDto.LastPrice = 7769.5
LastPrice = 7769.5
CurrentPrice = 776.9

The issue is that CurrentPrice seems to be for some reason shifting the decimal to the left by one place. The values coming in from the websocket are fine, its just when CurrentPrice is set to LastPrice that the issue happens.

I have no idea why this is happening and seems to be totally random.

Anyone have any idea why this might be happening or how?

Thank you for your help!


Solution

  • There's two common causes:

    • Market data, due to how fast it's updated, will occasionally give you straight up bad data depending on the provider. If you're consuming directly from an exchange you need to code for this. Some providers (like OPRA) will filter or mark bad ticks for you.
    • If you see this issue consistently it's due to things like tick size or scale. Some exchanges do this differently, but effectively you need to multiply certain price fields by a certain scale. Consult with the data provider documentation for details.

    If this is seen very rarely, you likely just got a bad price. Yes, this absolutely will happen on occassion and you need to be prepared for it, unless you want to become the next Knight Capital.

    In all handlers I've written (or contributed to) there's a "sanity check" to see if the data is good. Depending on what you're trying to accomplish, just dropping the bad tick is fine.

    Another solution that I've commonly used is alternate streams of data (usually called "A" and "B" streams or similar). If you get a bad tick on one stream, use the other.

    That said this is not directly related to the programming language, but at the core it's handling quirks with the API/data.

    Edit

    Also beware of threading issues here. Be sure CurrentPrice isn't updated by multiple threads at once. decimal is 128-bit base 10 floating point, and that's larger than word size currently (32 or 64 bits).

    You may need to synchronize the reads and writes to it which you can do in a variety of ways. The above information still applies, though.