Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CalculateInsyncIndex throws the following exception #43

Open
HamzaAhmedZia7 opened this issue Aug 8, 2023 · 11 comments
Open

CalculateInsyncIndex throws the following exception #43

HamzaAhmedZia7 opened this issue Aug 8, 2023 · 11 comments
Assignees
Labels
good first issue Good for newcomers help wanted Extra attention is needed question Further information is requested

Comments

@HamzaAhmedZia7
Copy link

Greetings Franklin,

This code

var bars = stockHistoryDaily[@"RELIANCE"];
var stockData = new StockData(bars.Select(x => x.Open), bars.Select(x => x.High), bars.Select(x => x.Low), bars.Select(x => x.Close), bars.Select(x => x.Volume), bars.Select(x => x.DateTime));
var insyncResults = stockData.CalculateInsyncIndex();
var insyncIndex = insyncResults.OutputValues["Iidx"];

produces this exception

OoplesFinance.StockIndicators.Exceptions.CalculationException: Calculations based off of BollingerBands can't be completed because this indicator doesn't have a single output.
   at OoplesFinance.StockIndicators.Helpers.CalculationsHelper.GetInputValuesList(StockData stockData)
   at OoplesFinance.StockIndicators.Calculations.CalculateDetrendedPriceOscillator(StockData stockData, MovingAvgType maType, Int32 length)
   at OoplesFinance.StockIndicators.Calculations.CalculateInsyncIndex(StockData stockData, MovingAvgType maType, Int32 fastLength, Int32 slowLength, Int32 signalLength, Int32 emoLength, Int32 mfiLength, Int32 bbLength, Int32 cciLength, Int32 dpoLength, Int32 rocLength, Int32 rsiLength, Int32 stochLength, Int32 stochKLength, Int32 stochDLength, Int32 smaLength, Double stdDevMult, Double divisor)
   at Program.<Main>$(String[] args) in 

in method CalculateDetrendedPriceOscillator at line CalculationsHelper.GetInputValuesList(stockData).inputList;

      this StockData stockData,
      MovingAvgType maType = MovingAvgType.SimpleMovingAverage,
      int length = 20)
    {
      List<double> doubleList = new List<double>();
      List<Signal> signalList = new List<Signal>();
      List<double> inputList = CalculationsHelper.GetInputValuesList(stockData).inputList;
      int num1 = MathHelper.MinOrMax(checked ((int) Math.Ceiling(unchecked ((double) length / 2.0 + 1.0))));
      List<double> movingAverageList = CalculationsHelper.GetMovingAverageList(stockData, maType, length, inputList);
      int index = 0;

It is called by this code

      List<double> customValuesList5 = stockData1.CalculateBollingerBands(length: length, stdDevMult: stdDevMult1).CustomValuesList;
      List<double> customValuesList6 = stockData.CalculateDetrendedPriceOscillator(length: dpoLength).CustomValuesList;
      List<double> customValuesList7 = stockData.CalculateRateOfChange(rocLength).CustomValuesList;

I am trying out your excellent humongous library. :-)

@ooples
Copy link
Owner

ooples commented Aug 8, 2023

@HamzaAhmedZia7 This error is by design since the Bollinger Bands are one of the few indicators that doesn't output a single value but outputs 3 values (High band, Middle band, and Low band), and if you were to calculate an indicator based on this output, you would need to specifically select one of the bands using the OutputValues Dictionary instead of using the CustomValuesList object. I will be including a test project where you can try out some of these options and hopefully it will make things easier for the average user. Let me know if you need an example

@HamzaAhmedZia7
Copy link
Author

@ooples

LazyBear makes use of both upper and lower bands if I'm not mistaken

bolinslb=sma( src,lengthBB ) - multBB * ( stdev( src,lengthBB ) )
bolinsub=sma( src,lengthBB ) + multBB * ( stdev( src,lengthBB ) )
bolins2= (src- bolinslb ) / ( bolinsub - bolinslb )
bolinsll=( bolins2 < 0.05 ? -5 : ( bolins2 > 0.95 ? 5 : 0 ) )

and then uses bolinsll in the final calculation

iidx = 50 + cciins + bolinsll + rsiins + stopkins + stopdins + mfiins + emvinsb + emvinss + rocinss + rocinsb + nz(pdoinss[10]) + nz(pdoinsb [10]) + macdinss + macdinsb

then why should I need to specifically select one?

and if you were to calculate an indicator based on this output, you would need to specifically select one of the bands using the OutputValues Dictionary instead of using the CustomValuesList object.

I have not read your code...do you not take into account the upper and the lower bands? Then will the iidx values be consistent with what is on tradingview?

A Test project and example ... yes please.

ooples added a commit that referenced this issue Aug 8, 2023
…inger Bands method #43

Made some minor changes for better code readability
@ooples
Copy link
Owner

ooples commented Aug 8, 2023

@HamzaAhmedZia7 I will add the test project later but I did see the reason for the exception and provided a fix so if you can please get the latest and confirm that it works now

@HamzaAhmedZia7
Copy link
Author

@ooples

With the latest the exception is gone but the iidx values are not consistent with what is on tradingview.

