|
avishn
|
|
11/10/2009 2:43 PM
|
|
Last changed: |
|
11/10/2009 3:02 PM |
|
by
avishn |
|
This is not an indicator per se, rather a custom PricePane background. The concept is very simple -- * take price and volume information over lookback period (such as last 40 bars) * split price range into a number of "bins" * calculate EMA of volume for each bin over the lookback period * calculate standard deviation for all bins at the given bar * plot it on the chart using yellow for volume values within standard deviation range and red for volume above standard deviation
It seems to help in identifying congestion areas as well as "resistance becoming support" scenarios.


It is possible that somebody already came up with similar idea before, I was not able to find any references though.
I'm sharing it here so maybe somebody else finds it helpful. Any kind of feedback is more than welcome.
|
|
|
|
|
avishn
|
|
11/10/2009 2:45 PM
|
|
Last changed: |
|
11/10/2009 3:10 PM |
|
by
avishn |
|
Source code. Use at your own risk.
using System; using System.Collections.Generic; using System.Text; using System.Drawing; using WealthLab; using WealthLab.Indicators;
namespace WealthLab.Strategies { public class MyStrategy : WealthScript { protected override void Execute() { PriceVolumeHeatMap(40, 40); } public void PriceVolumeHeatMap(int lookback, int binCount) { for (int bar = lookback; bar < Bars.Count; bar++) { PriceVolumeHeatMapAtBar(bar, lookback, binCount); } } public void PriceVolumeHeatMapAtBar(int currentBar, int lookback, int binCount) { double[] bins = new double[binCount]; int[] a = new int[binCount]; int[] r = new int[binCount]; int[] g = new int[binCount]; int[] b = new int[binCount]; // get price range double lp = Lowest.Value(currentBar, Bars.Low, lookback); double hp = Highest.Value(currentBar, Bars.High, lookback); double stp = (hp - lp) / binCount; // put volume into bins double alpha = 1.0 / (1.0 + lookback); for (int bin = 0; bin < binCount; bin++) { double y = lp + stp * bin; for (int bar = currentBar - lookback + 1; bar <= currentBar; bar++) { double v = 0.0; if ((y <= Bars.High[bar]) && (Bars.Low[bar] <= (y + stp))) { v = Bars.Volume[bar]; } bins[bin] = bins[bin] + alpha * (v - bins[bin]); } } // normalize and calculate mean double minVol = Double.PositiveInfinity; double maxVol = Double.NegativeInfinity; for (int bin = 0; bin < binCount; bin++) { minVol = Math.Min(bins[bin], minVol); maxVol = Math.Max(bins[bin], maxVol); } double mean = 0.0; for (int bin = 0; bin < binCount; bin++) { bins[bin] = (bins[bin] - minVol) / (maxVol - minVol); mean += bins[bin]; } mean /= binCount;
// calculate standard deviation double stdDev = 0.0; for (int bin = 0; bin < binCount; bin++) { stdDev += (bins[bin] - mean) * (bins[bin] - mean); } stdDev = Math.Sqrt(stdDev / binCount); double stdDevFac = 1.0; for (int bin = 0; bin < binCount; bin++) { if (bins[bin] < (mean - stdDevFac * stdDev)) { r[bin] = 255; g[bin] = 255; b[bin] = 255; } else if (bins[bin] > (mean + stdDevFac * stdDev)) { r[bin] = 255; g[bin] = 255/4; b[bin] = 255/4; } else { r[bin] = 255; g[bin] = 255; b[bin] = 0; } a[bin] = ToInt(bins[bin] * 255 / 2); } // plot for (int bin = 0; bin < binCount; bin++) { double y = lp + stp * bin; double[] rectangle = { currentBar - 1, y, currentBar-1, y + stp, currentBar, y + stp, currentBar, y }; DrawPolygon(PricePane, Color.Transparent, Color.FromArgb(a[bin], r[bin], g[bin], b[bin]), LineStyle.Solid, 0, true, rectangle); } } int ToInt(double d) { return System.Convert.ToInt32(d); } } }
|
|
|
|
|
|
|
Very nice. Thank you for sharing!
|
|
|
|
|
|
|
Included this eye candy in Community.Components 2009.12. Thanks again, Andrew!
|
|
|
|