This commit is contained in:
2024-02-22 14:52:53 -05:00
parent 72c94666c5
commit 29b417e3f7
445 changed files with 360852 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
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 BandBreakIndicator
{
private BandBreakIndicator()
{
}
// This Indicator determines if a high price exceeds the K band (+2SSD) of the bollinger band over the past "dayCount" days.
// If high price breaks the K band then we consider that to be a true indication.
public static bool IsUpperBandBreakHigh(String symbol,DateTime pricingDate,int dayCount=20)
{
bool isBandBreak=false;
int pricingDays=dayCount*4;
if(pricingDays<60)pricingDays=60;
Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,pricingDays);
if(null==prices || 0==prices.Count)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("*** IsUpperBandBreakHigh: Failed to retrieve prices for {0} on {1} for {2} days. ***",symbol,pricingDate.ToShortDateString(),pricingDays));
return isBandBreak;
}
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices);
if(null==bollingerBands)return false;
bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
BollingerBandElement item=bollingerBands.Where(x => x.High > x.K).FirstOrDefault();
if(null!=item)isBandBreak=true;
return isBandBreak;
}
// This Indicator determines if a close price is equal to or less than the L band (-2SSD) of the bollinger band over the past "dayCount" days.
// If close price breaks or is equal to the L band then we consider that to be a true indication.
// If there is a violation then the date of the violation is return otherwise we return Epoch
public static DateTime IsLowerBandBreakClose(String symbol,DateTime pricingDate,int dayCount=20)
{
DateTime bandBreakDate=Utility.Epoch;
int pricingDays=dayCount*4;
if(pricingDays<60)pricingDays=60;
Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,pricingDays);
if(null==prices || 0==prices.Count)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("*** IsLowerBandBreakClose: Failed to retrieve prices for {0} on {1} for {2} days. ***",symbol,pricingDate.ToShortDateString(),pricingDays));
return bandBreakDate;
}
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices);
if(null==bollingerBands || bollingerBands.Count<dayCount)return bandBreakDate;
bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
BollingerBandElement item=bollingerBands.Where(x => x.Close <= x.L).FirstOrDefault();
if(null!=item)
{
bandBreakDate=item.Date;
}
return bandBreakDate;
}
}
}

View File

@@ -0,0 +1,32 @@
using MarketData.MarketDataModel;
using MarketData.Numerical;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Richard Donchian Channel Breakout. Donchian used 20 days.
namespace MarketData.Generator.Indicators
{
public class ChannelBreakoutIndicator
{
private ChannelBreakoutIndicator()
{
}
public static bool IsChannelBreakOut(DateTime tradeDate,Prices prices,int dayCount)
{
if(null==prices||prices.Count<dayCount||0==dayCount||prices[0].Date!=tradeDate) return false;
return IsChannelBreakOut(prices[0],prices,dayCount);
}
public static bool IsChannelBreakOut(Price currentPrice,Prices prices,int dayCount)
{
if(null==prices||prices.Count<dayCount||null==currentPrice) return false;
prices=new Prices(prices.Take(dayCount).ToList()); // use the dayCount range provided
prices=new Prices(prices.Where(x => !(x.Date.Date.Equals(currentPrice.Date.Date))).ToList()); // make sure currentPrice is not in the list of prices
int count=prices.Count(x => x.Close>=currentPrice.Close); // count how many closing prices are above or equal to our closing price
return 0==count?true:false; // if no records then currentPrice is the max over the period so return true, otherwise return false;
}
}
}

View File

@@ -0,0 +1,62 @@
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 MVPIndicator
{
private static readonly double DAY_COUNT=15.00;
private static readonly double MOMENTUM_MIN_DAYS=12.00;
private MVPIndicator() // Marc Minervini "M"omentum, "V"olume, "P"rice
{
}
public static bool IsTrue(String symbol,DateTime pricingDate)
{
Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,(int)DAY_COUNT+1);
if(null==prices||DAY_COUNT+1>prices.Count) return false;
double daysUp=0;
double daysDown=0;
bool qualifiesOnPrice=false;
bool qualifiesOnVolume=false;
bool qualifiesOnMomentum=false;
// Momentum Check
for(int index=prices.Count-2;index>=0;index--)
{
Price currentPrice=prices[index];
Price prevPrice=prices[index+1];
if(currentPrice.Close>prevPrice.Close)daysUp++;
else daysDown++;
}
if(0.00==daysDown) qualifiesOnMomentum=true;
else qualifiesOnMomentum=daysUp>=MOMENTUM_MIN_DAYS?true:false;
if(!qualifiesOnMomentum) return false;
// Volume Check
double baseVolume=prices[prices.Count-1].Volume;
for(int index=prices.Count-2;index>=0 && !qualifiesOnVolume;index--)
{
Price currentPrice=prices[index];
double percentChangeInVolume=((double)currentPrice.Volume-baseVolume)/baseVolume;
if(percentChangeInVolume>=.25)qualifiesOnVolume=true;
}
if(!qualifiesOnVolume)return false;
// Price check
double cumulativeReturn=prices.GetCumulativeReturn();
if(cumulativeReturn>=.20) qualifiesOnPrice=true;
if(!qualifiesOnPrice) return false;
return true;
}
}
}

