Arg Posted December 7, 2021 Report Share Posted December 7, 2021 (edited) I want to put together a portfolio spike scan and a breakout scan: Pasted below is what I've got so far. The spike scan and BO scan both work separately. Put together (as below) only the BO scan results appear in portfolio. How do I get the spike alerts to also appear? Also, for the spike scan the 11 length (bar) array is specified explicitly. Is it possible to change the spike code below to use "period" parameter to set the array length to any desired value, i.e. so I can set number of bars to eg 16. I tried to change the BO indicator to also include a volume condition. It doesn't work - how can I correct this? if (Max(BarsTotal,Close) == Close) && BarVolume[1]>15000 public void MainCalculation() { DefinePaintbarParameter("Period","Period",true, 2, 100, 1, 11); var lvca0 = Math.Log(Close[1]/Close[2]); var lvca1 = Math.Log(Close[2]/Close[3]); var lvca2 = Math.Log(Close[3]/Close[4]); var lvca3 = Math.Log(Close[4]/Close[5]); var lvca4 = Math.Log(Close[5]/Close[6]); var lvca5 = Math.Log(Close[6]/Close[7]); var lvca6 = Math.Log(Close[7]/Close[8]); var lvca7 = Math.Log(Close[8]/Close[9]); var lvca8 = Math.Log(Close[9]/Close[10]); var lvca9 = Math.Log(Close[10]/Close[11]); var lvca10 = Math.Log(Close[11]/Close[12]); double[] LogValCloseArray = new double[11] {lvca0, lvca1, lvca2, lvca3, lvca4, lvca5, lvca6, lvca7, lvca8, lvca9, lvca10}; double CloseArrayAverage = LogValCloseArray.Average(); double CsumOfSquaresOfDifferences = LogValCloseArray.Select(val => (val - CloseArrayAverage) * (val - CloseArrayAverage)).Sum(); double SDevClose = Math.Sqrt(CsumOfSquaresOfDifferences / (LogValCloseArray.Length - 1)); var m = SDevClose * Close[1]; var pricespike = (Close-Close[1])/m > 3; var lvva0 = Math.Log(BarVolume[1]/BarVolume[2]); var lvva1 = Math.Log(BarVolume[2]/BarVolume[3]); var lvva2 = Math.Log(BarVolume[3]/BarVolume[4]); var lvva3 = Math.Log(BarVolume[4]/BarVolume[5]); var lvva4 = Math.Log(BarVolume[5]/BarVolume[6]); var lvva5 = Math.Log(BarVolume[6]/BarVolume[7]); var lvva6 = Math.Log(BarVolume[7]/BarVolume[8]); var lvva7 = Math.Log(BarVolume[8]/BarVolume[9]); var lvva8 = Math.Log(BarVolume[9]/BarVolume[10]); var lvva9 = Math.Log(BarVolume[10]/BarVolume[11]); var lvva10 = Math.Log(BarVolume[11]/BarVolume[12]); double[] LogValVolumeArray = new double[11] {lvva0, lvva1, lvva2, lvva3, lvva4, lvva5, lvva6, lvva7, lvva8, lvva9, lvva10}; double VolumeArrayAverage = LogValVolumeArray.Average(); double VsumOfSquaresOfDifferences = LogValVolumeArray.Select(val => (val - VolumeArrayAverage) * (val - VolumeArrayAverage)).Sum(); double SDevVolume = Math.Sqrt(VsumOfSquaresOfDifferences / (LogValVolumeArray.Length - 1)); var n = SDevVolume * BarVolume[1]; var volumespike = (BarVolume-BarVolume[1])/n > 3; var scan = pricespike && volumespike && BarVolume[1]>15000; SetScanResult(scan); if (scan) { SetColorAndShape("Spike", PBShape.ArrowUp_Hollow, SysColor.VolumeUp); TriggerAlert("Spike", @"Spike"); SetScanResult("Spike"); return; } DefinePaintbarParameter("BarsTotal", "# Bars Total", true, 2, 500, 1, 15); int BarsTotal = (int)GetPaintbarParameter("BarsTotal"); if (Max(BarsTotal,Close) == Close) && BarVolume[1]>15000 { SetColorAndShape("Breakout", PBShape.ArrowUp_Hollow, SysColor.VolumeUp); TriggerAlert("Breakout", @"Breakout"); SetScanResult("Breakout"); } } Edited December 7, 2021 by Arg code didn't appear Quote Link to comment Share on other sites More sharing options...
Mike Medved Posted December 7, 2021 Report Share Posted December 7, 2021 Ok the spike code should be as below. The "breakout" code I don't understand. You're basically saying if your defined BarsTotal parameter is greater than the Close of the candle then it is a breakout. Is that what you intended? StateFIFOQueue PriceBuf; StateFIFOQueue VolBuf; public void MainCalculation() { var PriceLog = Close[2]==0?0:Close[1]/Close[2]; PriceLog = PriceLog==0?0:Math.Log(PriceLog); PriceBuf.Add(PriceLog); var StDev = PriceBuf.GetStDev(); var m = StDev*Close[1]; var pricespike = m!=0 && (Close-Close[1])/m>3; var VolLog = BarVolume[2]==0?0:BarVolume[1]/BarVolume[2]; VolLog = VolLog==0?0:Math.Log(VolLog); VolBuf.Add(VolLog); StDev = VolBuf.GetStDev(); var n = StDev*BarVolume[1]; var volumespike = n!=0 && (BarVolume-BarVolume[1])/n>3; var scan = pricespike && volumespike && BarVolume[1]>15000; if (scan) { SetColorAndShape("Spike", PBShape.ArrowUp_Hollow, SysColor.VolumeUp); TriggerAlert("Spike", @"Spike"); SetScanResult("Spike"); return; } } /// <summary> /// Is called at start of paintbar calculation, should be used to initialize anything needed for the paintbar /// </summary> private void PaintbarInitialize() { } /// <summary> /// Holds paintbar state - fill with variables needed to be preserved for next paintbar calc /// </summary> private struct PaintbarState { } /// <summary> /// Holds current PB state - use to calc PB, changes to it carry over to next PB calc /// </summary> private PaintbarState CurrentState; /// <summary> /// Holds saved PB state - internal /// </summary> private PaintbarState SavedState; /// <summary> /// Is called at start of paintbar calculation, should be used to clear the paintbar state /// </summary> private void PaintbarClearState() { CurrentState = new PaintbarState(); DefinePaintbarParameter("Period","Period",true, 2, 100, 1, 11); var per = Convert.ToInt32(GetPaintbarParameter("Period")); PriceBuf = new StateFIFOQueue(per); VolBuf = new StateFIFOQueue(per); } /// <summary> /// Saves paintbar state (called internally). /// </summary> private void PaintbarSaveState() { SavedState = CurrentState; PriceBuf.SaveState(); VolBuf.SaveState(); } /// <summary> /// Restores paintbar state (called internally). /// </summary> private void PaintbarRestoreState() { CurrentState = SavedState; PriceBuf.RestoreState(); VolBuf.RestoreState(); } Quote Link to comment Share on other sites More sharing options...
Arg Posted December 7, 2021 Author Report Share Posted December 7, 2021 Thanks Mike. The BO code is just inputting a BarsTotal value to set number of bars, eg 15, and giving a trigger if the current bar is the max out of the previous 15 bars. It works but I want to add a volume condition - that is what is giving me trouble. Quote Link to comment Share on other sites More sharing options...
Mike Medved Posted December 7, 2021 Report Share Posted December 7, 2021 Ah. I mixed up the Max with Math.Max - anyway yes the if (Max(BarsTotal,Close) == Close) && BarVolume[1]>15000) should be ok. But in general, it is a lot less efficient to use the Max (that is, any of the "looping functions") than using the StateFIFOQueue and its GetMinMax, Average, etc. function. Quote Link to comment Share on other sites More sharing options...
Arg Posted December 7, 2021 Author Report Share Posted December 7, 2021 Thanks Mike. I will take a look at the StateFIFOQueue over the Christmas period Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.