using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MarketData.Numerical; using MarketData.MarketDataModel; using MarketData.DataAccess; using MarketData.Cache; using MarketData.Utils; namespace MarketData.Generator.Indicators { // *********************************************************************************** public class OverExtendedIndicator { private static double marginPercent=1.50; // The default margin is 1.00. 1.50 Gives the best results in backtests from 2013->2021 private OverExtendedIndicator() // Also, regarding VioaltionThresshold below.... the best results were obtained with MarginePercent=1.5 and ViolationThresshol=1.00 { } // UseOverExtendedIndicator:true/false // UseOverExtendedIndicatorDays:45 // UseOverExtendedViolationThreshhold:2 breaks >=2 this number are considered to be violations // This Indicator determines if a price is overextended by looking at the K band of the bollinger band over the past "dayCount" days. // If closing price breaks the K band by more than 1.00% then we consider that to be an indication that the price is overextended. public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20) { bool isOverExtended=false; Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4); if(null==prices || 0==prices.Count)return null; BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount); if(null==bollingerBands)return false; bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList()); BollingerBandElement item=bollingerBands.Where(x => x.Close>x.K && (((x.Close-x.K)/x.K)*100.00)>marginPercent).FirstOrDefault(); if(null!=item)isOverExtended=true; return isOverExtended; } // This method considers an overextended condition based upon an allowable number of upper band breaks public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20,int violationThreshhold=1) { bool isOverExtended=false; Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4); if(null==prices||0==prices.Count) return null; BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount); if(null==bollingerBands) return false; bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList()); List items=bollingerBands.Where(x => x.Close>x.K&&(((x.Close-x.K)/x.K)*100.00)>marginPercent).ToList(); if(null==items)return null; if(items.Count>violationThreshhold)isOverExtended=true; return isOverExtended; } // This method considers an overextended condition based upon an allowable number of upper band breaks and user supplied marginPercent public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20,int violationThreshhold=1,double paramMarginPercent=1.00) { bool isOverExtended=false; Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4); if(null==prices||0==prices.Count) return null; BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount); if(null==bollingerBands) return false; bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList()); List items=bollingerBands.Where(x => x.Close>x.K&&(((x.Close-x.K)/x.K)*100.00)>paramMarginPercent).ToList(); if(null==items) return null; if(items.Count>violationThreshhold) isOverExtended=true; return isOverExtended; } public static int? OverExtendedCount(String symbol,DateTime pricingDate,int dayCount=20) { Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4); if(null==prices||0==prices.Count) return null; BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount); if(null==bollingerBands) return null; bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList()); List items=bollingerBands.Where(x => x.Close>x.K).ToList(); if(null==items)return null; return items.Count; } } }