View File

@@ -0,0 +1,47 @@
using MarketData.MarketDataModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.Indicators
{
public class NarrowRangeIndicator
{
private NarrowRangeIndicator()
{
}
// It is assumed that prices are in descending date order. (i.e.) The most recent price is in the lowest index position
public static bool IsNarrowRangeEntry(DateTime date,Prices prices,int dayCount)
{
if(!IsInsideDay(date,prices))return false;
if(!IsNarrowestRange(date,prices,dayCount))return false;
return true;
}
private static bool IsInsideDay(DateTime date,Prices prices)
{
int index=prices.FindIndex(x=>x.Date.Date.Equals(date));
if(-1==index||index+1>=prices.Count)return false;
if(!(prices[index].High<=prices[index+1].High&&prices[index].Low>=prices[index+1].Low))return false;
return true;
}
private static bool IsNarrowestRange(DateTime date,Prices prices,int dayCount)
{
int index=prices.FindIndex(x => x.Date.Date.Equals(date));
double range=GetRange(prices,index);
if(index+dayCount>=prices.Count-1)return false;
for(int dayIndex=index+1;dayIndex<index+dayCount;dayIndex++)
{
double nextRange=GetRange(prices,dayIndex);
if(nextRange<range)return false;
}
return true;
}
private static double GetRange(Prices prices,int index)
{
double range=prices[index].High-prices[index].Low;
return Math.Abs(range);
}
}
}

View File

@@ -0,0 +1,78 @@
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<BollingerBandElement> 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<BollingerBandElement> 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<BollingerBandElement> items=bollingerBands.Where(x => x.Close>x.K).ToList();
if(null==items)return null;
return items.Count;
}
}
}

View File

@@ -0,0 +1,44 @@
using MarketData.MarketDataModel;
using MarketData.Numerical;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.Indicators
{
public class PriceTrendIndicatorResult
{
public PriceTrendIndicatorResult(bool isUptrend,double highPriceSlope=double.NaN,double lowPriceSlope=double.NaN)
{
this.IsUpTrend=isUptrend;
this.HighPriceSlope=highPriceSlope;
this.LowPriceSlope=lowPriceSlope;
}
public bool IsUpTrend{get;private set;}
public double HighPriceSlope{get;private set;}
public double LowPriceSlope{get; private set;}
}
public class PriceTrendIndicator
{
private PriceTrendIndicator()
{
}
public static PriceTrendIndicatorResult IsUptrend(Prices prices,int dayCount)
{
if(null==prices||prices.Count<dayCount) return new PriceTrendIndicatorResult(false);
float[] highPrices=prices.GetPricesHigh();
highPrices=highPrices.Take(dayCount).ToArray();
highPrices=Numerics.Reverse(ref highPrices);
double highPricesSlope=Numerics.Slope(highPrices);
if(highPricesSlope<0) return new PriceTrendIndicatorResult(false);
float[] lowPrices=prices.GetPricesLow();
lowPrices=lowPrices.Take(dayCount).ToArray();
lowPrices=Numerics.Reverse(ref lowPrices);
double lowPricesSlope=Numerics.Slope(lowPrices);
if(lowPricesSlope<0) return new PriceTrendIndicatorResult(false);
return new PriceTrendIndicatorResult(true,highPricesSlope,lowPricesSlope);
}
}
}

View File

@@ -0,0 +1,26 @@
using MarketData.MarketDataModel;
using MarketData.Numerical;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.Indicators
{
public class VolumeTrendIndicator
{
private VolumeTrendIndicator()
{
}
public static bool IsUptrend(Prices prices,int dayCount)
{
if(null==prices||prices.Count<dayCount) return false;
float[] volume=prices.GetVolume();
volume=volume.Take(dayCount).ToArray();
volume=Numerics.Reverse(ref volume);
double volumeSlope=Numerics.Slope(volume);
return volumeSlope>0.00?true:false;
}
}
}