- ago
I created an indicator that calculates the sum of bars volume for a period of bars. (See code below) I need help converting the period from a hard number to the number of bars since open (9:30AM ET) This would be plotted in a one minute chart. Any suggestions welcomed. Thanks.

CODE:
//populate public override void Populate() {          BarHistory source = Parameters[0].AsBarHistory;          Int32 period = Parameters[1].AsInt; DateTimes = source.Close.DateTimes;          if (period <= 0)             return;          //modify the code below to implement your own indicator calculation for (int n = period + 1; n < source.Close.Count; n++)          {                          double totalVolume = 0;             for (int v = 0; v <= period; v++)             {                //totalVolume = source.Volume[n] + source.Volume[n - 1] + source.Volume[n - 2] + source.Volume[n - 3] + etc.;                totalVolume = totalVolume + source.Volume[n - v];                Values[n] = totalVolume;             }                       } } //generate parameters protected override void GenerateParameters() {          AddParameter("Source", ParameterType.BarHistory, null);          AddParameter("Period", ParameterType.Int32, 60); }
0
415
Solved
7 Replies

Reply

Bookmark

Sort
- ago
#1
Here ya go. See the Description property for more details...

CODE:
using WealthLab.Core; using WealthLab.Indicators; namespace WLUtility.Indicators { public class IntraDayVolume : IndicatorBase { public IntraDayVolume() { // for WL 8 - do not remove } public IntraDayVolume(BarHistory bars) { Parameters[0].Value = bars; Populate(); } private BarHistory Source => Parameters[0].AsBarHistory; public override WLColor DefaultColor { get; } = WLColor.Green; public override PlotStyle DefaultPlotStyle => PlotStyle.Histogram; public override string Name => "IntraDayVolume"; public override string Abbreviation => "IntraDayVolume"; public override string HelpDescription => "Determines the running total of intra-day volume for bars between market open and close, excluding pre and post market. Pre and post market bars totals are zero. For scales that don't align with a market open and/or close, pre and/or post market volume will be included from scale boundary bars. For daily, weekly, monthly and yearly scales, the values are simply the bar volume without summing."; public override string PaneTag => "IntraDayVolume"; public override void Populate() { // dereference for speed... var source = Source; var dateTimes = source.DateTimes; DateTimes = dateTimes; var vol = source.Volume; // for non-intra-day just display the volume for that bar if (!source.IsIntraday) { for (var idx = 0; idx < source.Count; idx++) { Values[idx] = vol[idx]; } return; } // intra-day... var total = 0.0; for (var idx = 0; idx < source.Count; idx++) { // if pre/post filtering is active then we need a way to reset the total if (idx > 0 && dateTimes[idx].Date != dateTimes[idx - 1].Date) { total = 0; } if (source.Market.IsOpenMarketTime(dateTimes[idx])) { total += vol[idx]; Values[idx] = total; } else { // presumes we don't want to sum volume in pre/post market Values[idx] = 0; total = 0; } } } protected override void GenerateParameters() { AddParameter("Source", ParameterType.BarHistory, null); } public static IntraDayVolume Series(BarHistory bars) { var key = CacheKey("IntraDayVolume"); if (bars.Cache.TryGetValue(key, out var obj)) { return (IntraDayVolume) obj; } var result = new IntraDayVolume(bars); bars.Cache[key] = result; return result; } } }
0
Best Answer
Cone8
 ( 24.99% )
- ago
#2
It sure would be easier just to use the Market Filter and then use bars.IntradayBarNumber(idx).
0
- ago
#3
Thank you Paul1986. Works really good! I implemented your code into mine to also get the Pre-Market data volume included.

CODE:
//populate public override void Populate() {          BarHistory source = Parameters[0].AsBarHistory;               // dereference for speed...          var dateTimes = source.DateTimes;          DateTimes = dateTimes;          //modify the code below to implement your own indicator calculation     var totalVolume = 0.0;          for (var n = 0; n < source.Count; n++)          {             // if pre/post filtering is active then we need a way to reset the total             if (n > 0 && dateTimes[n].Date != dateTimes[n - 1].Date)             {                totalVolume = 0;             }             totalVolume += source.Volume[n];                Values[n] = totalVolume;          } }
0
- ago
#4
@designer01 - you're welcome. If you copied my HelpDescription into your code, then you'll probably want to change it. Also, Cone suggested to use IntraDayBarNumber, but that is a moot point, because you want pre/post market volume included. But, the date change check is necessary to reset the total each day.

Also, for future reference, if pre/post market filtering is off (i.e. pre/post bars included) then IntraDayBarNumber will return a value greater than or equal to zero even if the bar is at a pre-market time. That is the case with a U.S. equity in the U.S. Market with default market hours of 9:30 to 16:00 defined. However, Cone did indicate his solution is to use the market filter.

@Cone - I ran a test with IntraDayBarNumber, using symbol RBLX (a U.S. equity that trades pre/post market), one-minute scale, U.S. Market (using defaults of 9:30 to 16:00) and found IntraDayBarNumber is always greater than or equal to 0 (never -1). This is the case with market filter on or off. Maybe that is a defect with IntraDayBarNumber or maybe not. Here's my test code...

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; 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)       {          if (bars.IsIntraday && bars.IntradayBarNumber(idx) < 0)          {             WriteToDebugLog($"When intraday bar number is less than 0: {bars.DateTimes[idx]}\r\n");          }       }    } }
0
Cone8
 ( 24.99% )
- ago
#5
IntradayBarNumber always starts at 0 for the first intraday bar of the day. Market hours or bar time makes no difference. Even if there's only 1 intraday trade at 15:59:59.999, it will bar 0.
0
- ago
#6
@Cone do you have any examples of how to use IntradayBarNumber if I wanted to refer a bar number say the bar just before open at 9:29 am? I was able to find an example here: but not the one I need. Thanks.
https://www.wealth-lab.com/Support/ApiReference/BarHistory
0
Cone8
 ( 24.99% )
- ago
#7
QUOTE:
refer a bar number say the bar just before open at 9:29 am
First, keep in mind that the timestamp of the bar before the open will be 09:30. The first one minute bar of the data is 09:31.

Anyway, IntradayBarNumber isn't the right function to do that since you can't use the Market filter (otherwise you won't get the premarket data). You need to look at the bar's time. Here's how I'd go about it. This code assumes there will always be a bar for the first interval in the regular market session.

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript15 { public class MyStrategy : UserStrategyBase { public override void Initialize(BarHistory bars) {          _openTime = bars.Market.GetOpenTimeMarketTime(false).TimeOfDay;          _openTime.Add(new TimeSpan(0, bars.Scale.Interval, 0)); } public override void Execute(BarHistory bars, int idx) {          if (bars.DateTimes[idx].TimeOfDay == _openTime)             _lastRegularSessionOpenBar = idx;          int barBeforeTheOpen = _lastRegularSessionOpenBar - 1;           }       //declare private variables below       int _lastRegularSessionOpenBar = 0;       TimeSpan _openTime; } }
0

Reply

Bookmark

Sort