DaveSkender / Stock.Indicators

Stock Indicators for .NET is a C# NuGet package that transforms raw equity, commodity, forex, or cryptocurrency financial market price quotes into technical indicators and trading insights. You'll need this essential data in the investment tools that you're building for algorithmic trading, technical analysis, machine learning, or visual charting.
https://dotnet.StockIndicators.dev
Apache License 2.0
977 stars 245 forks source link

Attempted to divide by zero with Bollinger Bands. #183

Closed M22arius494 closed 3 years ago

M22arius494 commented 3 years ago

Yesterday I switched (for a brief moment) from TA-LIB to your approach, but in I'm getting divide errors. I'm using version version 1.1.2, is this anything familiar?

I think it seems to happen on coins with a low price (like viteusdt=0.0016), but I'm not yet sure that is actually the cause. I'll try to give you some test data soon (today i hope).

System.DivideByZeroException: Attempted to divide by zero. at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2) at Skender.Stock.Indicators.Indicator.GetBollingerBands(IEnumerable`1 history, Int32 lookbackPeriod, Decimal standardDeviations)

List resultsbb = (List)Indicator.GetBollingerBands(history);

DaveSkender commented 3 years ago

There was one small issue with a bug fix in 1.1.2 (#181), so try with newer 1.1.5. Also, check your history and make sure it's okay. In any case, this looks like a bug since we're not handling some data situation correctly.

As far as Bollinger Band goes, there's really not many unhandled divisions. I'll check the StdDev calculation to see what happens with very small prices in case there's a rounding issue. If stdDev returns zero, you'd get this error.

decimal periodAvg = sum / lookbackPeriod;
decimal stdDev = (decimal)Functions.StdDev(periodClose);

r.Sma = periodAvg;
r.UpperBand = periodAvg + standardDeviations * stdDev;
r.LowerBand = periodAvg - standardDeviations * stdDev;

r.PercentB = (h.Close - r.LowerBand) / (r.UpperBand - r.LowerBand);
r.ZScore = (stdDev == 0) ? null : (h.Close - r.Sma) / stdDev;
r.Width = (r.Sma == 0) ? null : (r.UpperBand - r.LowerBand) / r.Sma;

PercentB does not handle the zero standard deviation situation well, so I'm fixing that part. The question I have though, is whether standard deviations of 0 is the right value given your particular data. It can happen.

DaveSkender commented 3 years ago

If you can give me some quote data, that would be helpful. I’ll add it to my test suite with additional unit tests to better cover the small values we see in cryptocurrency. Thank you!

DaveSkender commented 3 years ago

The small fix I mentioned was implemented in internal release version 1.1.6 and will be available in the next public package release, which will be in the next few days or this weekend.

M22arius494 commented 3 years ago

Hello Dave,,

I got you some values from a coin called VITE-BTC on Binance. That coin is almost a ghost with almost a "flatline" graph. My tool tried to calculate the BB and voila, boom.

Funny/weird enough is the BB with just 30 candles OK and does not give the divide by zero error.

Greetings, Marius

VITEBTC - Attempted to divide by zero.txt

DaveSkender commented 3 years ago

Yah, a flatline would have produced a 0 standard deviation scenario. I’ve fixed this in newer versions so it will simply return nulls on impacted dates in the results, rather than blowing up. Thanks for the data!

18-11-2020 17:27:00, 0.0000009200, 0.0000009200, 0.0000009200, 0.0000009200

Wow, those are some small values! I’ll add some of this to my test data.

github-actions[bot] commented 3 years ago

This Issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new Issue for related bugs.