Parent: TimeSeriesBase
The BarHistory class represents historical price and volume data for a market. When you work with code-based Strategies, you're passed an instance of a BarHistory object in the Initialize, Execute, and other methods. This instance contains the historical data your Strategy should backtest.
A "bar" of data contains an open price, a high, low and closing price. The BarHistory class exposes these through Open, High, Low, and Close properties, each of which is an instance of the TimeSeries class. Volume information is available via the Volume property, also a TimeSeries instance. Use the DateTimes property to access the list of DateTimes that these time series are keyed off of.
Calculates and returns the average price TimeSeries (high + low) / 2.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 { public class MyStrategy : UserStrategyBase { //plot the average price, both versions public override void Initialize(BarHistory bars) { PlotTimeSeries(bars.AveragePriceHL, "Average Price", "Price", WLColor.Blue, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceHLC, "Average Price w/Close", "Price", WLColor.Red, PlotStyle.Line); } public override void Execute(BarHistory bars, int idx) { } } }
Calculates and returns the average price TimeSeries (high + low + close) / 3.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 { public class MyStrategy : UserStrategyBase { //plot the average price, both versions public override void Initialize(BarHistory bars) { PlotTimeSeries(bars.AveragePriceHL, "Average Price", "Price", WLColor.Blue, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceHLC, "Average Price w/Close", "Price", WLColor.Red, PlotStyle.Line); } public override void Execute(BarHistory bars, int idx) { } } }
Calculates and returns the average price TimeSeries (high + low + close + close) / 4.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 { public class MyStrategy : UserStrategyBase { //plot the average price, both versions public override void Initialize(BarHistory bars) { PlotTimeSeries(bars.AveragePriceOHLC, "Average Price OHLC", "Price", WLColor.Red, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceHLCC, "Average Price w/ Double-weight Close", "Price", WLColor.Blue, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceOC, "Average Price Open-Close", "Price", WLColor.Purple, PlotStyle.Line); } public override void Execute(BarHistory bars, int idx) { } } }
Calculates and returns the average price TimeSeries (open + close) / 2.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 { public class MyStrategy : UserStrategyBase { //plot the average price, both versions public override void Initialize(BarHistory bars) { PlotTimeSeries(bars.AveragePriceOHLC, "Average Price OHLC", "Price", WLColor.Red, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceHLCC, "Average Price w/ Double-weight Close", "Price", WLColor.Blue, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceOC, "Average Price Open-Close", "Price", WLColor.Purple, PlotStyle.Line); } public override void Execute(BarHistory bars, int idx) { } } }
Calculates and returns the average price TimeSeries (open + high + low + close) / 4.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 { public class MyStrategy : UserStrategyBase { //plot the average price, both versions public override void Initialize(BarHistory bars) { PlotTimeSeries(bars.AveragePriceOHLC, "Average Price OHLC", "Price", WLColor.Red, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceHLCC, "Average Price w/ Double-weight Close", "Price", WLColor.Blue, PlotStyle.Line); PlotTimeSeries(bars.AveragePriceOC, "Average Price Open-Close", "Price", WLColor.Purple, PlotStyle.Line); } public override void Execute(BarHistory bars, int idx) { } } }
BarHistory has three constructors. The first assigns the Symbol and Scale based on the passed parameters. The second assigns the Symbol and creates a HistoryScale instance based on the passed Frequency enum value. The third takes a BarHistory as a parameter (parent), and assigns the various property values from that instance to the new BarHistory instance.
Returns a list of EventDataPoint instances that represents the event data that has been loaded along with the historical data.
Remarks
- For intraday charts EventDataPoints will synchronize to the first bar of the Event Date.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using WealthLab.ChartWPF; using System.Drawing; using System.Collections.Generic; namespace WealthLab { public class MyStrategy : UserStrategyBase { //report last event item public override void Initialize(BarHistory bars) { if (bars.EventDataPoints.Count == 0) return; EventDataPoint fdp = bars.EventDataPoints[bars.EventDataPoints.Count - 1]; DrawHeaderText($"Most recent event data occurred on {fdp.Date:yyyy-MM-dd}", WLColor.Red, 14); DrawHeaderText($"It was of type {fdp.Name} and value: {fdp.Value:N4}", WLColor.Red, 14); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a list of EventDataPoint instances for the event data specified in the name parameter. Specify the idx overload to return list of EventDataPoint only for events that occurred on the bar number idx.
Remarks
- Event Providers can use the same name string. If there's a chance of duplication, put a checkmark next to the Event Provider desired and uncheck the rest. And/or you can test the EventDataPoint.ProviderName property to ensure you use the desired Provider.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Data; using System.Drawing; namespace WealthScript1 { public class MyStrategy2 : UserStrategyBase { //assumes an EventProvider with a "Dividend" item has been updated public override void Initialize(BarHistory bars) { if (bars.EventDataPoints.Count > 0) { foreach (EventDataPoint edp in bars.GetEventDataPoints("Dividend")) { WriteToDebugLog(edp.ProviderName + "\t" + edp.Name + "\t" + bars.IndexOf(edp.Date, false) + "\t" + edp.Value); } } } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { } } }
Set by the backtester, returns true if Futures Mode was enabled for this backtest.
The amount of capital required to open a 1 share/contract position. In Futures Mode, the backtester uses Margin to determine the position's cost basis.
The point value for each 1 point move of the share/contract. In Futures Mode, the backtester multiplies a position's profit by PointValue.
The minimum resolution for a position's quantity. In Futures Mode, the backtester adjusts a position's quantity based on TickSize.
Allows you to add an datetime/open/high/low/close/volume group of values to this BarHistory. Normally you won't need to directly add values to a BarHistory. This method is most useful in the development of custom Historical Data Source extensions.
Returns the date after adding the specified number of trading days to the DateTime of the specified bar.
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 a TimeSeries that represents the closing prices.
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 information about the most recent trading day public override void Initialize(BarHistory bars) { DrawHeaderText($"Closing price for the most recent trading day was: {bars.Close[bars.Count - 1]:C2}", WLColor.Red, 14); } public override void Execute(BarHistory bars, int idx) { } } }
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) { } } }
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) { } } }
The number of decimals places to use when displaying price data.
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, WLColor.Red, 14); } public override void Execute(BarHistory bars, int idx) { } } }
You can assign a value to ExtendedBars to create projected space along the right edge of the chart. The chart is filled with a number of future date/time values equal to the value you assign to ExtendedBars. The projected OHLC/V are assigned 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 { //project 20 bar price trend 20 bars into the future public override void Initialize(BarHistory bars) { if (bars.Count < 20) return; int x1 = bars.Count - 20; double y1 = bars.Close[x1]; int x2 = bars.Count - 1; double y2 = bars.Close[x2]; DrawLine(x1, y1, x2, y2, WLColor.Teal, 2, LineStyle.Solid, "Price", false, true); bars.ExtendedBars = 20; } public override void Execute(BarHistory bars, int idx) { } } }
Returns the "Named TimeSeries" if it has been registered in the BarHistory object by specific data providers; otherwise, returns null.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript6 { public class MyStrategy : UserStrategyBase { // Run this on a DataSet with defined Custom series // For example: //DATE;TIME;VOLUME;OPEN;CLOSE;MIN;MAX //06/08/2007;22:36:41;0;21.83;21.83;21.83;21.83 //06/08/2007;22:36:51;0;21.83;21.83;21.83;21.83 //06/08/2007;22:37:01;0;21.83;21.83;21.83;21.83 // Will output the value of the 'Min' column public override void Initialize(BarHistory bars) { TimeSeries min = bars.GetNamedSeries("MIN"); if (min?.Count > 0) { for(int i = 0; i < min.Count; i++) WriteToDebugLog(min[i]); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns an integer value for the time of day. For example, returns 930 for 9:30 AM, but returns 2130 for 9:30 PM.
Remarks
- See also GetTime() method inherited from TimeSeriesBase, which returns a TimeSpan type.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { 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) { } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { Position p = LastPosition; if (!HasOpenPosition(bars, PositionType.Long)) { //one trade per day if (p == null || !p.IsOpen && p.EntryBar < (idx - bars.IntradayBarNumber(idx))) // one trade per day { //buy on the first bar after 10:15AM if (bars.GetTimeAsInt(idx) >= 1015) PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } } else { //sell on the first bar after 12:30PM if (bars.GetTimeAsInt(idx) >= 1230) ClosePosition(p, OrderType.Market); } } } }
Returns true if BarHistory has streaming bar. This property is not intended to be used in Strategy code, and will return inconsistent results. Rather, it is intended for use in Chart Style and other Extension development.
Returns a TimeSeries that represents the high prices.
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 information about the most recent trading day public override void Initialize(BarHistory bars) { DrawHeaderText("High price for the most recent trading day was: $" + bars.High[bars.Count - 1].ToString("N2")); } public override void Execute(BarHistory bars, int idx) { } } }
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 { 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 the intraday bar number of the day for intraday data. If the Bars object contains non-intraday data, IntradayBarNumber always returns -1. The first bar of a particular date returns 0, the next bar returns 1, and so on.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { 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) { // Check for intraday data if (bars.Scale.IsIntraday) { // Color the middle of the trading day // First determine how many bars there are in one day int MaxBars = 0; double pct; for (int bar = bars.Count - 1; bar > -1; bar--) if (bars.IntradayBarNumber(bar) == 0) { MaxBars = bars.IntradayBarNumber(bar - 1); break; } if (MaxBars == 0) return; // Now color the bars 40 - 60% within the day's range for (int bar = 0; bar < bars.Count; bar++) { pct = (double)bars.IntradayBarNumber(bar) / MaxBars; if ((pct >= 0.4) & (pct <= 0.6)) SetBarColor(bars, bar, WLColor.Blue); } } } //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 true if the specified index is the first bar of data for the day. Useful for intraday Strategies.
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 { //visually accent the first and last bars of the trading day public override void Execute(BarHistory bars, int idx) { if (bars.IsFirstBarOfDay(idx)) SetBackgroundColor(bars, idx, WLColor.AliceBlue); if (bars.IsLastBarOfDay(idx)) SetBackgroundColor(bars, idx, WLColor.Beige); } } }
Returns true if the opening price has gapped up or down (see IsGapUp and IsGapDown) at given bar.
using WealthLab.Backtest; using WealthLab.Core; using System.Drawing; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { } public override void Execute(BarHistory bars, int idx) { if (bars.IsGap(idx)) SetBackgroundColor(bars, idx, WLColor.FromArgb(30, WLColor.Silver)); } } }
Returns true if the opening price has gapped down at given bar. For this function, a gap is when the Open of bar is less than the previous bar's Low.
using WealthLab.Backtest; using WealthLab.Core; using System.Drawing; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { } public override void Execute(BarHistory bars, int idx) { if (bars.IsGapDown(idx)) SetBackgroundColor(bars, idx, WLColor.FromArgb(30, WLColor.Red)); } } }
Returns true if the opening price has gapped up at given bar. For this function, a gap is when the Open of bar is greater than the previous bar's High.
using WealthLab.Backtest; using WealthLab.Core; using System.Drawing; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { } public override void Execute(BarHistory bars, int idx) { if (bars.IsGapUp(idx)) SetBackgroundColor(bars, idx, WLColor.FromArgb(30, WLColor.Green)); } } }
Returns true if the specified index is the last bar of data for the regular trading session. Useful for intraday Strategies.
Remarks
- Pass idx + 1 for minute-based strategies to determine if the next bar is the last bar of the session. You can use the result to place a trade at the start of the last bar of the day.
- The method is designed to used with the Pre/Post Filter enabled.
- Bars with timestamps after the session close time (post market) will also return true.
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 { //visually accent the first and last bars of the trading day public override void Execute(BarHistory bars, int idx) { if (bars.IsFirstBarOfDay(idx)) SetBackgroundColor(bars, idx, WLColor.AliceBlue); if (bars.IsLastBarOfDay(idx)) SetBackgroundColor(bars, idx, WLColor.Beige); } } }
Returns true if bar falls on the last trading day of a calendar month for the specifed BarHistory, otherwise false.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript123 { 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) { } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { //highlight the bar(s) on the last trading day of the month if (bars.IsLastTradingDayOfMonth(idx)) SetBackgroundColorAllPanes(bars, idx, WLColor.FromArgb(40, WLColor.Blue)); } } }
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 TimeSeries that represents the low prices.
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 information about the most recent trading day public override void Initialize(BarHistory bars) { DrawHeaderText("Low price for the most recent trading day was: $" + bars.Low[bars.Count - 1].ToString("N2")); } public override void Execute(BarHistory bars, int idx) { } } }
Returns an instance of the MarketDetails class that contains information about the market that the symbol belongs to. This instance is populated by the historical data provider that was used to obtain the data for the symbol.
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 information about the historical data public override void Initialize(BarHistory bars) { MarketDetails md = bars.Market; DrawHeaderText("Trades on the " + md.Name + " market, which operated in the " + md.BaseTimeZone + " zone"); } public override void Execute(BarHistory bars, int idx) { } } }
The NamedSeries property returns a list of all of the "Named TimeSeries" that have been registered in the BarHistory object. Named DataSeries can be registered with a BarHistory object by specific data providers. A common example of a possible Named TimeSeries is open interest for futures data. Another example are additional data fields that are imported in ASCII files.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript6 { public class MyStrategy : UserStrategyBase { // Run this on a DataSet with defined Custom series // For example: //DATE;TIME;VOLUME;OPEN;CLOSE;MIN;MAX //06/08/2007;22:36:41;0;21.83;21.83;21.83;21.83 //06/08/2007;22:36:51;0;21.83;21.83;21.83;21.83 //06/08/2007;22:37:01;0;21.83;21.83;21.83;21.83 // Will output 'Min' and 'Max' public override void Initialize(BarHistory bars) { if (bars.NamedSeries.Count > 0) { foreach (var ns in bars.NamedSeries) WriteToDebugLog(ns.Key); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns DateTime of the next closest monthly options expiration date as of the specified bar. Options expiration dates typically fall on the third Friday of every month.
Remarks
- Returns the current date if it is an expiry date
- If expiry Friday is a holiday, returns Thursday's date prior to the holday.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript123 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { } public override void Execute(BarHistory bars, int idx) { //make the background light blue on option expiry day if (bars.DateTimes[idx].IsOptionExpiry()) SetBackgroundColor(bars, idx, WLColor.FromArgb(40, WLColor.Blue)); if (!HasOpenPosition(bars, PositionType.Long)) { //buy 4 trading day before the next option expiry //using BarHistory method int daysToExpiry = bars.TradingDaysBetweenDates(bars.DateTimes[idx], bars.NextOptionExpiryDate(idx)); //since we buy on next bar, test for 5 days if (daysToExpiry == 5) PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } else { //get the expiry after the position entry bar DateTime expiryAfterEntry = bars.NextOptionExpiryDate(LastPosition.EntryBar); //now get the following expiry date using the DateTime extension method DateTime nextExpiry = expiryAfterEntry.AddDays(1).NextOptionExpiryDate(bars); int daysToExpiry = bars.TradingDaysBetweenDates(bars.DateTimes[idx], nextExpiry); //sell 11 trading days before the next expiry if (daysToExpiry == 12) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } }
Returns the TimeSeries that represents the open prices.
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 information about the most recent trading day public override void Initialize(BarHistory bars) { DrawHeaderText("Open price for the most recent trading day was: $" + bars.Open[bars.Count - 1].ToString("N2")); } public override void Execute(BarHistory bars, int idx) { } } }
The number of decimal places to use when calculating the number of shares/contracts in a position.
Reads back a binary file in the Wealth-Lab 8 supported format (created programmatically or via WriteToBinaryFile). Specify the fileName, start and end dates to load the data, and maximum bars of data to load.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { 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) { //download AAPL data string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); BarHistory bh = GetHistoryUnsynched("AAPL", bars.Scale); //write it to a WL8 binary file on Desktop bh.WriteToBinaryFile(path); //create a blank BarHistory BarHistory fromFile = new BarHistory(bars); //read back the AAPL data from file fromFile.ReadFromBinaryFile(path, DateTime.MinValue, DateTime.MaxValue, 0); //plot it PlotBarHistory(fromFile, "AAPL"); } //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 (!HasOpenPosition(bars, PositionType.Long)) { //code your buy conditions here } else { //code your sell conditions here } } //declare private variables below } }
Removes the datetime/open/high/low/close/volume values from this BarHistory at the index specified in the idx parameter. You generally won't need to remove bars of data during normal Strategy development.
The scale of the data being represented, as an instance of the HistoryScale class.
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 information about the historical data public override void Initialize(BarHistory bars) { DrawHeaderText("Symbol " + bars.Symbol + " has " + bars.Count + " bars of " + bars.Scale.Description + " data"); } public override void Execute(BarHistory bars, int idx) { } } }
The security name being represented, if available. For example, "Apple, Inc." for Apple corporation. Not all data sources provide a security name.
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 information about the historical data public override void Initialize(BarHistory bars) { string name = bars.SecurityName == "" ? bars.Symbol : bars.SecurityName; DrawHeaderText(name + " has " + bars.Count + " bars of data"); } 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 an instance of BarData with its properties if the BarHistory object contains a streaming bar.
Returns the date after subtracting the specified number of trading days to the DateTime of the specified bar.
The symbol being represented. For example, "MSFT" for Microsoft Corporation stock.
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 information about the historical data public override void Initialize(BarHistory bars) { DrawHeaderText("Symbol " + bars.Symbol + " has " + bars.Count + " bars of data"); } 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 next trading day is the last trading day of the week (Sunday through Saturday), otherwise false.
Tip!
Identify the current bar index as the last or first day of the week just by subtracting 1 or 2, respectively from the bar passed to the index. See example.
Remarks
- Valid for Daily and Intraday frequencies.
- Returns false for all other frequencies (Weekly, Monthly, etc.)
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript9 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { StartIndex = 2; } public override void Execute(BarHistory bars, int idx) { //use the function to identify the current bar as the first day of the week if (bars.TomorrowIsLastTradingDayOfWeek(idx - 2)) DrawBarAnnotation(TextShape.DiamondHollow, idx, true, WLColor.NeonGreen, 14); if (!HasOpenPosition(bars, PositionType.Long)) { //buy at close on the last day of the week if (bars.TomorrowIsLastTradingDayOfWeek(idx)) PlaceTrade(bars, TransactionType.Buy, OrderType.MarketClose); } else { //sell on the first day of the next week PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } }
Returns the number of trading days between the specified dates. The value will be positive number if dt2 is later than dt1, and a negative number if dt2 is before dt1.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript123 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) { } public override void Execute(BarHistory bars, int idx) { //make the background light blue on option expiry day if (bars.DateTimes[idx].IsOptionExpiry()) SetBackgroundColor(bars, idx, WLColor.FromArgb(40, WLColor.Blue)); if (!HasOpenPosition(bars, PositionType.Long)) { //buy 4 trading day before the next option expiry //using BarHistory method int daysToExpiry = bars.TradingDaysBetweenDates(bars.DateTimes[idx], bars.NextOptionExpiryDate(idx)); //since we buy on next bar, test for 5 days if (daysToExpiry == 5) PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } else { //get the expiry after the position entry bar DateTime expiryAfterEntry = bars.NextOptionExpiryDate(LastPosition.EntryBar); //now get the following expiry date using the DateTime extension method DateTime nextExpiry = expiryAfterEntry.AddDays(1).NextOptionExpiryDate(bars); int daysToExpiry = bars.TradingDaysBetweenDates(bars.DateTimes[idx], nextExpiry); //sell 11 trading days before the next expiry if (daysToExpiry == 12) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } }
Returns the number of trading days remaining in the specified Frequency
interval enum, not including the trading day for the bar index. Valid Frequency enums for this function are Weekly, Monthly, Quarterly, Yearly.
For example, if Bars.DateTimes[bar].DayOfWeek is DayOfWeek.Friday, TradingDaysRemaining(bar, Frequency.Weekly) would return 0. Likewise if it's DayOfWeek.Tuesday, it would return 3, assuming no market holidays.
using System; using WealthLab.Core; using WealthLab.Backtest; using WealthLab.Indicators; using Polly.Fallback; namespace WealthScript123 { public class MyStrategy : UserStrategyBase { Parameter _period; SMA _ma; public override void Initialize(BarHistory bars) { _ma = SMA.Series(bars.Close, 20); PlotIndicator(_ma); StartIndex = 20; } public override void Execute(BarHistory bars, int idx) { int trdaysremain = bars.TradingDaysRemaining(idx, Frequency.Weekly); DrawBarAnnotation(trdaysremain.ToString(), idx, true, WLColor.Red, 10); if (!HasOpenPosition(bars, PositionType.Long)) { // don't open a trade on the last day of the week if (trdaysremain > 0 && bars.Close.CrossesOver(_ma, idx)) { Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } } else { Position p = LastPosition; // exit at market on the morning of the last day of the week if (bars.IsLastBarOfDay(idx)) if (trdaysremain == 1) // trigger signals the day *before* ClosePosition(p, OrderType.Market); } } } }
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 a TimeSeries that represents the volume data.
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 information about the most recent trading day public override void Initialize(BarHistory bars) { DrawHeaderText("Volume for the most recent trading day was: " + bars.Volume[bars.Count - 1].ToString("N2")); } public override void Execute(BarHistory bars, int idx) { } } }
Writes a BarHistory object to a binary file in the format supported by Wealth-Lab 8 on the disk at the specified location.
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { 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) { //download AAPL data string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); BarHistory bh = GetHistoryUnsynched("AAPL", bars.Scale); //write it to a WL8 binary file on Desktop bh.WriteToBinaryFile(path); //create a blank BarHistory BarHistory fromFile = new BarHistory(bars); //read back the AAPL data from file fromFile.ReadFromBinaryFile(path, DateTime.MinValue, DateTime.MaxValue], 0); //plot it PlotBarHistory(fromFile, "AAPL"); } //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 (!HasOpenPosition(bars, PositionType.Long)) { //code your buy conditions here } else { //code your sell conditions here } } //declare private variables below } }