An example of this is RELIANCE on Friday August 04, 2023. The Insync index on Trading View is approx 45.02.
Screenshot_20230809_111944

The Insync Index produced by this library is 60.

Screenshot_20230809_113103

Did you take into account both the lower and upper bands in the calculation?

@HamzaAhmedZia7
Copy link
Author

I have sourced the data for this stock from TradingView website so there should be no discrepencies

@HamzaAhmedZia7
Copy link
Author

Even Bollinger Bands calculations do not match
RELIANCE on Friday August 04, 2023. The bollinger bands values are as in the screenshot below
Screenshot_20230809_135253

The Bollinger band produced by the library is way off.

Upper Band
Screenshot_20230809_135550

Middle Band
Screenshot_20230809_135737

Lower Band
Screenshot_20230809_135859

This can be ONE of the many reasons why Insync Index values produced by the library is incorrect.

@HamzaAhmedZia7
Copy link
Author

Interestingly enough the bollinger bands values calculated by the python wrapper library ta-lib is matching with the charts on sites like investing.com For eg RELIANCE on Friday August 04, 2023.

This python code

bbands = talib.BBANDS(reliance.close,timeperiod=20,nbdevup=2.0,nbdevdn=2.0,matype=0)
out = pd.DataFrame({'upperband':bb.upperband,'middleband':bb.middleband,'lowerband':bb.lowerband})
out

produces the following bollinger band values
Screenshot_20230809_165515

Which matches investing.com charts
Screenshot_20230809_165822

However it still does not match tradingview charts posted above.

What is going on here?

Is the calculation methodology adopted by TradingView (pinescript); their runtime different from others?

@ooples
Copy link
Owner

ooples commented Aug 9, 2023

@HamzaAhmedZia7 Well in this case, feel free to take a look at my bollinger band code and see if you spot any issues

@HamzaAhmedZia7
Copy link
Author

In method public static StockData CalculateStandardDeviationVolatility(this StockData stockData, MovingAvgType maType = MovingAvgType.SimpleMovingAverage, int length = 20)

which is called from CalculateBollingerBands(); the item is being set to the moving average list and not the close price/inputList therefore there is an error

I do not know how to edit and fix nuget packages. I tried doing the following change however while debugging VS always picks up your nuget package. Wasted an hour trying to debug with my changes in vain.

//List<double> item = CalculationsHelper.GetInputValuesList(stockData).inputList;
List<double> item = stockData.ClosePrices;

I cannot investigate further since I cannot change nuget source code or maybe I do not know how to....

Hopefully this will take you in the right direction.

Also there are straight forward ways of calculating std deviations. Why have you taken such a convoluted approach.

public static class Extend
{
    public static double StandardDeviation(this IEnumerable<double> values)
    {
        double avg = values.Average(); 
        return Math.Sqrt(values.Average(v=>(v-avg) * (v-avg)));
    }
}

I would highly recommend not to reinvent the wheel and use one of the better open source math libraries Math.NET

Install-Package MathNet.Numerics
var populationStdDev = new List<double>(1d, 2d, 3d, 4d, 5d).PopulationStandardDeviation();

var sampleStdDev = new List<double>(2d, 3d, 4d).StandardDeviation();

DescriptiveStatistics

@ooples
Copy link
Owner

ooples commented Aug 9, 2023

@HamzaAhmedZia7 A couple of things I need to clarify with you. I do my own standard deviation calculation because it is used as a stock indicator and is also used by multiple technical analysis calculations and the code you posted above will fail since it doesn't handle potential errors like doing a square root for a negative number or checking that the values list has items for example.

You can view the full source code for my library by going to the main code tab and click on the green code button that will allow you to download my full source code.

I have no clue what you mean about it being set to the moving average list and not using the input list so you will need to elaborate on that.

@HamzaAhmedZia7
Copy link
Author

HamzaAhmedZia7 commented Aug 9, 2023

@ooples

code you posted above will fail

Obviously I wasn't trying to fully understand the architectural decisions you took and the reasons for using such a round about method. I just wanted to check for a quick fix. If it had worked I would have pointed out the trivial resolution for you to elaborately fix it. ;-)

since it doesn't handle potential errors like doing a square root for a negative number or checking that the values list has items for example.

Checking for these are trivial

I have no clue what you mean about it being set to the moving average list and not using the input list so you will need to elaborate on that.

In function CalculateStandardDeviationVolatility which is called from CalculateBollingerBands();
while debugging I found that inputList = CalculationsHelper.GetInputValuesList(stockData).inputList;
is being incorrectly set to the simple moving average of the close price inplace of the close prices.

Therefore, the next line calculates the simple moving average of the simple moving average instead of the close prices.

I presume you are trying to set item to the list of close prices for the security. That is discrepency I found and after that being a nuget package could not go further. Hope this points you to the right direction.

Screenshot_20230809_215911

You can view the full source code for my library by going to the main code tab and click on the green code button that will allow you to download my full source code.

Possibly some other time

@ooples ooples self-assigned this Oct 21, 2023
@ooples ooples added help wanted Extra attention is needed good first issue Good for newcomers question Further information is requested labels Oct 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants