Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions include/pineforge/ta.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,8 +800,10 @@ class OBV {
double prev_close_ = na<double>();
int bar_count_ = 0;

double saved_sum_, saved_prev_close_;
int saved_bar_count_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_sum_ = 0.0, saved_prev_close_ = na<double>();
int saved_bar_count_ = 0;

public:
OBV() = default;
Expand All @@ -812,7 +814,9 @@ class OBV {
class AccDist {
double sum_ = 0.0;

double saved_sum_;
// Mirror the initial committed sum_ (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_sum_ = 0.0;

public:
AccDist() = default;
Expand All @@ -826,8 +830,11 @@ class NVI {
double prev_volume_ = na<double>();
int bar_count_ = 0;

double saved_nvi_, saved_prev_close_, saved_prev_volume_;
int saved_bar_count_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_nvi_ = 1.0, saved_prev_close_ = na<double>(),
saved_prev_volume_ = na<double>();
int saved_bar_count_ = 0;

public:
NVI() = default;
Expand All @@ -841,8 +848,11 @@ class PVI {
double prev_volume_ = na<double>();
int bar_count_ = 0;

double saved_pvi_, saved_prev_close_, saved_prev_volume_;
int saved_bar_count_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_pvi_ = 1.0, saved_prev_close_ = na<double>(),
saved_prev_volume_ = na<double>();
int saved_bar_count_ = 0;

public:
PVI() = default;
Expand All @@ -854,7 +864,9 @@ class PVT {
double pvt_ = 0.0;
double prev_close_ = na<double>();

double saved_pvt_, saved_prev_close_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_pvt_ = 0.0, saved_prev_close_ = na<double>();

public:
PVT() = default;
Expand All @@ -866,7 +878,9 @@ class WAD {
double wad_ = 0.0;
double prev_close_ = na<double>();

double saved_wad_, saved_prev_close_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_wad_ = 0.0, saved_prev_close_ = na<double>();

public:
WAD() = default;
Expand Down Expand Up @@ -908,7 +922,9 @@ class VWAP {
// anchor (`anchor = timeframe.change("1D")`); engine matches that.
int64_t anchor_day_ = std::numeric_limits<int64_t>::min();

double saved_cum_pv_, saved_cum_vol_, saved_cum_pv_sq_;
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
double saved_cum_pv_ = 0.0, saved_cum_vol_ = 0.0, saved_cum_pv_sq_ = 0.0;
int64_t saved_anchor_day_ = std::numeric_limits<int64_t>::min();

public:
Expand Down
17 changes: 14 additions & 3 deletions src/ta_extremes_volume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,10 @@ double PivotLow::compute(double src) {

// --- Cum (Cumulative Sum) ---

Cum::Cum() : sum_(0.0) {}
// saved_sum_ mirrors the initial committed sum_ (see RMA::RMA) so a
// recompute() before the first compute() restores a well-defined pristine
// state instead of reading uninitialized save-state.
Cum::Cum() : sum_(0.0), saved_sum_(0.0) {}

double Cum::compute(double src) {
saved_sum_ = sum_;
Expand All @@ -183,7 +186,11 @@ double Cum::compute(double src) {

// --- All-time max/min (chart series) ---

AllTimeMax::AllTimeMax() : max_(na<double>()), has_(false) {}
// saved_* mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
AllTimeMax::AllTimeMax()
: max_(na<double>()), has_(false),
saved_max_(na<double>()), saved_has_(false) {}

double AllTimeMax::compute(double src) {
saved_max_ = max_;
Expand All @@ -200,7 +207,11 @@ double AllTimeMax::compute(double src) {
return max_;
}

AllTimeMin::AllTimeMin() : min_(na<double>()), has_(false) {}
// saved_* mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
AllTimeMin::AllTimeMin()
: min_(na<double>()), has_(false),
saved_min_(na<double>()), saved_has_(false) {}

double AllTimeMin::compute(double src) {
saved_min_ = min_;
Expand Down
6 changes: 5 additions & 1 deletion src/ta_misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ double PercentRank::compute(double src) {
// BarsSince
// ============================================================================

BarsSince::BarsSince() : count_(0), ever_true_(false) {}
// saved_* mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
BarsSince::BarsSince()
: count_(0), ever_true_(false),
saved_count_(0), saved_ever_true_(false) {}

double BarsSince::compute(bool condition) {
saved_count_ = count_;
Expand Down
15 changes: 13 additions & 2 deletions src/ta_moving_averages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ namespace pineforge {
namespace ta {

RMA::RMA(int length)
: output_val(na<double>()), sum(0.0), length(length), bar_count(0) {}
: output_val(na<double>()), sum(0.0), length(length), bar_count(0),
// Mirror the initial committed state so a recompute() issued before
// the first compute() (e.g. the first partial sub-bar of a
// lookahead request.security aggregation) restores a well-defined
// pristine state instead of reading uninitialized save-state. Without
// this, restore() reads indeterminate memory and can poison the RMA
// with NaN non-deterministically.
saved_output_val_(na<double>()), saved_sum_(0.0), saved_bar_count_(0) {}

double RMA::compute(double src) {
save();
Expand Down Expand Up @@ -111,7 +118,11 @@ double SMA::compute(double src) {

EMA::EMA(int length)
: output_val(na<double>()), alpha(2.0 / (length + 1)), sum(0.0),
bar_count(0) {}
bar_count(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// issued before the first compute() restores a well-defined pristine
// state instead of reading uninitialized save-state members.
saved_output_val_(na<double>()), saved_sum_(0.0), saved_bar_count_(0) {}

double EMA::compute(double src) {
save();
Expand Down
43 changes: 36 additions & 7 deletions src/ta_oscillators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ namespace ta {
// --- RSI ---

RSI::RSI(int length)
: rma_up(length), rma_down(length), prev_src(na<double>()), bar_count(0) {}
: rma_up(length), rma_down(length), prev_src(na<double>()), bar_count(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state
// rather than reading uninitialized save-state members.
saved_prev_src_(na<double>()), saved_bar_count_(0) {}

double RSI::compute(double src) {
saved_prev_src_ = prev_src;
Expand Down Expand Up @@ -69,7 +73,10 @@ double RSI::compute(double src) {
// Ref: pinets/src/namespaces/ta/methods/crossover.ts

Crossover::Crossover()
: prev_a(na<double>()), prev_b(na<double>()) {}
: prev_a(na<double>()), prev_b(na<double>()),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_a_(na<double>()), saved_prev_b_(na<double>()) {}

bool Crossover::compute(double a, double b) {
saved_prev_a_ = prev_a;
Expand All @@ -91,7 +98,10 @@ bool Crossover::compute(double a, double b) {
// Ref: pinets/src/namespaces/ta/methods/crossunder.ts

Crossunder::Crossunder()
: prev_a(na<double>()), prev_b(na<double>()) {}
: prev_a(na<double>()), prev_b(na<double>()),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_a_(na<double>()), saved_prev_b_(na<double>()) {}

bool Crossunder::compute(double a, double b) {
saved_prev_a_ = prev_a;
Expand Down Expand Up @@ -159,7 +169,11 @@ double Change::compute(double src, int length) {

Cross::Cross()
: prev_a(na<double>()), prev_b(na<double>()),
last_nonzero_sign_(0) {}
last_nonzero_sign_(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_a_(na<double>()), saved_prev_b_(na<double>()),
saved_last_nonzero_sign_(0) {}

bool Cross::compute(double a, double b) {
saved_prev_a_ = prev_a;
Expand Down Expand Up @@ -391,7 +405,13 @@ double RCI::compute(double src) {
// MFI (Money Flow Index)
// ============================================================================

MFI::MFI(int length) : length_(length), prev_src_(na<double>()), bar_count_(0) {}
MFI::MFI(int length)
: length_(length), prev_src_(na<double>()), bar_count_(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
// The saved_*_buffer_ deques default-construct empty, matching the
// live pos_/neg_buffer_ initial empty state.
saved_prev_src_(na<double>()), saved_bar_count_(0) {}

double MFI::compute(double src, double vol) {
saved_prev_src_ = prev_src_;
Expand Down Expand Up @@ -421,7 +441,13 @@ double MFI::compute(double src, double vol) {
// CMO (Chande Momentum Oscillator)
// ============================================================================

CMO::CMO(int length) : length_(length), prev_src_(na<double>()), bar_count_(0) {}
CMO::CMO(int length)
: length_(length), prev_src_(na<double>()), bar_count_(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
// The saved_*_buffer_ deques default-construct empty, matching the
// live up_/down_buffer_ initial empty state.
saved_prev_src_(na<double>()), saved_bar_count_(0) {}

double CMO::compute(double src) {
saved_prev_src_ = prev_src_;
Expand Down Expand Up @@ -455,7 +481,10 @@ double CMO::compute(double src) {
TSI::TSI(int short_length, int long_length)
: ema_long_(long_length), ema_short_(short_length),
ema_abs_long_(long_length), ema_abs_short_(short_length),
prev_src_(na<double>()), bar_count_(0) {}
prev_src_(na<double>()), bar_count_(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_src_(na<double>()), saved_bar_count_(0) {}

double TSI::compute(double src) {
saved_prev_src_ = prev_src_;
Expand Down
33 changes: 28 additions & 5 deletions src/ta_volatility_trend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ MACDResult MACD::compute(double src) {
// --- ATR ---

ATR::ATR(int length)
: rma(length), prev_close(na<double>()), bar_count(0) {}
: rma(length), prev_close(na<double>()), bar_count(0),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_close_(na<double>()), saved_bar_count_(0) {}

double ATR::compute(double high, double low, double close) {
saved_prev_close_ = prev_close;
Expand Down Expand Up @@ -119,7 +122,12 @@ Supertrend::Supertrend(double factor, int atr_period)
: factor_(factor), atr_(atr_period),
prev_upper_(na<double>()), prev_lower_(na<double>()),
prev_st_(na<double>()), prev_direction_(1.0),
prev_close_(na<double>()), initialized_(false) {}
prev_close_(na<double>()), initialized_(false),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_upper_(na<double>()), saved_prev_lower_(na<double>()),
saved_prev_st_(na<double>()), saved_prev_direction_(1.0),
saved_prev_close_(na<double>()), saved_initialized_(false) {}

SupertrendResult Supertrend::compute(double high, double low, double close) {
saved_prev_upper_ = prev_upper_;
Expand Down Expand Up @@ -216,7 +224,11 @@ DMI::DMI(int di_length, int adx_smoothing)
: rma_plus_(di_length), rma_minus_(di_length), rma_tr_(di_length),
rma_adx_(adx_smoothing),
prev_high_(na<double>()), prev_low_(na<double>()),
prev_close_(na<double>()), first_bar_(true) {}
prev_close_(na<double>()), first_bar_(true),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_high_(na<double>()), saved_prev_low_(na<double>()),
saved_prev_close_(na<double>()), saved_first_bar_(true) {}

DMIResult DMI::compute(double high, double low, double close) {
saved_prev_high_ = prev_high_;
Expand Down Expand Up @@ -287,7 +299,14 @@ SAR::SAR(double start, double increment, double maximum)
af_(0.0), ep_(0.0), sar_(0.0),
is_long_(true), initialized_(false),
prev_high_(na<double>()), prev_low_(na<double>()), prev_close_(na<double>()),
prev_prev_high_(na<double>()), prev_prev_low_(na<double>()) {}
prev_prev_high_(na<double>()), prev_prev_low_(na<double>()),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_af_(0.0), saved_ep_(0.0), saved_sar_(0.0),
saved_is_long_(true), saved_initialized_(false),
saved_prev_high_(na<double>()), saved_prev_low_(na<double>()),
saved_prev_close_(na<double>()),
saved_prev_prev_high_(na<double>()), saved_prev_prev_low_(na<double>()) {}

namespace {

Expand Down Expand Up @@ -514,7 +533,11 @@ double KCW::compute(double src, double high, double low, double close) {
// TR (True Range as function)
// ============================================================================

TR::TR(bool handle_na) : prev_close_(na<double>()), bar_count_(0), handle_na_(handle_na) {}
TR::TR(bool handle_na)
: prev_close_(na<double>()), bar_count_(0), handle_na_(handle_na),
// Mirror the initial committed state (see RMA::RMA) so a recompute()
// before the first compute() restores a well-defined pristine state.
saved_prev_close_(na<double>()), saved_bar_count_(0) {}

double TR::compute(double high, double low, double close) {
saved_prev_close_ = prev_close_;
Expand Down
Loading
Loading