-
Notifications
You must be signed in to change notification settings - Fork 1k
Improve Weighted Moving Average (WMA) indicator parity with Cython #2662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
needs some attention from you @cjdsellers 👇
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff, and thanks for all the tests!
Removing has_inputs
is a nice refinement.
On the suggestions, I don't think we need to support optional weights at this stage?
if self.inputs.len() == self.period { | ||
self.inputs.remove(0); | ||
self.inputs.pop_front(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're using a VecDeque
with a fixed capacity then this might not be necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VecDeque::with_capacity(n)
only pre-allocates space; it doesn’t enforce a hard cap.
If you keep pushing after len == n
, the deque re-allocates and grows, so you must still pop_front()
(or otherwise drop the oldest element) to keep the window at exactly period
items.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @nicolad 👌
Restores feature-parity and behavioural equivalence between the Rust
WeightedMovingAverage
implementation and the canonical Python/Cython reference.1 · Why this matters — Context & Motivation
has_inputs
flag and double-initialisation logic.2 · What changed
new_checked
:period > 0
,weights.len() == period
,∑wᵢ > ε
has_inputs
boolean tracked manuallyhas_inputs()
now derives from!inputs.is_empty()
reverse_weights
veczip(self.inputs.iter().rev(), self.weights.iter().rev())
(zero alloc)initialized = count() ≥ period
"period must equal weights.len()"
)///
comments on invariants & panics3 · Implementation notes
EPS = f64::EPSILON
ensures weight-sum check does not break on FP rounding.weighted_average()
is safe becauseself.weights.len() == self.period
is proven by construction.reset()
— matches Python behaviour.WeightedMovingAverage
is still!Send + !Sync
; wrap inArc<Mutex<…>>
when sharing between threads.4 · Tests added / updated
new_panics_on_zero_period
/new_checked_err_on_zero_period
period > 0
new_panics_on_zero_weight_sum
/weight_sum_below_epsilon
variants∑wᵢ > ε
initialized_flag_transitions
period
samplescount_matches_inputs_and_has_inputs
weighted_average_with_non_uniform_weights
negative_weights_positive_sum
nan_input_propagates
single_period_returns_latest_input
period == 1
degenerates to last pricevalue_with_sparse_weights
Related #2507