Indicator with timeframe parameter issue
Created at 14 Nov 2024, 13:50
Indicator with timeframe parameter issue
14 Nov 2024, 13:50
Hello,
after searching a solution for my issue without success i call for your help please…when i run the indicator with the timeframe parameter (IndicTimeFrame) different than the chart timeframe, i have alwayse the same value returned (ie 2) and it seems the BollingerPhasys class does not work but i do not understand why…please could you tell me what am i doing wrong please ?
using cAlgo.API;
using cAlgo.API.Indicators;
using System.Linq;
using ClassLibraryCbotTools;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
public class BollingerPhasysIndicator : Indicator
{
[Parameter("Indic Timeframe", DefaultValue = "Hour", Group = "Moving Averages")]
public TimeFrame IndicTimeframe { get; set; }
[Output("Phasys", LineColor = "Green", Thickness = 2, PlotType = PlotType.Points)]
public IndicatorDataSeries Phase { get; set; }
private Bars _ms;
private BollingerBands _boll;
private BollingerPhasys _bollPh;
protected override void Initialize()
{
//Chart timeframe MarketData
_ms = MarketData.GetBars(IndicTimeframe);
//Bollinger indicator
_boll = Indicators.BollingerBands(_ms.ClosePrices, 20, 2, MovingAverageType.Simple);
//BollingerPhasys Class
_bollPh = new BollingerPhasys(ref _ms, ref _boll);
}
public override void Calculate(int index)
{
//Set the phase level on the last closed candle (just before the current one)
Phase[index-1] = _bollPh.EvalPhase();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public enum Trend
{
Bullish,
Bearish,
Unknown,
Weak,
Regular,
Strong,
ExtraStrong
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class BollingerPhasys
{
private Bars _ms;
private BollingerBands _bollbands;
//Bollinger Cycle properties
public int cycle_phase;
public Trend cycle_trend;
public int cycle_duration_periods;
//Phase 2 Properties :
//ph2_Tx_last_idx = 1st candle bollinger starts Phasys 2 trend
public int ph2_Tx_last_idx;
//ph2_T0_last_idx = 1st Candle making bollingers diverging and officialy enter in a phase 2
public int ph2_T0_last_idx;
//ph2_T1_last_idx = 1st candle in the phasys 2 closing outside the bollinger bands
public int ph2_T1_last_idx;
public int ph2_duration_periods;
public int ph2_power;
public int ph2_period_min = 5;
//Phase 2 Properties :
//ph3_T3_last_idx = 1st Candle of Phase 3
public int ph3_T3_last_idx;
public int ph3_duration_periods;
//Phase 2 Properties :
//ph4_T4_last_idx = 1st Candle of Phase 4
public int ph4_duration_periods = -1;
public int ph4_T4_last_idx = -1;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CONSTRUCTOR
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public BollingerPhasys(ref Bars ms, ref BollingerBands bollbands)
{
this._ms = ms;
this._bollbands = bollbands;
this.Reset();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Reset Method
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void Reset()
{
this.cycle_phase = -1;
this.cycle_duration_periods = 0;
this.cycle_trend = Trend.Unknown;
this.ph2_Tx_last_idx = -1;
this.ph2_T0_last_idx = -1;
this.ph2_T1_last_idx = -1;
this.ph2_duration_periods = 0;
this.ph2_power = -1;
this.ph3_duration_periods = 0;
this.ph3_T3_last_idx = -1;
this.ph4_duration_periods = 0;
this.ph4_T4_last_idx = -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// EvalPhase Method
//Returned value :
// Phasys unknown or error : -1
// Phasys 1 : 1
// Phasys 2 : 2
// Phasys 3 : 3
// Phasys 4 : 4
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int EvalPhase(int last_index = 1)
{
int phase;
//Return error if last_index is greater than marketseries size
if(_ms.Count <= last_index)
return -1;
//Initialize phasys with current pulse
phase = GetPhasysPulseByLastIdx();
//Phasys 2 pulse : set Phasys 2 properties
if(phase == 2)
{
//Set the Trend (the most recent price the better)
this.cycle_trend = (_ms.ClosePrices.Last(0) > _bollbands.Main.Last(0)) ? Trend.Bullish : Trend.Bearish;
//Find & Set the Tx (last index)
this.ph2_Tx_last_idx = GetTxLastIdx(this.cycle_trend, last_index);
//Find & Set the T0 (last index)
this.ph2_T0_last_idx = GetT0FromTxLastIdx( this.ph2_Tx_last_idx);
//Find & Set the T1 (last index)
this.ph2_T1_last_idx = GetT1FromTxLastIdx(this.cycle_trend, this.ph2_Tx_last_idx, last_index);
//Calculate the T2 duration (in periods)
this.ph2_duration_periods = ph2_T0_last_idx - last_index;
}
//Phasys 3 pulse
else if(phase == 3)
{
//Bullish Trend (for avoiding wrong signal check one periode more earlyer)
if(_bollbands.Main.Last(last_index+2) < _bollbands.Main.Last(last_index+1))
{
// Check if it is a real Phasys 3 (it should only be preceded by a Phase 2)
if(IsPhase3Bullish(last_index)){
SetPropertiesFromPhase3(Trend.Bullish);
}
else
phase = 0;
}
else{
//Faire Bearish trend...mais pour l'instant on renvoie 0
// Check if it is a real Phasys 3 (it should only be preceded by a Phase 2)
if(IsPhase3Bearish(last_index)){
SetPropertiesFromPhase3(Trend.Bearish);
}
else
phase = 0;
}
}
//Phasys 4 pulse
else if(phase == 4)
{
//Bullish Trend (for avoiding wrong signal check one periode more earlyer
if(_bollbands.Main.Last(last_index+2) < _bollbands.Main.Last(last_index+1))
{
// Check if it is a real Phasys 4 (it should only be preceded by a Phase 3 itself preceded by a phase 2)
if(IsPhase4Bullish(last_index)){
SetPropertiesFromPhase4(Trend.Bullish);
}
else
phase = 0;
}
else
{
// Check if it is a real Phasys 4 (it should only be preceded by a Phase 3 itself preceded by a phase 2)
if(IsPhase4Bearish(last_index)){
SetPropertiesFromPhase4(Trend.Bearish);
}
else
phase = 0;
}
}
//Exit
return phase;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GetPhasysPulseByLastIdx Method
// Parameters :
// * "last_index" : value of the "last index" in market series for which to identify the current phase (default 1 = the last complete period)
// Returned value :
// * Value of phasys (2, 3, 4) at a given last index if a clear pulse is detected
// * 1 if no clear pulse detected
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int GetPhasysPulseByLastIdx(int last_index = 1)
{
//Bollinger divergence = Phase 2
if (_bollbands.Top.Last(last_index + 1) < _bollbands.Top.Last(last_index) && _bollbands.Bottom.Last(last_index + 1) > _bollbands.Bottom.Last(last_index))
return 2;
//Bollinger both rising = Phase 3
else if (_bollbands.Top.Last(last_index + 1) < _bollbands.Top.Last(last_index) && _bollbands.Bottom.Last(last_index + 1) < _bollbands.Bottom.Last(last_index))
return 3;
//Bollinger both decreasing = Phase 3
else if (_bollbands.Top.Last(last_index + 1) > _bollbands.Top.Last(last_index) && _bollbands.Bottom.Last(last_index + 1) > _bollbands.Bottom.Last(last_index))
return 3;
//Bollinger converging = Phase 4
else if (_bollbands.Top.Last(last_index + 1) > _bollbands.Top.Last(last_index) && _bollbands.Bottom.Last(last_index + 1) < _bollbands.Bottom.Last(last_index))
return 4;
//One (or both) Bollinger band is flat => no clear pulse detected => return -1
else
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GetTxByLastIdx Method
// Returned value : last index of the first reverse Trending Bollinger
// -1 if no reverse found
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int GetTxLastIdx(Trend trend_type, int start_last_index = 1)
{
//Go Back up the Top Bollinger until its reversed for setting Tx & T0
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
//Check if Reversed identified
if ((trend_type == Trend.Bullish && _bollbands.Top.Last(i + 1) > _bollbands.Top.Last(i)) || (trend_type == Trend.Bearish && _bollbands.Bottom.Last(i + 1) < _bollbands.Bottom.Last(i)))
//Return last index of the reverse candle
return i-1;
}
//No case found
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GetT0FromTxByLastIdx Method
// Returned value : last index of the first bollinger divergence
// -1 if no reverse found
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int GetT0FromTxLastIdx(int Tx_last_index = 1)
{
//Starting from Tx Index (should be passed by input parameter), try to find 1st Bollinger divergence
for (int i = Tx_last_index; i >= 1; i--)
{
//Check if Divergence identified
if (GetPhasysPulseByLastIdx(i) == 2)
//Return T0 Last Idx value
return i;
}
//No case found
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GetT1BullishFromTxByLastIdx Method
// Returned value : last index of the first candle to close outside top bollinger
// -1 if not found
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int GetT1FromTxLastIdx(Trend trend_type, int start_last_index = 1, int stop_last_index = 1)
{
//Starting from Tx Index (should be passed by input parameter), try to find 1st Bollinger divergence
for (int i = start_last_index; i >= stop_last_index; i--)
{
//Check if close price is above top bollinger
if ((trend_type == Trend.Bullish && _ms.ClosePrices.Last(i) > _bollbands.Top.Last(i)) || (trend_type == Trend.Bearish && _ms.ClosePrices.Last(i) < _bollbands.Bottom.Last(i)) )
//Return T0 Last Idx value
return i;
}
//No case found
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IsPhase2 Method
// Returned value :
// 2 if phasys 2 identified
// number of other phase if identified too (wrong phasys 2)
// -1 if no phasys detected
// Side effect : update class properties for Phasys 2
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int IsPhase2(int start_last_index = 1)
{
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IsPhase3Bullish Method
// Returned value :
// * True if a real phasys 3 identified
// * False if not
// Side effect : none
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool IsPhase3Bullish(int start_last_index = 1)
{
//A Phase 3 Bullish is defined by :
// - a minimum of 5 periods of the top Bollinger in the same way of the main (mm20) bollinger
// - only a phase2 previously to the phase 3
int trend_duration = 0;
int pulse = 0;
bool hasPhase2 = false;
//Go Back up the Top Bollinger until its reversed
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
pulse = GetPhasysPulseByLastIdx(i);
//Set Phase 2 found indicator
if(pulse == 2)
hasPhase2 = true;
//Check if Top Bollinger is Rising (this means that we are necessarily in phase 2 or 3)
if(_bollbands.Top.Last(i + 1) < _bollbands.Top.Last(i))
trend_duration++;
else
break;
}
//If trend_duration succeed to reach the minimum to define a trend with Phase 2 reached we can say it is a Phase 3
if(hasPhase2 && trend_duration >= ph2_period_min)
return true;
//Exit
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IsPhase3Bearish Method
// Returned value :
// * True if a real phasys 3 identified
// * False if not
// Side effect : none
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool IsPhase3Bearish(int start_last_index = 1)
{
//A Phase 3 Bearisj is defined by :
// - a minimum of 5 periods of the Bottom Bollinger in the same way of the main (mm20) bollinger
// - only a phase2 previously to the phase 3
int trend_duration = 0;
int pulse = 0;
bool hasPhase2 = false;
//Go Back up the Top Bollinger until its reversed
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
pulse = GetPhasysPulseByLastIdx(i);
//Set Phase 2 found indicator
if(pulse == 2)
hasPhase2 = true;
//Check if Top Bollinger is Rising (this means that we are necessarily in phase 2 or 3)
if(_bollbands.Top.Last(i + 1) > _bollbands.Top.Last(i))
trend_duration++;
else
break;
}
//If trend_duration succeed to reach the minimum to define a trend with Phase 2 reached we can say it is a Phase 3
if(hasPhase2 && trend_duration >= ph2_period_min)
return true;
//Exit
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IsPhase4Bullish Method
// Returned value :
// * True if phasys 3 identified
// * False if no phase 3 detected
// Side effect : none
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool IsPhase4Bullish(int start_last_index = 1)
{
//A Phase 4 Bullish is defined by :
// - coming from a phasys 3 itself coming from a phasys 2
//Go Back up history
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
//Pulse evaluation
if (GetPhasysPulseByLastIdx(i) != 4){
//We leave a phasys 4 pulses series
//Check from here if precedent phase was a real Phase 3
if(IsPhase3Bullish(i))
return true;
else
return false;
}
}
//Exit
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IsPhase4Bearish Method
// Returned value :
// * True if phasys 3 identified
// * False if no phase 3 detected
// Side effect : none
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool IsPhase4Bearish(int start_last_index = 1)
{
//A Phase 4 Bullish is defined by :
// - coming from a phasys 3 itself coming from a phasys 2
//Go Back up history
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
//Pulse evaluation
if (GetPhasysPulseByLastIdx(i) != 4){
//We leave a phasys 4 pulses series
//Check from here if precedent phase was a real Phase 3
if(IsPhase3Bearish(i))
return true;
else
return false;
}
}
//Exit
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SetPropertiesFromPhase3 Method
// Returned value : none
// Side effect : Properties set
//Prerequities : start_last_index should be in a real phase 3
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void SetPropertiesFromPhase3(Trend trend_type, int start_last_index = 1)
{
this.cycle_trend = trend_type;
//Find & Set the Tx (last index)
this.ph2_Tx_last_idx = GetTxLastIdx(this.cycle_trend, start_last_index);
//Find & Set the T0 (last index)
this.ph2_T0_last_idx = GetT0FromTxLastIdx( this.ph2_Tx_last_idx);
//Find & Set the T1 (last index)
this.ph2_T1_last_idx = GetT1FromTxLastIdx(Trend.Bullish, this.ph2_Tx_last_idx, start_last_index);
//Go Back up the Top Bollinger until its reversed
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
//If Bullish trend && Top Bollinger stop Rising then stop evaluation
if(trend_type == Trend.Bullish && _bollbands.Top.Last(i + 1) > _bollbands.Top.Last(i))
break;
//If Bearish trend && Bottom Bollinger stop Falling then stop evaluation
if(trend_type == Trend.Bearish && _bollbands.Bottom.Last(i + 1) < _bollbands.Bottom.Last(i))
break;
//Stop if we quit the phase 3
if(GetPhasysPulseByLastIdx(i) != 3)
break;
//Set T3 (1st candle of phase 3)
this.ph3_T3_last_idx = i;
}
//Calculate the Phase 2 duration (in periods) (start at T0 and stop before T3)
this.ph2_duration_periods = this.ph2_T0_last_idx - this.ph3_T3_last_idx;
//Calculate the Phase 3 duration (in periods)
this.ph3_duration_periods = this.ph3_T3_last_idx - start_last_index;
//Calculate Bollinger cycle duration
this.cycle_duration_periods = this.ph2_Tx_last_idx - start_last_index;
//Set the phasys
this.cycle_phase = 3;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SetPropertiesFromPhase4 Method
// Returned value : none
// Side effect : Properties set
//Prerequities : start_last_index should be in a real phase 4
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void SetPropertiesFromPhase4(Trend trend_type, int start_last_index = 1)
{
this.cycle_trend = trend_type;
this.ph4_duration_periods = 0;
//Go Back up history to find the last candle of the Phase 3
for (int i = start_last_index; i <= _ms.ClosePrices.Count - 1; i++)
{
//Calculate the Phase 4 duration
this.ph4_duration_periods += 1;
//Pulse evaluation
if (GetPhasysPulseByLastIdx(i) != 4){
//We leave a phasys 4 pulses series (candle(i) is the last of Phase 3
//Correct the Ph4 period counter
this.ph4_duration_periods -= 1;
//Set T4 (1st candle of phase 4)
this.ph4_T4_last_idx = i-1;
//=> Set properties from Phase 3
SetPropertiesFromPhase3(trend_type, i);
//And leave this loop
break;
}
}
//Calculate Bollinger cycle duration
this.cycle_duration_periods = this.ph2_Tx_last_idx - start_last_index;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// FindPh2T0WithMinPerDuration Method
// Returned value : T0 last index
// Side effect : none
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int FindPh2T0WithMinPerDuration(int last_idx_start, int last_idx_end, int ph2_per_duration_min=3)
{
int ph2_per_duration = 0;
int T0_to_return = -1;
for (int i = last_idx_end; i <= last_idx_start; i++)
{
if (_bollbands.Top.Last(i + 1) < _bollbands.Top.Last(i) && _bollbands.Bottom.Last(i + 1) > _bollbands.Bottom.Last(i))
{
ph2_per_duration++;
T0_to_return = i;
}
else
{
//Phasys 2 not encoutered yet or has been reset (in case of noize)...continue till end loop or ph2 fully identifyed
if (ph2_per_duration <= 0)
continue;
else
{
//if ph2 duration < min expected, continue to see if there were longer phasys 2 before (current one could be a noize)
if (ph2_per_duration < ph2_per_duration_min)
{
//reset counter
ph2_per_duration = 0;
T0_to_return = 0;
continue;
}
else
//last phasys 2 fully identifyed => Exit
return i;
}
}
}
return (ph2_per_duration >= ph2_per_duration_min ? T0_to_return : -1) ;
}
}
}
firemyst
09 Dec 2024, 23:52
First thing I would do is use the Print statement and write output to the logging (algo) tab to see what values and such are coming through where, so you can see what's happening.
And/or using visual studio to debug to see what the values are where.
@firemyst