public static void DeMarkSetupForChart(UltraChart chart, ConstructGen<double> candleData_, bool isDateChart, int openIndex_=0, int highIndex_=1, int lowIndex_=2, int closeIndex_=3, int setupLength_=9, int countdownLength_=13) { var closes = candleData_.GetColumnValuesAsDDC(closeIndex_); var range = closes.Data.Max() - closes.Data.Min(); var cellHeight = range / 10d; var setupStarts = Analysis.GetSetups(candleData_, openIndex_, highIndex_, lowIndex_, closeIndex_, setupLength_); Analysis.AddCountdowns(candleData_, setupStarts, openIndex_, highIndex_, lowIndex_, closeIndex_, setupLength_, countdownLength_); for (int i = 0; i < candleData_.Dates.Count; ++i) { var date = candleData_.Dates[i]; var arr = candleData_.GetValues(date); //dt.LoadDataRow(new object[] //{ // date, // arr[openIndex_], // arr[highIndex_], // arr[lowIndex_], // arr[closeIndex_], // 0d //}, true); foreach (var mark in setupStarts) { addAnnotations(chart, date, mark, i, cellHeight, arr, openIndex_, highIndex_, lowIndex_, closeIndex_); } } }
public void Create(ConstructGen<double> candleData_, int openIndex_ = 0, int highIndex_ = 1, int lowIndex_ = 2, int closeIndex_ = 3, int setupLength_=9, int countdownLength_=13) { var dt = new DataTable(); dt.Rows.Clear(); dt.Columns.Clear(); dt.Columns.Add("Date", typeof(DateTime)); dt.Columns.Add("Open", typeof(double)); dt.Columns.Add("High", typeof(double)); dt.Columns.Add("Low", typeof(double)); dt.Columns.Add("Close", typeof(double)); dt.Columns.Add("Volume", typeof(double)); ultraChart1.DataSource = dt; var closes = candleData_.GetColumnValuesAsDDC(closeIndex_); var range = closes.Data.Max() - closes.Data.Min(); var cellHeight = range/10d; var setupStarts = DeMarkAnalysis.GetSetups(candleData_,openIndex_,highIndex_,lowIndex_,closeIndex_,setupLength_); DeMarkAnalysis.AddCountdowns(candleData_, setupStarts,openIndex_,highIndex_,lowIndex_,closeIndex_,setupLength_,countdownLength_); for (int i = 0; i < candleData_.Dates.Count; ++i) { var date = candleData_.Dates[i]; var arr = candleData_.GetValues(date); dt.LoadDataRow(new object[] { date, arr[openIndex_], arr[highIndex_], arr[lowIndex_], arr[closeIndex_], 0d }, true); foreach(var mark in setupStarts) { addAnnotations(date, mark, i, cellHeight, arr,openIndex_,highIndex_,lowIndex_,closeIndex_); } } EstablishDefaultTooltip(hash => { int rowNumber = (int) hash["DATA_ROW"]; return string.Format("{0} Open: {1}, High: {2}, Low: {3}, Close: {4}", ((DateTime) dt.Rows[rowNumber]["Date"]).ToString("dd-MMM-yyyy"), ((double) dt.Rows[rowNumber]["Open"]).ToString(CultureInfo.InvariantCulture), ((double)dt.Rows[rowNumber]["High"]).ToString(CultureInfo.InvariantCulture), ((double)dt.Rows[rowNumber]["Low"]).ToString(CultureInfo.InvariantCulture), ((double)dt.Rows[rowNumber]["Close"]).ToString(CultureInfo.InvariantCulture) ).Replace(",", System.Environment.NewLine); }); }
public static MarketViewItem ComputeMarketRatio(InstrumentPriceItem inputItem, ConstructGen<double> histData) { // get historical high low double high=0; double low=0; if (histData != null) { high = histData.GetColumnValuesAsDDC(1).Data.Max(); low = histData.GetColumnValuesAsDDC(2).Data.Min(); } return new MarketViewItem { Instrument = inputItem.Instrument, LivePrice = inputItem.Close, High = high, Low = low, Ratio = histData == null ? 0 : (inputItem.IsLong ? Math.Round((inputItem.Close - low) / (high - low), 3) : Math.Round((inputItem.Close - high) / (low - high), 3)), }; }
public static void Go() { // var is like 'dim' // make an array of size 10 - each initalized to the default double value i.e. 0d var arr = new double[10]; // I could 'initialise' the values of this array in one call: arr = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // an expanding construct is a list // make a list that I can only put doubles into var list = new List<double>(); list.Add(1); list.Add(2); list.Add(3); // this is exactly the same as using an intializer: list = new List<double> {1, 2, 3}; // I can use in built stuff to convert this to an array really easily double[] arr2 = list.ToArray(); // dictionaries are lookups or hashmaps with types var birthdays = new Dictionary<string, DateTime>(); birthdays.Add("Ben", new DateTime(1979, 12, 11)); //or birthdays["Jess"] = new DateTime(1985, 1, 19); // note, the first method (.Add) will throw an exception if the item already exists, the second method will just overwrite // might be better to: if (birthdays.ContainsKey("Ben")) birthdays.Add("Ben", new DateTime(1979, 12, 11)); // as we're dealing with time series a lot, I have created some classes that make it easier to work with dates and associated values // first of these is DatedDataCollection<T> where T is normally 'double'. // these are created with an array of Dates, and an array of 'Ts', which obviously must be of the same length, as the values correspond // NOTE: creating array on 1st, 3rd, 5th var dtsArray = new DateTime[] {new DateTime(2001, 1, 1), new DateTime(2001, 1, 3), new DateTime(2001, 1, 5)}; var valuesArray = new double[] {1.21, 1.45, 1.65}; var ddc = new DatedDataCollectionGen<double>(dtsArray, valuesArray); // obviously you wouldn't put normally create ddc like this - it normally gets populated from calls the the database or bbg initially, but we'll // look at that later var date4th = new DateTime(2001, 1, 4); var value = ddc.ValueOnExactDate(date4th); // this will fail as I'm insisting on the date being exact and there's nothing for 4th var value2 = ddc.ValueOnDate(date4th); // this will give me a value equal to that on the 3rd, since that is value for max date that is before 4th var value3 = ddc.ValueOnExactDate_Zero(date4th); // this won't fail but will pass back zero if there isn't an exact date // I've extended the classes to make it really easy to plot and see stuff ddc.DisplayColumnChart("Values in column chart"); ddc.DisplayInGrid("values in grid"); ddc.DisplayLineChart("Line chart"); // this might be a bit of a leap, but I could very quickly extract EUR values from bloomberg in the following way, and display in a graph BbgTalk.HistoryRequester.GetHistory(new DateTime(2001, 1, 1),"EUR Curncy","PX_CLOSE",true) .DisplayLineChart("EUR from bbg from 2001"); // what's this done? // BbgTalk.HistoryRequest knows how to connect to bloomberg and pulls out the series as a DatedDataCollection (so long as you're logged into bloomberg) DatedDataCollectionGen<double> euroSeries = BbgTalk.HistoryRequester.GetHistory(new DateTime(2001, 1, 1), "EUR Curncy", "PX_CLOSE", true); // then we displayed in a line chart: euroSeries.DisplayLineChart("EUR"); // what else could we do with this euro series? // convert to returns: var euroReturns = euroSeries.ToReturns(); var cumulative = euroReturns.ToCumulative(); var stdFromMean = euroSeries.ToStdevFromMean(meanWindowLength_: 21, sdWindowLength_: 126); // I've also done a load of stuff to transform this series, take a look at HelperMethods. // often, we don't deal with individual price series, though we need inline data // for this I have made something called ConstructGen<T>, where again, T is normally a double var firstConstruct = new ConstructGen<double>(9); // this has made a construct that is set up to store dated values for 9 different variables // it's good to set the columnHeadings on the construct so you know what they refer to var headings = new string[] {"AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "NOK", "NZD", "SEK"}; firstConstruct.ColumnHeadings = headings; // (I'll show you how to do this more easily in a bit... // let's look at what we can do with construct and how we use it DateTime conDate = new DateTime(2014, 1, 1); firstConstruct.SetValue(conDate, 0, 100.2); // this has set the value for the first column (AUD) on the given Date // we get it out by: var v1 = firstConstruct.GetValue(conDate, 0); // set the second value: firstConstruct.SetValue(conDate, 1, 45.6); // this has set the value for the given date for 'CAD' // we could set all values at once using SetValues rather than SetValue firstConstruct.SetValues(conDate, new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9}); // and we could get them out using: double[] allValuesOnDate = firstConstruct.GetValues(conDate); // there are lots of methods on Construct<T> to make our life easier when dealing with data // we can fill it up randomly using the SetValues, and then just call SortKeys() to ensure teh dates are in order firstConstruct.SortKeys(); // this means that we will be iterate over the dates in order when we go through it // e.g. foreach (DateTime date in firstConstruct.Dates) { var datesVAlues = firstConstruct.GetValues(date); // here we could process them... } // there are methods on ConstructGen<T> to make it easy to see what's in it. e.g. firstConstruct.DisplayInGrid("Grid of construct values"); firstConstruct.DisplayInDataCollectionDisplay("Display each column as a line in a chart"); // there is also a useful method to get the column of values as a DatedDataCollection<T> DatedDataCollectionGen<double> firstColumn = firstConstruct.GetColumnValuesAsDDC(0); // this is an expensive operation FYI, so you wouldn't use this iterating over the dates within the ConstructGen<T> , but it is useful // ok, now, as we have a set universe of ccys, in the way I extract data from the database (prices / weights / carry / etc) I tend to pull // out in a standard way, making a ConstructGen<double> with a column for every currency in the universe // so, for example, if I wanted the spots from the database from 2013 onwards, I would call this SI.Data.FXSpots spotsProvider = new FXSpots(); ConstructGen<double> spots = spotsProvider.GetData(new DateTime(2013, 1, 1), DateTime.Today); // this returns me a ConstructGen<double> with 27 columns, with each row being a date // I can then use the spots values as I wish // similarly SI.Data.FXForwards1Wk fwdProvider = new FXForwards1Wk(); ConstructGen<double> fwds = fwdProvider.GetData(new DateTime(2013, 1, 1), DateTime.Today); // within these classes, the data is cached, so that I don't call the database again if I don't need to // so if I call for the second time: var spots2 = spotsProvider.GetData(new DateTime(2013, 1, 1), DateTime.Today); // ... this won't have hit the database again, but will get from the cached data // but you'll notice that i have to have a reference to spotsProvider to benefit from the cached data. // if I was to make the same request from another point in my code, I would have to create a new FXSpots() instance and then call the method on it to get the data // it can be useful in this instance to make use of what's known as the 'Singleton' pattern. // This basically provides a means of referring to the same instance every time, in this case so that we make use of cached data // I have a Singleton<T> wrapper that wraps up a single instance of T so that I know I'm calling methods on the same instance every time // so I would usually get spots from the database wrapping FXSpots in this. like: spots = Singleton<FXSpots>.Instance.GetData(new DateTime(2013, 1, 1), DateTime.Today); // now I could call the method on Singleton<FXSpots>.Instance from anywhere in my code and I would benefit from the caching // I do tend to use most of the classes that retrive from the database Within SI.Data wrapped in a Singleton // another example is the class that pulls information about signals var signals = Singleton<Signals>.Instance; // this is just a list of SI.Data.Signal classes }
private void buildData() { var pxDates = new List<DateTime>(); var pxValues = new List<double>(); for (int y = 2003;y <= DateTime.Now.Year; ++y) { // find the contracts var conLon = Long.Underlying.Futures.Where(x => x.Expiry.Year-Long.YearOffset == y && x.Expiry.Month == (int)Long.Month).FirstOrDefault(); var conShort = Short.Underlying.Futures.Where(x => x.Expiry.Year-Short.YearOffset == y && x.Expiry.Month == (int)Short.Month).FirstOrDefault(); if (conLon != null && conShort != null) { m_contractsLongShort.Add(y, new KeyValuePair<ComFutureMeta, ComFutureMeta>(conLon, conShort)); // last trade of this pair is the earliest lastTrade date of the two var lastTrade = (conLon.LastTrade < conShort.LastTrade) ? conLon.LastLastDate : conShort.LastLastDate; var dataStart = lastTrade.AddYears(-1); if (MyCalendar.IsWeekend(dataStart)) dataStart = MyCalendar.NextWeekDay(dataStart); ConstructGen<double> con = new ConstructGen<double>(new string[] { conLon.Ticker, conShort.Ticker, "Diff", "Normalized" }); con.SetColumnValues((int)dataColumns.Long, conLon.Prices.GetSubValues(dataStart, lastTrade)); con.SetColumnValues((int)dataColumns.Short, conShort.Prices.GetSubValues(dataStart, lastTrade)); if (con.NeedsToSortKeys()) con.SortKeys(); if (con.Dates.Count == 0) continue; // calculate differences foreach (DateTime date in con.Keys) { double[] d = con.GetValues(date); // if we have a value for both contracts on this day if (d[(int)dataColumns.Long] != 0d && d[(int)dataColumns.Short] != 0d) { // save down the difference d[(int)dataColumns.Diff] = d[(int)dataColumns.Long] - d[(int)dataColumns.Short]; if (date.Year == y) { pxDates.Add(date); pxValues.Add(d[2]); } } } // normalize differences { DatedDataCollectionGen<double> diffs = con.GetColumnValuesAsDDC((int)dataColumns.Diff); if (diffs==null || diffs.Length == 0) continue; var min = diffs.Data.Min(); var max = diffs.Data.Max(); var normArr = new double[diffs.Length]; for (int i = 0; i < normArr.Length; ++i) normArr[i] = (diffs.Data[i] - min) / (max - min); con.SetColumnValues((int)dataColumns.NormalizedDiff, new DatedDataCollectionGen<double>(diffs.Dates, normArr)); } m_yearToPxs.Add(y, con); } } m_hasBuiltData = true; }
public void ShowPortfolioPnlProgression() { var pnl = new ConstructGen<double>(Positions.Select(x=>x.Security).ToArray()); var flp = new System.Windows.Forms.FlowLayoutPanel(); var listOfInfraBoxes = new List<Infragistics.Win.Misc.UltraGroupBox>(); for (int i = 0; i < pnl.ArrayLength; ++i) { var posPnl = Positions[i].GeneratePnlSinceFix(); for (int d = 0; d < posPnl.Length; ++d) { pnl.SetValue(posPnl.Dates[d], i, posPnl.Data[d].Close); } { Infragistics.Win.Misc.UltraGroupBox box = new Infragistics.Win.Misc.UltraGroupBox(); box.Text = string.Format("{0} {1}", Positions[i].Security, Positions[i].Pnl.ToString("###0.0#;(###0.0#);-")); box.Tag = Positions[i].Pnl; box.Size = new System.Drawing.Size(250, 250); var chart = new SI.Controls.BarDataPointChart(); chart.SetYAxisFormat("##0.0#"); chart.Dock = System.Windows.Forms.DockStyle.Fill; chart.Create(posPnl); box.Controls.Add(chart); listOfInfraBoxes.Add(box); } } Infragistics.Win.Misc.UltraGroupBox[] boxArr = listOfInfraBoxes.OrderByDescending(x => (double)x.Tag).ToArray(); { double max = 0d; foreach (Infragistics.Win.Misc.UltraGroupBox box in boxArr) { max = Math.Max(max, ((SI.Controls.BarDataPointChart)box.Controls[0]).YAxisAbsoluteMax); } foreach (Infragistics.Win.Misc.UltraGroupBox box in boxArr) { ((SI.Controls.BarDataPointChart)box.Controls[0]).SetMaxMinYAxisRange(max); } } foreach (Infragistics.Win.Misc.UltraGroupBox box in boxArr) { flp.Controls.Add(box); } pnl.SortKeys(); for (int i = 0; i < pnl.ArrayLength; ++i) { DatedDataCollectionGen<double> col = pnl.GetColumnValuesAsDDC(i); double last = col.Data[0]; for (int j = 1; j < col.Length; ++j) { double val = col.Data[j]; if (val == 0d) { if (last != 0d) { pnl.SetValue(col.Dates[j], i, last); } } else last = val; } } DatedDataCollectionGen<double> total = pnl.SumRows(); KeyValuePair<string, System.Windows.Forms.Control>[] cons = new KeyValuePair<string, System.Windows.Forms.Control>[3]; var stack = new Controls.SimpleStackedColumnChart(); stack.Create<string, string>( pnl.Dates.Select(x => x.ToString("HH:mm")).ToArray(), Positions.Select(x => x.Security).ToArray(), pnl.ToArray()); cons[0] = new KeyValuePair<string, System.Windows.Forms.Control>("position attributed", stack); //stack.DisplayInShowForm(string.Format("{0} pnl progression, position attributed", this.Name)); var lcdd = new SI.Controls.LineChartDataDisplay(); lcdd.AddSeries(total.Dates, total.Data, Name, 40, "#0.0#"); lcdd.SetXAxisFormat("HH:mm"); //lcdd.DisplayInShowForm(string.Format("{0} total pnl progression", m_p.DisplayName)); cons[1] = new KeyValuePair<string, Control>("total", lcdd); cons[2] = new KeyValuePair<string, Control>("comp", flp); cons.DisplayInShowForm(string.Format("{0} pnl progression", Name)); }
public void AddCandleSeries(ConstructGen<double> values, string description) { SI.Controls.LookFeel.ProcessControl(lineChartDataDisplay1); lineChartDataDisplay1.AddCandleSeries(values, description, 40, "###0.000"); //lineChartDataDisplay1.AddDeMarkSeries(values); Rescale(values.GetColumnValuesAsDDC(1)); }
public static ConstructGen<double> GetFlow(ConstructGen<double> wts_) { var ret = new ConstructGen<double>(wts_.ColumnHeadings); for (int i = 0; i < wts_.ArrayLength; ++i) { ret.SetColumnValues(i, wts_.GetColumnValuesAsDDC(i).ToDifferences().ToAbs()); } return ret; }
public static List<HoldingPeriod> GenerateHoldingPeriods(ConstructGen<double> historicalWeights_, double? trimDistributionsBy_=null) { var ret = new List<HoldingPeriod>(); for (int colIndex = 0; colIndex < historicalWeights_.ArrayLength; ++colIndex) { var colVals = historicalWeights_.GetColumnValuesAsDDC(colIndex); if (colVals.Data.SumAbs() == 0d) continue; Dictionary<WtState, List<double>> dict = new Dictionary<WtState, List<double>>(); WtState currentState = WtState.None; DateTime stateStart = DateTime.MinValue; for (int i = 0; i < colVals.Length; ++i) { var wt = colVals.Data[i]; WtState newState = (wt > 0d) ? WtState.Long : (wt < 0d) ? WtState.Short : WtState.Flat; if (currentState == WtState.None) { stateStart = colVals.Dates[i]; currentState = newState; } else if (newState == currentState) { // do nothing } else // we have a new state { var ts = colVals.Dates[i] - stateStart; if (!dict.ContainsKey(currentState)) dict[currentState] = new List<double>(); dict[currentState].Add(MyCalendar.NumBusinessDaysBetween(stateStart,colVals.Dates[i])); currentState = newState; stateStart = colVals.Dates[i]; } } // commit the last values { } var hp = new HoldingPeriod() { Ccy=historicalWeights_.ColumnHeadings[colIndex], State=currentState, Held=MyCalendar.NumBusinessDaysBetween(stateStart,DateTime.Today), Wt=colVals.Data.Last() }; foreach (var key in dict.Keys) { if (trimDistributionsBy_.HasValue && trimDistributionsBy_.Value >0d && trimDistributionsBy_ <1d) { var series = dict[key].OrderBy(x => x); int numberInTail = Convert.ToInt32(series.Count() * trimDistributionsBy_.Value); //var subset = series.TakeWhile<double>( } hp.SetValues(key, dict[key]); } ret.Add(hp); } return ret; }
public static void AddCountdowns(ConstructGen<double> prices_, List<DeMarkMarker> topLevelSetups_, int openIndex_ = 0, int highIndex_ = 1, int lowIndex_ = 2, int closeIndex_ = 3, int setupSeriesLength_ = 9, int countdownLength_ = 13) { var closes = prices_.GetColumnValuesAsDDC(closeIndex_); var opens = prices_.GetColumnValuesAsDDC(openIndex_); var highs = prices_.GetColumnValuesAsDDC(highIndex_); var lows = prices_.GetColumnValuesAsDDC(lowIndex_); var tuples = new List<Tuple<DeMarkMarker, DeMarkMarker>>(); foreach (var v in topLevelSetups_.Where(x => x.Disabled.HasValue == false)) { tuples.Add(new Tuple<DeMarkMarker, DeMarkMarker>(v, v.Children.FirstOrDefault( x => (x.EventType == DeMarkEventType.BuySetupIndex || x.EventType == DeMarkEventType.SellSetupIndex) && x.SeriesIndex == 9))); } foreach (var t in tuples) { var setupEnd = t.Item2; if (setupEnd == null) continue; DateTime? nextSetupEnd = null; { var s = tuples.Where(x => x.Item2 != null).ToArray(); if(s.Any()) { var series = s.Where(x => x.Item2.Date > setupEnd.Date && x.Item1.EventType != t.Item1.EventType).ToArray(); if (series.Any()) nextSetupEnd = series.OrderBy(x => x.Item2.Date).First().Item2.Date; } } int count = 0; for (int i = setupEnd.PriceIndex; i < closes.Length; ++i) { var date = closes.Dates[i]; // if a new setup has set, then don't continue with the countdown (aka 'recycling') if (nextSetupEnd.HasValue && nextSetupEnd == date && count < 12) { i = closes.Length; //t.Item1.Disabled = true; continue; } switch (setupEnd.EventType) { case DeMarkEventType.BuySetupIndex: // series has been going down { if ((closes.Data[i] <= lows.Data[i - 2]) || (count == 12 && opens.Data[i] <= lows.Data[i - 2])) { ++count; t.Item1.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.ReducingCountDown, PriceIndex = i, SeriesIndex = count, CountDownLength = countdownLength_, }); } if (count == countdownLength_) { t.Item1.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.CountDownStop, PriceIndex = i, SeriesIndex = count }); i = closes.Length; } } break; case DeMarkEventType.SellSetupIndex: // series has been going up { if ((closes.Data[i] >= highs.Data[i - 2]) || (count == 12 && opens.Data[i] >= highs.Data[i - 2])) { ++count; t.Item1.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.IncreasingCountDown, PriceIndex = i, SeriesIndex = count, CountDownLength = countdownLength_, }); } if (count == countdownLength_) { t.Item1.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.CountDownStop, PriceIndex = i, SeriesIndex = count }); i = closes.Length; } } break; } } } }
public static List<DeMarkMarker> GetSetups(ConstructGen<double> prices_, int openIndex_ = 0, int highIndex_ = 1, int lowIndex_ = 2, int closeIndex_ = 3, int targetSeriesLength = 9) { var closes = prices_.GetColumnValuesAsDDC(closeIndex_); var highs = prices_.GetColumnValuesAsDDC(highIndex_); var lows = prices_.GetColumnValuesAsDDC(lowIndex_); var ret = new List<DeMarkMarker>(); int lowerSetupCount = 0; int higherSetupCount = 0; for (int i = 4; i < closes.Length; ++i) { { if (closes.Data[i] < closes.Data[i - 4]) { /////Setup Cancellation//// //if the setups do not reach the target, we cancel the setup if (higherSetupCount > 0 && higherSetupCount < targetSeriesLength) { higherSetupCount = 0; ret.RemoveAt(ret.Count - 1); } ++lowerSetupCount; } else { /////Setup Cancellation//// //if the setups do not reach the target, we cancel the setup if (lowerSetupCount > 0 && lowerSetupCount < targetSeriesLength) ret.RemoveAt(ret.Count - 1); lowerSetupCount = 0; } if (lowerSetupCount > 0) { if (lowerSetupCount == 1) { // setups start. var mark = new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.BuySetupStart, PriceIndex = i, SeriesIndex = 1, SetupSeriesLength = targetSeriesLength, }; ret.Add(mark); } var recentSetupStart = ret.Last(); recentSetupStart.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.BuySetupIndex, PriceIndex = i, SeriesIndex = lowerSetupCount, SetupSeriesLength = targetSeriesLength, }); if (lowerSetupCount == targetSeriesLength) { lowerSetupCount = 0; if ((lows.Data[i] <= lows.Data[i-2] && lows.Data[i] <= lows.Data[i-3]) || (lows.Data[i-1] <= lows.Data[i-2] && lows.Data[i] <= lows.Data[i-3])) recentSetupStart.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.PerfectedBuySetup, PriceIndex = i, SeriesIndex = lowerSetupCount, SetupSeriesLength = targetSeriesLength, }); } } } { if (closes.Data[i] > closes.Data[i - 4]) { if (lowerSetupCount > 0 && lowerSetupCount < targetSeriesLength) { lowerSetupCount = 0; ret.RemoveAt(ret.Count - 1); } ++higherSetupCount; } else { /////Setup Cancellation//// //if the setups do not reach the target, we cancel the setup if (higherSetupCount > 0 && higherSetupCount < targetSeriesLength) ret.RemoveAt(ret.Count - 1); higherSetupCount = 0; } if (higherSetupCount > 0) { if (higherSetupCount == 1) { var mark = new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.SellSetupStart, PriceIndex = i, SeriesIndex = 1, SetupSeriesLength = targetSeriesLength, }; ret.Add(mark); } var recentSetupStart = ret.Last(); recentSetupStart.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.SellSetupIndex, PriceIndex = i, SeriesIndex = higherSetupCount, SetupSeriesLength = targetSeriesLength, }); if (higherSetupCount == targetSeriesLength) { higherSetupCount = 0; if ((highs.Data[i] >= highs.Data[i - 2] && highs.Data[i] >= highs.Data[i - 3]) || (highs.Data[i - 1] >= highs.Data[i - 2] && highs.Data[i] >= highs.Data[i - 3])) recentSetupStart.AddChild(new DeMarkMarker { Date = closes.Dates[i], EventType = DeMarkEventType.PerfectedSellSetup, PriceIndex = i, SeriesIndex = lowerSetupCount, SetupSeriesLength = targetSeriesLength, }); } } } } // if one setup immediately continues in the another one, // then disable the latter one if (ret.Count > 1) for (int i = 1; i < ret.Count; ++i) { if (ret[i].Disabled.HasValue == false && ret[i - 1].Disabled.HasValue == false && ret[i].EventType == ret[i - 1].EventType && ret[i].PriceIndex == (ret[i - 1].PriceIndex + targetSeriesLength)) ret[i].Disabled = ret[i - 1].Date; } return ret; }