Files
QuanTAlib/lib/averages/Htit.cs
T
2024-09-24 16:41:26 -07:00

146 lines
4.7 KiB
C#

//not working yet
//TODO consistency test
using QuanTAlib;
public class Htit : AbstractBase
{
private readonly CircularBuffer _priceBuffer = new(7);
private readonly CircularBuffer _spBuffer = new(7);
private readonly CircularBuffer _dtBuffer = new(7);
private readonly CircularBuffer _i1Buffer = new(7);
private readonly CircularBuffer _q1Buffer = new(7);
private readonly CircularBuffer _i2Buffer = new(2);
private readonly CircularBuffer _q2Buffer = new(2);
private readonly CircularBuffer _reBuffer = new(2);
private readonly CircularBuffer _imBuffer = new(2);
private readonly CircularBuffer _pdBuffer = new(2);
private readonly CircularBuffer _sdBuffer = new(2);
private readonly CircularBuffer _itBuffer = new(4);
private double _lastPd = 0;
private double _p_lastPd = 0;
public Htit() : base()
{
Name = "Htit";
WarmupPeriod = 12;
}
public Htit(object source) : this()
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_p_lastPd = _lastPd;
_index++;
}
else
{
_lastPd = _p_lastPd;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
double pr = Input.Value;
_priceBuffer.Add(pr, Input.IsNew);
if (_index <= 5)
{
_spBuffer.Add(0, Input.IsNew);
_dtBuffer.Add(0, Input.IsNew);
_i1Buffer.Add(0, Input.IsNew);
_q1Buffer.Add(0, Input.IsNew);
_i2Buffer.Add(0, Input.IsNew);
_q2Buffer.Add(0, Input.IsNew);
_reBuffer.Add(0, Input.IsNew);
_imBuffer.Add(0, Input.IsNew);
_pdBuffer.Add(0, Input.IsNew);
_sdBuffer.Add(0, Input.IsNew);
_itBuffer.Add(pr, Input.IsNew);
return pr;
}
double adj = (0.075 * _lastPd) + 0.54;
// Smooth and detrender
double sp = ((4 * _priceBuffer[0]) + (3 * _priceBuffer[1]) + (2 * _priceBuffer[2]) + _priceBuffer[3]) / 10;
_spBuffer.Add(sp, Input.IsNew);
double dt = ((0.0962 * _spBuffer[0]) + (0.5769 * _spBuffer[2]) - (0.5769 * _spBuffer[4]) - (0.0962 * _spBuffer[6])) * adj;
_dtBuffer.Add(dt, Input.IsNew);
// In-phase and quadrature
double q1 = ((0.0962 * _dtBuffer[0]) + (0.5769 * _dtBuffer[2]) - (0.5769 * _dtBuffer[4]) - (0.0962 * _dtBuffer[6])) * adj;
_q1Buffer.Add(q1, Input.IsNew);
double i1 = _dtBuffer[3];
_i1Buffer.Add(i1, Input.IsNew);
// Advance the phases by 90 degrees
double jI = ((0.0962 * _i1Buffer[0]) + (0.5769 * _i1Buffer[2]) - (0.5769 * _i1Buffer[4]) - (0.0962 * _i1Buffer[6])) * adj;
double jQ = ((0.0962 * _q1Buffer[0]) + (0.5769 * _q1Buffer[2]) - (0.5769 * _q1Buffer[4]) - (0.0962 * _q1Buffer[6])) * adj;
// Phasor addition for 3-bar averaging
double i2 = i1 - jQ;
double q2 = q1 + jI;
i2 = (0.2 * i2) + (0.8 * _i2Buffer[0]);
q2 = (0.2 * q2) + (0.8 * _q2Buffer[0]);
_i2Buffer.Add(i2, Input.IsNew);
_q2Buffer.Add(q2, Input.IsNew);
// Homodyne discriminator
double re = (i2 * _i2Buffer[1]) + (q2 * _q2Buffer[1]);
double im = (i2 * _q2Buffer[1]) - (q2 * _i2Buffer[1]);
re = (0.2 * re) + (0.8 * _reBuffer[0]);
im = (0.2 * im) + (0.8 * _imBuffer[0]);
_reBuffer.Add(re, Input.IsNew);
_imBuffer.Add(im, Input.IsNew);
// Calculate period
double pd = (im != 0 && re != 0) ? 2 * Math.PI / Math.Atan(im / re) : 0;
// Adjust period to thresholds
pd = (pd > 1.5 * _lastPd) ? 1.5 * _lastPd : pd;
pd = (pd < 0.67 * _lastPd) ? 0.67 * _lastPd : pd;
pd = (pd < 6) ? 6 : pd;
pd = (pd > 50) ? 50 : pd;
// Smooth the period
pd = (0.2 * pd) + (0.8 * _lastPd);
_pdBuffer.Add(pd, Input.IsNew);
double sd = (0.33 * pd) + (0.67 * _sdBuffer[0]);
_sdBuffer.Add(sd, Input.IsNew);
// Smooth dominant cycle period
int dcPeriods = (int)(sd + 0.5);
double sumPr = _priceBuffer.GetSpan().Slice(0, Math.Min(dcPeriods, _priceBuffer.Count)).ToArray().Sum();
double it = dcPeriods > 0 ? sumPr / dcPeriods : pr;
_itBuffer.Add(it, Input.IsNew);
_p_lastPd = _lastPd;
_lastPd = pd;
// Final indicator
if (_index >= 11) // 12th bar
{
return ((4 * _itBuffer[0]) + (3 * _itBuffer[1]) + (2 * _itBuffer[2]) + _itBuffer[3]) / 10;
}
else
{
return pr;
}
}
}