/// <summary> /// Load the List with StockPoint objects /// </summary> /// <param name="stockPoints">Stock points to fill.</param> /// <param name="st">Stream with CSV data.</param> public static void LoadList(ref StockPoints stockPoints, Stream st) { StreamReader sr = new StreamReader(st); string line; int lineNumber = 1; double open; double high; double low; double close; long volume; while (!sr.EndOfStream) { line = sr.ReadLine(); string[] terms = line.Split(','); for (int i = 0; i < 7; i++) { if (terms[i] == String.Empty) { terms[i] = "0"; } } open = (double)Double.Parse(terms[0]); high = (double)Double.Parse(terms[1]); low = (double)Double.Parse(terms[2]); close = (double)Double.Parse(terms[3]); volume = Int64.Parse(terms[4]); StockPoint stockPoint = new StockPoint(terms[6], terms[5], open, high, low, close, volume); stockPoints.Add(stockPoint); lineNumber++; } }
//Aroon public static void CalculateAroon(out string key, out string key2, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = string.Format("Aroon-UP({0})", period.ToString("00")); key2 = string.Format("Aroon-Down({0})", period.ToString("00")); offset = period - 1; // Aroon-Up = ((period - Days Since period-day High)/period) x 100 double up; // Aroon-Down = ((period - Days Since period-day Low)/period) x 100 double down; // day since 25 day high int high; // day since 25 day low int low; Queue<double> highVals = new Queue<double>(); Queue<double> lowVals = new Queue<double>(); int i = 0; foreach(StockPoint point in data) { highVals.Enqueue(point.High); lowVals.Enqueue(point.Low); if(highVals.Count > period) { highVals.Dequeue(); lowVals.Dequeue(); } if (i < period - 1) { i++; } else { high = period - highVals.ToList().IndexOf(highVals.Max()); low = period - highVals.ToList().IndexOf(highVals.Min()); up = ((period - high) / (double)period) * 100; down = ((period - low) / (double)period) * 100; AddValue(point.PointDateTime, key, up, indicators); AddValue(point.PointDateTime, key2, down, indicators); } } }
/// <summary> /// Populates the datagrid with a given StockPoints object. /// </summary> /// <param name="stockPoints">Data to put in the grid.</param> /// <param name="dgv">Grid to fill with data.</param> public static void PopulateGrid(ref StockPoints stockPoints, DataGridView dgv) { string[] terms = new string[8]; int i = 1; foreach (StockPoint s in stockPoints) { terms[0] = string.Empty + i; terms[1] = string.Empty + s.Open; terms[2] = string.Empty + s.High; terms[3] = string.Empty + s.Low; terms[4] = string.Empty + s.Close; terms[5] = string.Empty + s.Volume; terms[6] = s.Time; terms[7] = s.Date; dgv.Rows.Add(terms); i++; } }
// SMA /// <summary> /// Calculates the Simple Moving Average and fills indicators with the data needed to graph it. /// </summary> /// <param name="key">Name of the set to put in the graph key</param> /// <param name="data">StockPoints to calculate the SMA with.</param> /// <param name="indicators">The mfvvalues needed to graph the SMA.</param> /// <param name="period">The number of days to average.</param> /// <param name="offset">Where to start the graph.</param> public static void CalculateSma(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = "SMA(" + period.ToString("00") + ")"; SimpleMovingAverage sma = new SimpleMovingAverage(period); offset = period - 1; foreach (StockPoint point in data) { sma.AddValue(point.Close); if (sma.Period == sma.ValueCount) { AddValue(point.PointDateTime, key, sma.MovingAverage(), indicators); } } }
// RSI /// <summary> /// Calculates the Relative Strength Index and fills indicators with the data needed to graph it. /// </summary> /// <param name="key">Name of the set to put in the graph key</param> /// <param name="data">StockPoints to calculate the Relative Strength Index with.</param> /// <param name="indicators">The mfvvalues needed to graph the RSI.</param> /// <param name="period">The number of days gained/lost to consider.</param> /// <param name="offset">Where to start the graph.</param> public static void CalculateRsi(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = "RSI(" + period.ToString("00") + ")"; ExponentialMovingAverage gains = new ExponentialMovingAverage(period); ExponentialMovingAverage losses = new ExponentialMovingAverage(period); offset = period; int i = 0; StockPoint previousPoint = data[0]; foreach (StockPoint point in data.Skip(1)) { if (previousPoint.Close > point.Close) { losses.AddValue(previousPoint.Close - point.Close); gains.AddValue(0); } else if (previousPoint.Close < point.Close) { gains.AddValue(point.Close - previousPoint.Close); losses.AddValue(0); } if (i < period - 1) { i++; } else { double rsi = 100 - (100 / (1 + (gains.MovingAverage / losses.MovingAverage))); AddValue(point.PointDateTime, key, rsi, indicators); } previousPoint = point; } }
// Money Flow Index public static void CalculateMFI(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = string.Format("MFI({0})", period.ToString("00")); offset = period; // Typical Price = (High + Low + Close)/3 double typicalPrice; // Raw Money Flow = Typical Price x Volume double rawMoneyFlow; // Money Flow Ratio = (x-period Positive Money Flow)/(x-period Negative Money Flow) double moneyFlowRatio; // Money Flow Index = 100 - 100/(1 + Money Flow Ratio) double moneyFlowIndex; double positiveMoneyFlow = 0D; double negativeMoneyFLow = 0D; Queue<double> moneyFlow = new Queue<double>(); double previousTipycalPrice = (data[0].Low + data[0].High + data[0].Close) / 3; int i = 0; foreach (StockPoint point in data.Skip(1)) { typicalPrice = (point.Low + point.High + point.Close) / 3; rawMoneyFlow = typicalPrice * point.Volume; moneyFlow.Enqueue(rawMoneyFlow * (typicalPrice >= previousTipycalPrice ? 1 : -1)); if(moneyFlow.Count > period) { moneyFlow.Dequeue(); } if (i < period - 1) { i++; } else { positiveMoneyFlow = moneyFlow.Where(v => v >= 0).Sum(); negativeMoneyFLow = Math.Abs(moneyFlow.Where(v => v < 0).Sum()); moneyFlowRatio = positiveMoneyFlow / negativeMoneyFLow; moneyFlowIndex = 100 - (100 / (1 + moneyFlowRatio)); AddValue(point.PointDateTime, key, moneyFlowIndex, indicators); } previousTipycalPrice = typicalPrice; } }
// MACD public static void CalculateMACD(out string key, out string key2, out double[] key3, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period1, int period2, int period3, out int offset, out int min, out int max) { min = int.MaxValue; max = int.MinValue; key = string.Format("MACD({0}-{1}-{2})", period1.ToString("00"), period2.ToString("00"), period3.ToString("00")); key2 = string.Format("MACD-SignalLine({0}-{1}-{2})", period1.ToString("00"), period2.ToString("00"), period3.ToString("00")); List<double> hist = new List<double>(); offset = (new List<int>(){period1, period2}.Max()) - 1; ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period1); ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period2); ExponentialMovingAverage ema3 = new ExponentialMovingAverage(period3); int i = 0; foreach(StockPoint point in data) { ema1.AddValue(point.Close); ema2.AddValue(point.Close); double EMA1 = ema1.MovingAverage; double EMA2 = ema2.MovingAverage; double MACDLine = EMA1 - EMA2; ema3.AddValue(MACDLine); if (i < offset) { i++; hist.Add(0); } else { double SignalLine = ema3.MovingAverage; if (min > MACDLine || min > SignalLine) { min = (int)(Math.Floor(MACDLine < SignalLine ? MACDLine : SignalLine)); } if (max < MACDLine || max < SignalLine) { max = (int)(Math.Ceiling(MACDLine > SignalLine ? MACDLine : SignalLine)); } AddValue(point.PointDateTime, key, MACDLine, indicators); AddValue(point.PointDateTime, key2, SignalLine, indicators); hist.Add(MACDLine - SignalLine); } } key3 = hist.ToArray(); }
// TRIX public static void CalculateTRIX(out string key, out string key2, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, int period2, out int offset, out int min, out int max, bool leverage = false) { min = int.MaxValue; max = int.MinValue; key = string.Format("TRIX({0}-{1})", period.ToString("00"), period2.ToString("00")); key2 = string.Format("TRIX-Smooth-({0}-{1})", period.ToString("00"), period2.ToString("00")); offset = 3 * (period > period2 ? period : period2); ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period); ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period); ExponentialMovingAverage ema3 = new ExponentialMovingAverage(period); ExponentialMovingAverage ema4 = new ExponentialMovingAverage(period2); double singleSmooth; double doubleSmooth; double tripleSmooth; double prevTriplesmooth = -1; double trix; int i = 0; foreach (StockPoint point in data) { ema1.AddValue(point.Close); if (i < period) { i++; } else { singleSmooth = ema1.MovingAverage; ema2.AddValue(singleSmooth); if (i < 2 * period) { i++; } else { doubleSmooth = ema2.MovingAverage; ema3.AddValue(doubleSmooth); if (i < 3 * period) { i++; } else { tripleSmooth = ema3.MovingAverage; if (prevTriplesmooth != -1) { trix = (double)decimal.Round((((decimal)tripleSmooth - (decimal)prevTriplesmooth) / (decimal)tripleSmooth) * 100 * (leverage ? 100 : 1), 4); ema4.AddValue(trix); AddValue(point.PointDateTime, key, trix, indicators); AddValue(point.PointDateTime, key2, ema4.MovingAverage, indicators); if (min > trix) min = (int)Math.Floor(trix); if (max < trix) max = (int)Math.Ceiling(trix); } prevTriplesmooth = tripleSmooth; } } } } }
// Chaikin Oscillator public static void CalculateChaikinOscillator(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period1, int period2, out int offset, out int min, out int max) { key = string.Format("ChiOsc({0}:{1})", period1.ToString("00"), period2.ToString("00")); offset = (period2 > period1 ? period2 : period1) - 1; min = int.MaxValue; max = int.MinValue; // Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low) double mfm; // Money Flow Volume = Money Flow Multiplier x Volume for the Period double mfv; // ADL = Previous ADL + Current Period's Money Flow Volume double adl = 0D; // CHaikin Oscillator double co; ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period1); ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period2); int i = 0; foreach (StockPoint point in data) { mfm = ((point.Close - point.Low) - (point.High - point.Close)) / (point.High - point.Low == 0 ? 1 : point.High - point.Low); mfv = mfm * point.Volume; adl = adl + mfv; ema1.AddValue(adl); ema2.AddValue(adl); if (i < period2 - 1) { i++; } else { co = ema1.MovingAverage - ema2.MovingAverage; if (min > co) min = (int)Math.Floor(co); if (max < co) max = (int)Math.Ceiling(co); AddValue(point.PointDateTime, key, co, indicators); } } }
//cci public static void CalculateCCI(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset, out int min, out int max) { key = string.Format("CCI({0})", period.ToString("00")); offset = period - 1; min = int.MaxValue; max = int.MinValue; // cci = (Typical Price - 20-period SMA of TP) / (.015 x Mean Deviation) double cci; // Typical Price (TP) = (High + Low + Close)/3 double typicalPrice; double constant = 0.015; SimpleMovingAverage sma = new SimpleMovingAverage(period); int i = 0; foreach (StockPoint point in data) { typicalPrice = (point.High + point.Close + point.Low) / 3D; sma.AddValue(typicalPrice); if (i < period - 1) { i++; } else { cci = (typicalPrice - sma.MovingAverage())/ (constant * sma.MeanDeviation()); AddValue(point.PointDateTime, key, cci, indicators); if (min > cci) min = (int)Math.Floor(cci); if (max < cci) max = (int)Math.Ceiling(cci); } } }
// calculate Bollinger Bands public static void CalculateBollinger(out string key, out string key2, out string key3, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, int multiplier, out int offset) { key = string.Format("BB-Upper-({0}:{1})", period.ToString("00"), multiplier.ToString("00")); key2 = string.Format("BB-Mid-({0}:{1})", period.ToString("00"), multiplier.ToString("00")); key3 = string.Format("BB-Lower-({0}:{1})", period.ToString("00"), multiplier.ToString("00")); offset = period - 1; double upperBand; double midBand; double lowerBand; SimpleMovingAverage sma = new SimpleMovingAverage(period); SimpleMovingAverage smaPrice = new SimpleMovingAverage(period); int i = 0; foreach (StockPoint point in data) { sma.AddValue(point.Close); if (i < period - 1) { i++; } else { double smaValue = sma.MovingAverage(); double stdMultiplied = sma.StandardDeviation() * multiplier; upperBand = smaValue + stdMultiplied; midBand = smaValue; lowerBand = smaValue - stdMultiplied; AddValue(point.PointDateTime, key, upperBand, indicators); AddValue(point.PointDateTime, key2, midBand, indicators); AddValue(point.PointDateTime, key3, lowerBand, indicators); } } }
/// <summary> /// Draws the Open High Low Close graph. /// </summary> /// <param name="data">The stock points to plot.</param> /// <param name="control">The control to plot on.</param> public void DrawOHLCGraph(ref StockPoints data, ref ZedGraph.ZedGraphControl control) { StockPointList pointList = new StockPointList(); XDate date = new XDate(); foreach (StockPoint s in data) { date = new XDate(s.PointDateTime.Year, s.PointDateTime.Month, s.PointDateTime.Day, s.PointDateTime.Hour, s.PointDateTime.Minute, 0); StockPt p = new StockPt(date.XLDate, s.High, s.Low, s.Open, s.Close, s.Volume); pointList.Add(p); } Color[] colors = { Color.Red, Color.Black }; Fill myFill = new Fill(colors); myFill.Type = FillType.GradientByColorValue; myFill.SecondaryValueGradientColor = Color.Empty; myFill.RangeMin = 1; myFill.RangeMax = 2; MasterPane masterPane = control.MasterPane; masterPane.Margin.All = 10; masterPane.InnerPaneGap = 5; GraphPane ohlcPane = new GraphPane(new Rectangle(10, 10, 10, 10), "OHLC", "Time", "Price"); ohlcPane.IsBoundedRanges = true; OHLCBarItem bar = ohlcPane.AddOHLCBar("Price", pointList, Color.Empty); bar.Bar.GradientFill = myFill; bar.Bar.IsAutoSize = true; bar.Bar.Size = 5; ohlcPane.Title.Text = "OHLC Graph"; ohlcPane.XAxis.Type = AxisType.DateAsOrdinal; ohlcPane.XAxis.Title.Text = "Date"; ohlcPane.YAxis.Title.Text = "Price"; ohlcPane.Margin.All = 0; ohlcPane.Margin.Top = 10; ohlcPane.YAxis.MinSpace = 10; ohlcPane.Y2Axis.MinSpace = 10; ohlcPane.AxisChange(); masterPane.Add(ohlcPane); control.IsShowHScrollBar = true; control.ScrollMinX = 0; control.ScrollMaxX = data.Count; control.GraphPane.XAxis.Scale.Max = data.Count; if (data.Count >= 99) { control.GraphPane.XAxis.Scale.Min = data.Count - 99; } else { control.GraphPane.XAxis.Scale.Min = 0; } using (Graphics g = control.CreateGraphics()) { masterPane.SetLayout(g, PaneLayout.SingleColumn); masterPane.AxisChange(g); // Synchronize the Axes //// g.Dispose(); } }
public StockPointBuilder() { this.stockPoint = new StockPoints(); }
// Full Stochastic /// <summary> /// Calculates the Full Stochastic Oscillator and fills indicators with the data needed to graph it. /// </summary> /// <param name="key">Name of the first set to put in the graph key</param> /// <param name="key2">Name of the second set to put in the graph key</param> /// <param name="data">StockPoints to calculate the Full Stochastic with.</param> /// <param name="indicators">The mfvvalues needed to graph the Full Stochastic.</param> /// <param name="period1">The number of period to calculate Fast Stochastic.</param> /// <param name="period2">The number of period to calculate SMA of Fast Stochastic.</param> /// <param name="period3">The number of period to calculate SMA of calculated SMA of Fast Stochastic.</param> /// <param name="offset">Where to start the graph.</param> public static void CalculateStochastic(out string key, out string key2, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period1, int period2, int period3, out int offset) { key = string.Format("Full STO %K({0}:{1})", period1.ToString("00"), period2.ToString("00")); key2 = string.Format("Full STO %D({0})", period3.ToString("00")); offset = period1 - 1; SimpleMovingAverage ksma = new SimpleMovingAverage(period2); SimpleMovingAverage dsma = new SimpleMovingAverage(period3); // lowest among the lowest for the chosen period double lowestLow; // highest among the highest for the chosen period double highestHigh; // Lowest Low = lowest low for the look-back period // Highest High = highest high for the look-back period // fastk = (Current Close - Lowest Low)/(Highest High - Lowest Low) * 100 double fastk; // fullk smoothed with X-period SMA double fullk; // X-period SMA of Full fullk double fulld; int i = 0; // loop through each stockpoint skipping the foreach (StockPoint point in data) { lowestLow = data.Skip(data.IndexOf(point) - (period1 - 1)).Take(period1).OrderBy(sp => sp.Low).FirstOrDefault().Low; highestHigh = data.Skip(data.IndexOf(point) - (period1 - 1)).Take(period1).OrderByDescending(sp => sp.High).FirstOrDefault().High; fastk = (point.Close - lowestLow) / (highestHigh - lowestLow == 0 ? 1 : highestHigh - lowestLow) * 100; ksma.AddValue(fastk); fullk = ksma.MovingAverage(); dsma.AddValue(fullk); fulld = dsma.MovingAverage(); if (i < period1 - 1) { i++; } else { AddValue(point.PointDateTime, key, fullk, indicators); AddValue(point.PointDateTime, key2, fulld, indicators); } } }
// CMF /// <summary> /// Calculates the Chaikin Money Flow Index and fills indicators with the data needed to graph it. /// </summary> /// <param name="key">Name of the set to put in the graph key</param> /// <param name="data">StockPoints to calculate the Chaikin Money Flow with.</param> /// <param name="indicators">The mfvvalues needed to graph the Chaikin Money Flow.</param> /// <param name="period">The number of period to consider.</param> /// <param name="offset">Where to start the graph.</param> public static void CalculateCMF(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = string.Format("CMF({0})", period.ToString("00")); offset = period - 1; // Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low) double mfm; // Money Flow Volume = Money Flow Multiplier x Volume for the Period double mfv; // Chaikin money flow ChaikinMoneyFlow cmf = new ChaikinMoneyFlow(period); // Given Period Chaikin Money Flow value double cmfValue; int i = 0; foreach(StockPoint point in data) { mfm = ((point.Close - point.Low) - (point.High - point.Close)) / (point.High - point.Low == 0 ? 1 : point.High - point.Low); mfv = mfm * point.Volume; cmf.AddMFVValue(mfv); cmf.AddVolumeValue(point.Volume); if (i < period - 1) { i++; } else { cmfValue = cmf.CalculateChaikinMoneyFlow(); AddValue(point.PointDateTime, key, cmfValue, indicators); } } }
// Stochastic RSI public static void CalculateStochasticRSI(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset, bool leverage = true) { key = string.Format("StocRSI({0})", period.ToString("00")); ExponentialMovingAverage gains = new ExponentialMovingAverage(period); ExponentialMovingAverage losses = new ExponentialMovingAverage(period); offset = period * 2; double rsi; double stochRSI; double highestRSI; double lowestRSI; Queue<double> rsiQueue = new Queue<double>(); StockPoint previousPoint = data[0]; int i = 0; foreach (StockPoint point in data.Skip(1)) { if (previousPoint.Close > point.Close) { losses.AddValue(previousPoint.Close - point.Close); gains.AddValue(0); } else if (previousPoint.Close < point.Close) { gains.AddValue(point.Close - previousPoint.Close); losses.AddValue(0); } if (i < period - 1) { i++; } else { rsi = 100 - (100 / (1 + (gains.MovingAverage / losses.MovingAverage))); rsiQueue.Enqueue(rsi); if (rsiQueue.Count > period) { rsiQueue.Dequeue(); } if (rsiQueue.Count == period) { highestRSI = rsiQueue.Max(); lowestRSI = rsiQueue.Min(); stochRSI = (rsi - lowestRSI) / (highestRSI - lowestRSI) * (leverage ? 100 : 1); AddValue(point.PointDateTime, key, stochRSI, indicators); } } previousPoint = point; } }
// EMA /// <summary> /// Calculates the Exponential Moving Average and fills indicators with the data needed to graph it. /// </summary> /// <param name="key">Name of the set to put in the graph key</param> /// <param name="data">StockPoints to calculate the EMA with.</param> /// <param name="indicators">The mfvvalues needed to graph the EMA.</param> /// <param name="period">The number of days to average.</param> /// <param name="offset">Where to start the graph.</param> public static void CalculateEma(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset) { key = "EMA(" + period.ToString("00") + ")"; ExponentialMovingAverage ema = new ExponentialMovingAverage(period); offset = period - 1; int i = 0; foreach (StockPoint point in data) { ema.AddValue(point.Close); if (i < offset) { i++; } else { AddValue(point.PointDateTime, key, ema.MovingAverage, indicators); } } }
/// <summary> /// Add a horizontal line to the graph /// </summary> /// <param name="key">The name of the line to graph.</param> /// <param name="data">A list of stock points to get the date time range. (x-axis)</param> /// <param name="lineValue">The location of the line. (y-axis)</param> /// <param name="indicators">The dictionary to add the line to.</param> public static void GetHorizontalLine(string key, StockPoints data, double lineValue, Dictionary<DateTime, Dictionary<string, double>> indicators) { for (int i = 0; i < data.Count; i++) { AddValue(data[i].PointDateTime, key, lineValue, indicators); } }
public VariantsBuilder WithStockPoint(StockPoints stockPoint) { this.variants.stockPoints.Add(stockPoint); return(this); }