Parent: TimeSeries
IndicatorBase is the base class for indicators in WealthLab. It is derived from TimeSeries, and basically contains a list of floating point double Values keyed off a list of DateTimes. The class contains additional methods and properties that let it work with the indicator management subsystem of WealthLab, and will be most useful for developers creating their own custom indicators.
Copies the Values of the TimeSeries specified in ts into the Values of the indicator, after first clearing them out.
The method is meant to be used in custom Indicators which calculate a partial update for streaming charts, its only consumer. The calculated value should be assigned to the StreamingValue property. below is a reference implementation used in SMA:
//calculate partial value public override bool CalculatePartialValue() { StreamingValue = Double.NaN; TimeSeries source = Parameters[0].AsTimeSeries; if (Double.IsNaN(source.StreamingValue)) return false; Int32 period = Parameters[1].AsInt; if (period >= source.Count) return false; double sum = 0; for (int n = 0; n < period - 1; n++) { var i = source.Count - 1 - n; sum += source[i]; } sum += source.StreamingValue; StreamingValue = sum / period; return true; }
Returns the List<Parameter> that contains the indicator's parameters. Each parameter is an instance of the Parameter class.
WealthLab calls this method to populate the indicator with values. Each class descending from IndicatorBase provides its own implementation and calculates its indicator values here.
If the indicator has a pair indicator, this will return the instance of that companion indicator using the same parameters as the source indicator. This is used by the Bands plot style to determine what indicator to use when plotting the bands.
Returns the name of the indicator's band pair, if availoable. For example, BBandUpper's BandCompanion is BBandLower. The BandCompanion is used to determine what other indicator to use by the Bands plot style.
Returns the Abbreviations of any other indicators that are considered part of this indicator's family. An example family is Directional Movement which includes the indicators ADX, ADXR, DIPlus and DIMinus.
The TimeSeries class has three constructors. The first, parameterless constructor, creates a TimeSeries instance that manages its own DateTimes. When adding values to this instance, use the Add method that includes a DateTime parameter. The second and third constructors include a dateTimes parameter. This List of DateTimes becomes the TimeSeries' DateTimes property. The second constructor, by default, pre-populates the TimeSeries Values with Double.Nan. You can disable this by passing false in the fillNaN parameter. If you do so, be sure to Add values to the TimeSeries yourself (using the version that adds values only, not DateTimes), a number of values equal to the number of DateTimes. The last constructor accept a fillValue parameter which determines what value the TimeSeries will be pre-populated with.
Returns the abbreviation of the indicator.
The color to use when plotting the indicator.
Returns the default color to use when plotting the indicator.
Returns the default plot style to use when plotting the indicator.
Returns a 24x24 bitmap that is used to represent the indicator in the UI indicator list.
Returns descriptive text about the indicator.
Optionally returns a URL that links to a page containing more information about the indicator.
Returns the name of the .NET assembly that contains the indicator. Will contain null if the indicator is a custom indicator loaded from the My Indicators folder in WealthLab.
Returns the full name of the indicator.
The plot style to use when plotting the indicator.
The tooltip text can be used to show some detailed information when plotting the indicator.
Established the number of extended bars that the indicator requires. Extended bars are bars that cause a blank area to appear to the right of the plotted chart data, in effect projecting into the future. Internally, the extended bars are stored as Double.NaN values.
Return true if the indicator is considered an Oscillator, which means it moves within a defined range of minimum and maximum values. Examples include RSI and CMO, Oscillators come into play in certain building blocks.
Return true if the indicator is considered a Smoother, which means it takes a TimeSeries source as its first parameter, and smooths the source data in some way. Examples include any moving average indicator such as SMA or EMA. Smoothers come into play in certain building blocks.
Represents the overbought level for indicators that are considered Oscillators. The value is used to determine where to plot the overbought level on the chart.
Represents the oversold level for indicators that are considered Oscillators. The value is used to determine where to plot the oversold level on the chart.
Determines if the indicator should be plotted with the zero level always fixed and displayed in the chart pane.
Returns a new TimeSeries that is the absolute value of the source TimeSeries.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript4 { public class MyStrategy : UserStrategyBase { TimeSeries _barsAboveSMA; public override void Initialize(BarHistory bars) { //calculate the number of days the Close is above the 10-day SMA for the last 20 bars TimeSeries sma = SMA.Series(bars.Close, 10); PlotTimeSeriesLine(sma, "SMA(10)", "Price", WLColor.Blue, 2); TimeSeries tmp = bars.Close - sma; tmp = tmp / tmp.Abs(); tmp = (tmp + 1d) / 2d; _barsAboveSMA = tmp.Sum(20); PlotTimeSeries(_barsAboveSMA, "Closes Above SMA for last 20 bars", "BarsAbovePane", WLColor.Blue, PlotStyle.Histogram); } public override void Execute(BarHistory bars, int idx) { } } }
A generic cache Dictionary that can be used to store objects during a backtest run. Certain indicators such as ADX, ADXR, DIPlus and DIMinus use the Cache to store the collection of indicators that are all calculated together as a group.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //the list of symbols that we should buy each bar private static List<BarHistory> buys = new List<BarHistory>(); //create the weight indicator and stash it into the BarHistory object for reference in PreExecute public override void Initialize(BarHistory bars) { rsi = new RSI(bars.Close, 14); //store the RSI indicator in the cache, so it can be accessed when PreExecute is called bars.Cache["RSI"] = rsi; } //this is called prior to the Execute loop, determine which symbols have the lowest RSI public override void PreExecute(DateTime dt, List<BarHistory> participants) { //store the symbols' RSI value in their BarHistory instances foreach (BarHistory bh in participants) { RSI rsi = (RSI)bh.Cache["RSI"]; int idx = GetCurrentIndex(bh); //this returns the index of the BarHistory for the bar currently being processed double rsiVal = rsi[idx]; bh.UserData = rsiVal; //save the current RSI value along with the BarHistory instance } //sort the participants by RSI value (lowest to highest) participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); //keep the top 3 symbols buys.Clear(); for (int n = 0; n < 3; n++) { if (n >= participants.Count) break; buys.Add(participants[n]); } } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { bool inBuyList = buys.Contains(bars); if (!HasOpenPosition(bars, PositionType.Long)) { //buy logic - buy if it's in the buys list if (inBuyList) PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } else { //sell logic, sell if it's not in the buys list if (!inBuyList) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } //declare private variables below private RSI rsi; } }
Returns the number of items contained in the time series. The DateTimes property list contains this many DateTimes. For TimeSeries, the Values property contains this many values. And for BarHistory, the Open, High, Low, Close and Volume properties (all instances of the TimeSeries class) contain this many values.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //do some analysis of 10, 20, 50, 100 bars ago public override void Initialize(BarHistory bars) { SetTextDrawingOptions(WLColor.Beige, WLColor.Black, 1); ReportGainAfterNBars(bars, 10); ReportGainAfterNBars(bars, 20); ReportGainAfterNBars(bars, 50); ReportGainAfterNBars(bars, 100); } private void ReportGainAfterNBars(BarHistory bars, int numBars) { int idx = bars.Count - numBars; if (idx >= 0) { double gain = bars.Close[bars.Count - 1] - bars.Close[idx]; gain = gain * 100.0 / bars.Close[idx]; DrawBarAnnotation(numBars + " bar gain: " + gain.ToString("N2") + "%", idx, false, WLColor.Black, 7); DrawLine(idx, bars.Close[idx], bars.Count - 1, bars.Close[bars.Count - 1], WLColor.Gray, 2, LineStyle.Dotted); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns true if the TimeSeries value "crosses over" a specific value or ts at the specified bar index. A "cross over" occurs when the TimeSeries' value is greater than the value or ts, and it had previously been below.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript4 { public class MyStrategy : UserStrategyBase { //Create indicators public override void Initialize(BarHistory bars) { macd = new MACD(bars.Close); macdHist = new MACDHist(bars.Close, 10); PlotIndicatorLine(macd); PlotIndicator(macdHist, WLColor.Blue, PlotStyle.Histogram); } //flag the bars where the MACD Histogram crosses above and below zero public override void Execute(BarHistory bars, int idx) { if (macdHist.CrossesOver(0, idx)) SetBarColor(bars, idx, WLColor.Green); else if (macdHist.CrossesUnder(0, idx)) SetBarColor(bars, idx, WLColor.Red); else SetBarColor(bars, idx, WLColor.Silver); } //declare variables private MACD macd; private MACDHist macdHist; } }
Returns true if the TimeSeries value "crosses under" a specific value or ts at the specified bar index. A "cross under" occurs when the TimeSeries' value is less than the value or ts, and it had previously been above.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript4 { public class MyStrategy : UserStrategyBase { //Create indicators public override void Initialize(BarHistory bars) { macd = new MACD(bars.Close); macdHist = new MACDHist(bars.Close, 10); PlotIndicatorLine(macd); PlotIndicator(macdHist, WLColor.Blue, PlotStyle.Histogram); } //flag the bars where the MACD Histogram crosses above and below zero public override void Execute(BarHistory bars, int idx) { if (macdHist.CrossesOver(0, idx)) SetBarColor(bars, idx, WLColor.Green); else if (macdHist.CrossesUnder(0, idx)) SetBarColor(bars, idx, WLColor.Red); else SetBarColor(bars, idx, WLColor.Silver); } //declare variables private MACD macd; private MACDHist macdHist; } }
A list of DateTime objects that represents the date/time of each item in the time series. The derived classes maintain other lists that are synchronized with DateTimes. TimeSeries maintains a list of floating point double Values. BarHistory has TimeSeries properties for Open, High, Low, Close, and Volume. All of these other lists will have exactly the same number of elements as the DateTImes list, allowing you to use the same index to access their elements interchangably.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //annotate the 100 bar high and low public override void Initialize(BarHistory bars) { double lowVal = Double.MaxValue; double highVal = Double.MinValue; int lowIdx = -1; int highIdx = -1; for (int n = bars.Count - 1; n > bars.Count - 100; n--) { if (n >= 0) { if (bars.Low[n] < lowVal) { lowVal = bars.Low[n]; lowIdx = n; } if (bars.High[n] > highVal) { highVal = bars.High[n]; highIdx = n; } } } if (lowIdx >= 0) { string txt = "100 bar low occurred on " + bars.DateTimes[lowIdx].ToLongDateString(); DrawBarAnnotation(txt, lowIdx, false, WLColor.Red, 8); } if (highIdx >= 0) { string txt = "100 bar high occurred on " + bars.DateTimes[highIdx].ToLongDateString(); DrawBarAnnotation(txt, highIdx, true, WLColor.Green, 8); } } public override void Execute(BarHistory bars, int idx) { } } }
A text description of the TimeSeries. You typically won't need to access or set this directly. Indicators set this value automatically. And, when you Plot a plain vanilla TimeSeries in a C# coded Strategy, you provide a "name" parameter which is used to set the Description property.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript5 { public class MyStrategy : UserStrategyBase { //Display indicator's description public override void Initialize(BarHistory bars) { ADX adx = new ADX(bars, 20); PlotIndicatorLine(adx); DrawHeaderText("Plotted " + adx.Description); } public override void Execute(BarHistory bars, int idx) { } } }
Returns the last DateTime in the DateTimes property list. If the list is empty, returns DateTime.MaxValue.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { SetTextDrawingOptions(WLColor.AliceBlue, WLColor.Black, 1); string s = "Chart end date is " + bars.EndDate.ToLongDateString(); DrawHeaderText(s); } public override void Execute(BarHistory bars, int idx) { } } }
Returns the first index which contains valid data (not Double.NaN). WealthLab indicators populate initial values with Double.NaN until a valid value can be calculated. For example, a Simple Moving Average (SMA) indicator with a period of 20 will have its first 19 values set to Double.NaN.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { sma = new SMA(bars.Close, 200); PlotIndicatorLine(sma); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { if (idx < sma.FirstValidIndex) SetBackgroundColor(bars, idx, c); } //declare private variables below SMA sma; WLColor c = WLColor.FromArgb(32, 128, 0, 0); } }
Override this method if your indicator is designed to be represented as a series of Open, High, Low, and Close TimeSeries. Such an indicator can use the BarChart PlotStyle to render all of the components on the chart as a pseudo-BarHistory.
An example of an indicator that is presented this way is VChart. You are passed a PriceComponent parameter pc. If the value is PriceComponent.Close, return the current instance of your indicator, i.e., "this". If it is High, Low, or Open, create a new instance of the indicator based on the corresponding TimeSeries from the source BarHistory and return it.
Returns the highest value in the TimeSeries, looking back starting from bar, for a number of values equal to range.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Flag 60 bar high and low public override void Initialize(BarHistory bars) { if (bars.Count < 60) return; double high60 = bars.High.GetHighest(bars.Count - 1, 60); double low60 = bars.Low.GetLowest(bars.Count - 1, 60); WLColor c = WLColor.FromArgb(32, 128, 128, 128); FillRectangle(bars.Count - 60, high60, bars.Count - 1, low60, c); } public override void Execute(BarHistory bars, int idx) { } } }
Returns the bar number on which the highest value in the TimeSeries was found, looking back starting from bar, for a number of values equal to range.
Returns the lowest value in the TimeSeries, looking back starting from bar, for a number of values equal to range.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Flag 60 bar high and low public override void Initialize(BarHistory bars) { if (bars.Count < 60) return; double high60 = bars.High.GetHighest(bars.Count - 1, 60); double low60 = bars.Low.GetLowest(bars.Count - 1, 60); WLColor c = WLColor.FromArgb(32, 128, 128, 128); FillRectangle(bars.Count - 60, high60, bars.Count - 1, low60, c); } public override void Execute(BarHistory bars, int idx) { } } }
Returns the bar number on which the lowest value in the TimeSeries was found, looking back starting from bar, for a number of values equal to range.
Returns the index into the DateTimes property list that contains the DateTime specified in the dt parameter. If exactMatchOnly is false, and an exact match does not exist, the method returns the index following the closest matching DateTime, unless the requested DateTime falls completely outside the range of the list, in which case it returns -1. If exactMatchOnly is true and no exact match exists, the method returns -1.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //whoever figures out the significance of this date will receive a one month free Premium membership credit public override void Initialize(BarHistory bars) { WLColor green = WLColor.FromArgb(128, 0, 255, 0); if (bars.Count == 0) return; for (int yr = bars.StartDate.Year; yr <= bars.EndDate.Year; yr++) { DateTime dt = new DateTime(yr, 8, 25); int idx = bars.IndexOf(dt); if (idx >= 0) SetBackgroundColor(bars, idx, green); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns whether the historical data appears up to date, as of the DateTime specified in the endDate parameter. The method accounts for weekends, market holidays, and market open and closing times, when called from a BarHistory object.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //report on whether data needs updating public override void Initialize(BarHistory bars) { string txt; WLColor c; if (bars.IsUpToDate(DateTime.Now)) { txt = "Data appears to be up to date"; c = WLColor.Green; } else { txt = "Data appears to need updating!"; c = WLColor.Red; } DrawHeaderText(txt, c); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries containing the log returns of a TimeSeries for the specified period.
See ReadFromBinaryFile in class TimeSeries.
See ReadFromFile in class TimeSeries.
Calculates the percentage gain from the point in time specified by idx, going back the specified number of calendar days.
using WealthLab.Backtest; using WealthLab.Core; using System.Drawing; namespace WealthLab { public class MyStrategy1 : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { double oneYearReturn = bars.Close.ReturnNDays(bars.Count - 1, 365); SetTextDrawingOptions(WLColor.White, WLColor.Black, 1); DrawHeaderText("One year return of " + bars.Symbol + " is: " + oneYearReturn.ToString("N2") + "%", WLColor.Black, 12); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { } } }
Returns the first DateTime in the DateTimes property list. If the list is empty, returns DateTime.MinValue.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { SetTextDrawingOptions(WLColor.AliceBlue, WLColor.Black, 1); string s = "Chart start date is " + bars.StartDate.ToLongDateString(); DrawHeaderText(s); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a TimeSpan that encompasses the range of the DateTimes in the DateTimes property list. If there are fewer than two DateTimes in the list, returns a zero TimeSpan.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //display total amount of time covered in chart public override void Initialize(BarHistory bars) { string txt = "Chart data comprised of " + bars.TimeSpan.TotalHours.ToString("N0") + " total hours"; DrawHeaderText(txt); } public override void Execute(BarHistory bars, int idx) { } } }
Returns true if the TimeSeries "turns down" at the specified bar index. A TimeSeries "turns down" if its value decreases after an advance.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create indicators public override void Initialize(BarHistory bars) { macd = new MACD(bars.Close); macdHist = new MACDHist(bars.Close, 5); PlotIndicatorLine(macd); PlotIndicator(macdHist, WLColor.Blue, PlotStyle.Histogram); } //flag the bars where the MACD Histogram turns up and down public override void Execute(BarHistory bars, int idx) { if (macdHist.TurnsUp(idx)) SetBarColor(bars, idx, WLColor.Green); else if (macdHist.TurnsDown(idx)) SetBarColor(bars, idx, WLColor.Red); else SetBarColor(bars, idx, WLColor.Silver); } //declare variables private MACD macd; private MACDHist macdHist; } }
Returns true if the TimeSeries "turns up" at the specified bar index. A TimeSeries "turns up" if its value increases after a decline.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create indicators public override void Initialize(BarHistory bars) { macd = new MACD(bars.Close); macdHist = new MACDHist(bars.Close, 5); PlotIndicatorLine(macd); PlotIndicator(macdHist, WLColor.Blue, PlotStyle.Histogram); } //flag the bars where the MACD Histogram turns up and down public override void Execute(BarHistory bars, int idx) { if (macdHist.TurnsUp(idx)) SetBarColor(bars, idx, WLColor.Green); else if (macdHist.TurnsDown(idx)) SetBarColor(bars, idx, WLColor.Red); else SetBarColor(bars, idx, WLColor.Silver); } //declare variables private MACD macd; private MACDHist macdHist; } }
Allows you to store ad-hoc data in a property of a BarHistory or TimeSeries instance. You can store object instances, or primitive values like ints or doubles.
Allows you to access a value you stored in a BarHistory or TimeSeries UserData property as a double.
Allows you to access a value you stored in a BarHistory or TimeSeries UserData property as an int.
Returns the list of values. You typically do not need to reference the Values property directly, since the TimeSeries class can also access its values via its default property,
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Show how to use the "default" property of TimeSeries public override void Initialize(BarHistory bars) { TimeSeries closingPrices = bars.Close; int lastIdx = closingPrices.Count - 1; //doing this ... double lastCloseA = closingPrices[lastIdx]; //is the same as doing this, only shorter ... double lastCloseB = closingPrices.Values[lastIdx]; DrawHeaderText("These two values should be equal: " + lastCloseA.ToString("N2") + " and " + lastCloseB.ToString("N2")); } public override void Execute(BarHistory bars, int idx) { } } }
See WriteToBinaryFile in class TimeSeries.
See WriteToFile in class TimeSeries.
Returns a new TimeSeries that contains the unary negative of the TimeSeries.
The overloaded multiplication operator allows you to perform multiplication on two TimeSeries instances, or on a TimeSeries and a constant floating point double value.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create and plot a simple indicator that multiples closing price by volume public override void Initialize(BarHistory bars) { TimeSeries vc = bars.Close * bars.Volume; PlotTimeSeries(vc, "Volume x Close", "VC", WLColor.DarkOrchid, PlotStyle.ThickHistogram); } public override void Execute(BarHistory bars, int idx) { } } }
The overloaded division operator allows you to perform division on two TimeSeries instances, or on a TimeSeries and a constant floating point double value. In the case of division by zero, a zero is placed in the resulting values index.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create and plot a simple indicator that gets the percentage of how much close is above/below average 5 bar close public override void Initialize(BarHistory bars) { SMA sma = new SMA(bars.Close, 5); PlotIndicatorLine(sma, WLColor.DarkBlue); TimeSeries cma = 100.0 - (sma * 100.0 / bars.Close); PlotTimeSeries(cma, "Volume x Close", "SMA", WLColor.DarkBlue, PlotStyle.ThickLine); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries containing 1's where values of both of the TimeSeries being compared are greater than zero, and -1 where they are not.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { //highlight areas where price is above 2 moving averages SMA smaLong = new SMA(bars.Close, 200); SMA smaShort = new SMA(bars.Close, 50); TimeSeries aboveBoth = bars.Close > smaLong & bars.Close > smaShort; PlotIndicator(smaLong); PlotIndicator(smaShort); PlotTimeSeries(aboveBoth, "Above 2 SMAs", "Price", WLColor.DarkGreen, PlotStyle.BooleanDots); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { } } }
The overloaded addition operator allows you to perform addition on two TimeSeries instances, or on a TimeSeries and a constant floating point double value.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Take average of QID/QLD rate of changes and plot it public override void Initialize(BarHistory bars) { BarHistory qld = GetHistory(bars, "QLD"); ROC qldRoc = new ROC(qld.Close, 20); BarHistory qid = GetHistory(bars, "QID"); ROC qidRoc = new ROC(qid.Close, 20); TimeSeries rocAvg = (qldRoc + qidRoc) / 2; PlotTimeSeries(rocAvg, "QLD/QID ROC average", "Avg", WLColor.Navy, PlotStyle.ThickHistogram); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries containing 1's where the first TimeSeries argument is less than the second, and -1 where it is not. You can compare TimeSeries against another TimeSeries or a constant numeric value.
Returns a new TimeSeries that is shifted backward in time a number of bars specified in the period parameter. The shifted series is not safe to use in backtesting, because the shifted series introduces future information to the backtester. The right side of the shifted series will appear blank on the chart, these values contain Double.NaN.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create an idealized "centered" moving average public override void Initialize(BarHistory bars) { SMA sma = new SMA(bars.Close, 13); TimeSeries shifted = sma << 6; PlotTimeSeries(shifted, "Idealized SMA", "Price", WLColor.DarkOrange, PlotStyle.ThickLine); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries containing 1's where the first TimeSeries argument is greater than the second, and -1 where it is not. You can compare TimeSeries against another TimeSeries or a constant numeric value.
Returns a new TimeSeries that is shifted forward in time a number of bars specified in the period parameter. The shifted series is safe to use in backtesting, because the operation effectively delays the information in the TimeSeries. For example, imagine you shift a TimeSeries to the right by one bar, and examine a value at index X. The actual data you are seeing is the data that occupied X-1 of the original TimeSeries.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //Create and plot an SMA and a right shifted version public override void Initialize(BarHistory bars) { SMA sma = new SMA(bars.Close, 50); PlotIndicator(sma, WLColor.DarkBlue, PlotStyle.ThickLine); TimeSeries shifted = sma >> 10; PlotTimeSeries(shifted, "Shifted SMA", "Price", WLColor.DarkGreen, PlotStyle.ThickLine); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries containing 1's where values of either of the TimeSeries being compared are greater than zero, and -1 where neither is.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { //highlight areas where price is above either of 2 moving averages SMA smaLong = new SMA(bars.Close, 200); SMA smaShort = new SMA(bars.Close, 50); TimeSeries aboveBoth = bars.Close > smaLong | bars.Close > smaShort; PlotIndicator(smaLong); PlotIndicator(smaShort); PlotTimeSeries(aboveBoth, "Above one of 2 SMAs", "Price", WLColor.DarkGreen, PlotStyle.BooleanDots); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { } } }
Returns a new TimeSeries where each value is determined by comparing the value in source to 0 - If the value is greater than zero, the corresponding result value is obtained from resultTrue, otherwise from resultFalse.
Returns a new TimeSeries containing the kurtosis of a specified TimeSeries over the specified period. Kurtosis is a statistical measure that helps in describing distribution.
Returns a new TimeSeries containing the logarithm of a specified TimeSeries.
Returns a new TimeSeries containing the highest values over the specified period.
Returns a new TimeSeries containing the median absolute deviation of a specified TimeSeries which is a robust measure of variability.
Returns a new TimeSeries containing the lowest values over the specified period.
Returns a new TimeSeries containing the percent rank of a specified TimeSeries within all elements over the specified period. Matches Excel's function.
Returns a new TimeSeries raising the source TimeSeries values to the specified power.
Returns a new TimeSeries containing the YTD (Year To Date) change, in %, of a symbol's last Closing price compared to the last Close of the previous year.
Returns a new TimeSeries that rounds the data in the TimeSeries.
Returns a new TimeSeries containing the skewness of a specified TimeSeries over the specified period. Skewness represents the extent to which a given distribution varies from a normal distribution.
Returns a new TimeSeries containing the square root of the TimeSeries.
Returns a new TimeSeries that sums the TimeSeries over the specified length.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript4 { public class MyStrategy : UserStrategyBase { TimeSeries _barsAboveSMA; TimeSeries _barsAboveSMA2; public override void Initialize(BarHistory bars) { //calculate the number of days the Close is above the 10-day SMA for the last 20 bars TimeSeries sma = SMA.Series(bars.Close, 10); PlotTimeSeriesLine(sma, "SMA(10)", "Price", WLColor.Blue, 2); TimeSeries tmp = bars.Close - sma; tmp = tmp / tmp.Abs(); tmp = (tmp + 1d) / 2d; //using the static method _barsAboveSMA = TimeSeries.Sum(tmp, 20); //or using the memeber method _barsAboveSMA2 = tmp.Sum(20); PlotTimeSeries(_barsAboveSMA, "Bars Above SMA 20 bars", "BarsAbovePane", WLColor.Blue, PlotStyle.Histogram); PlotTimeSeries(_barsAboveSMA2, "Bars Above Method 2", "BarsAbovePane", WLColor.Red, PlotStyle.ThickLine); } public override void Execute(BarHistory bars, int idx) { } } }