//unused for now public static decimal GetOBVComposite(JArray resultSet, int daysToCalculate) { int daysCalulated = 0; int numberOfResults = 0; HashSet <string> dates = new HashSet <string>(); Stack <decimal> obvValueYList = new Stack <decimal>(); decimal obvSum = 0; foreach (var result in resultSet) { if (daysCalulated < daysToCalculate) { decimal obvValue = decimal.Parse(result.Value <string>("obv")); obvValueYList.Push(obvValue); obvSum += obvValue; numberOfResults++; string resultDate = result.Value <string>("datetime"); string obvDate = DateTime.Parse(resultDate).ToString("yyyy-MM-dd"); if (!dates.Contains(obvDate)) { dates.Add(obvDate); daysCalulated++; } } else { break; } } List <decimal> obvXList = new List <decimal>(); for (int i = 1; i <= numberOfResults; i++) { obvXList.Add(i); } List <decimal> obvYList = obvValueYList.ToList(); decimal obvSlope = Indicators.GetSlope(obvXList, obvYList); decimal obvSlopeMultiplier = Indicators.GetSlopeMultiplier(obvSlope); List <decimal> zScores = Indicators.GetZScores(obvYList); decimal zScoreSlope = Indicators.GetSlope(zScores, obvXList); decimal zScoreSlopeMultiplier = Indicators.GetSlopeMultiplier(zScoreSlope); List <decimal> normalizedScores = Indicators.GetNormalizedData(obvYList); decimal normalizedSlope = Indicators.GetSlope(normalizedScores, obvXList); decimal normalizedSlopeMultiplier = Indicators.GetSlopeMultiplier(normalizedSlope); decimal obvAverage = obvSum / numberOfResults; //look for buy and sell signals bool obvHasBuySignal = false; bool obvHasSellSignal = false; decimal obvPrev = obvYList[0]; bool obvPrevIsNegative = obvPrev < 0; for (int i = 1; i < obvYList.Count(); i++) { decimal current = obvYList[i]; bool currentIsNegative = current < 0; if (!currentIsNegative && obvPrevIsNegative) { obvHasBuySignal = true; if (obvHasSellSignal) { obvHasSellSignal = false; //cancel the previous sell signal if buy signal is most recent } } else if (currentIsNegative && !obvPrevIsNegative) { obvHasSellSignal = true; if (obvHasBuySignal) { obvHasBuySignal = false; //cancel the previous buy signal if sell signal is most recent } } obvPrev = current; obvPrevIsNegative = obvPrev < 0; } //Start with the average of the 2 most recent OBV Normalized Scores //Only use the normalized scores if average OBV is greater than 0 decimal baseValue; if (obvAverage > 0) { baseValue = ((normalizedScores[normalizedScores.Count - 1] + normalizedScores[normalizedScores.Count - 2]) / 2) * 100; } else { //ZScore bonus helps us score based on derivatives //Only add ZScoreBonus if it is positive, divide by 4 instead of 2 (which would be classic mean) decimal zScoreBonus = ((zScores[zScores.Count - 1] + zScores[zScores.Count - 2]) / 4) * 100; if (zScoreBonus < 0) { zScoreBonus = 15; //pity points } baseValue = zScoreBonus; } //Add bonus if average OBV is greater than 0 decimal obvAverageBonus = obvAverage > 0 ? 15 : 0; //Add bonus if OBV slope positive decimal obvSlopeBonus = (obvSlope > 0) ? 10 : 0; //calculate composite score based on the following values and weighted multipliers decimal composite = 0; composite += baseValue; composite += obvAverageBonus; composite += obvSlopeBonus; composite += (zScoreSlope > 0) ? (zScoreSlope * zScoreSlopeMultiplier) : 0; composite += (normalizedSlope > 0) ? (normalizedSlope * normalizedSlopeMultiplier) : 0; composite += (obvHasBuySignal) ? 15 : 0; composite += (obvHasSellSignal) ? -15 : 0; return(Math.Min(composite, 100)); //cap OBV composite at 100, no extra weight }