Cone8
 ( 25.31% )
- ago
Code for this chart below.
Run as-is, or copy the DrawIntradayVolumeProfile() method to another strategy and call it from Initialize(). It works for any intraday interval, but you'll get better resolution for 5 minute or more granular intervals.



CODE:
using System; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript9 { public class VPIIntraday : UserStrategyBase {        public override void Initialize(BarHistory bars) {          DrawIntradayVolumeProfile(bars, WLColor.FromArgb(255, 100, 200, 255));                    StartIndex = 1; } public override void Execute(BarHistory bars, int idx) {          }       // copy this routine and call it from Initialize       public void DrawIntradayVolumeProfile(BarHistory bars, WLColor clr, int alpha = 100, int profileBars = 20, double valueRange = 70, bool vpBehindBars = true, bool showVolumePane = false)       {          ChartDisplaySettings cds = new();          cds.ShowVolumePane = showVolumePane;          SetChartDrawingOptions(cds);                   VolumeProfileItem _lastPOC = null;          List<IChartPoint> points = new List<IChartPoint>();                    for (int idx = 1; idx < bars.Count; idx++)          {             if (bars.IsLastBarOfDay(idx) || idx == bars.Count - 1)             {                // draw level from previous day's POC                if (_lastPOC is not null)                {                   double pocLvl = (_lastPOC.RangeMax + _lastPOC.RangeMin) / 2d;                   DrawLine(idx, pocLvl, idx - bars.IntradayBarNumber(idx) - 1, pocLvl, WLColor.Gold, 2, behindBars: vpBehindBars);                }                int mbars = (bars.IntradayBarNumber(idx) + 1) * 2 / 3; // max bars for POC                VolumeProfile vp = new(bars, bars.IntradayBarNumber(idx) + 1, profileBars, valueRange, idx);                foreach (VolumeProfileItem vpi in vp.Items)                {                   if (vpi.IsPOC)                   {                      _lastPOC = vpi;                      continue;                   }                   int x1 = idx - (int)(vpi.WidthPct * mbars);                   DrawVPI(x1, idx, vpi);                   if (vpi.IsPOC)                      _lastPOC = vpi;                }                //draw POC last                if (_lastPOC is not null)                   DrawVPI(idx - mbars, idx, _lastPOC);             }          }          void DrawVPI(int x1, int x2, VolumeProfileItem vpi)          {             points.Clear();             HistoricalDataPoint hdp = new(x2, vpi.RangeMin);             points.Add(hdp);             hdp = new(x2, vpi.RangeMax);             points.Add(hdp);             hdp = new(x1, vpi.RangeMax);             points.Add(hdp);             hdp = new(x1, vpi.RangeMin);             points.Add(hdp);             int aa = vpi.InValueArea ? alpha : alpha * 2 / 3;             FillPolygon(points, clr.SetAlpha((byte)aa), behindBars: vpBehindBars);             WLColor rclr = vpi.IsPOC ? WLColor.Gold : WLColor.Black;             DrawRectangle(x1, vpi.RangeMin, x2, vpi.RangeMax, rclr, behindBars: vpBehindBars);          }       } } }
Merry Christmas!
4
58
2 Replies

Reply

Bookmark

Sort
Glitch8
 ( 10.87% )
- ago
#1
What an amazing gift, thanks! Maybe I should convert that into a drawing object? 🤔
3
Cone8
 ( 25.31% )
- ago
#2
Of course this was only possible due to Glitch's Volume Profile work (https://youtu.be/qgl61z4v_8I). There's already a more detailed drawing object, but it's not dynamic for intraday charts by day and interval. In a streaming chart, this code updates the profile for the current day without adjusting the parameters (and extends the POC value to the next day).
0

Reply

Bookmark

Sort