OPEN SOURCE · UPSTREAM CONTRIBUTIONS
NautilusTrader
Correctness, reference validation, regression and performance work across Rust-native trading indicators in an open-source, production-grade multi-asset trading engine.
What NautilusTrader is
NautilusTrader is an open-source, production-grade, Rust-native engine for multi-asset and multi-venue trading systems. It combines research, deterministic simulation and live execution in one event-driven architecture, with Python serving as a control plane for strategy logic, configuration and orchestration.
Contribution trail
Seven authored upstream items across two indicator areas: three AroonOscillator contributions and four ArcherMovingAveragesTrends contributions.
7 items
AroonOscillator
Boundary correctness, merged regression coverage and a separate rolling-extrema performance RFC.
3 items
merge Merged PR
#5037 · merged 21 Sep 2026
Fix AroonOscillator MAX_PERIOD window capacity
ChangeThe accepted maximum period is 1,024, but Aroon requires a period + 1 observation window. The fix increases the internal high and low buffer capacity to retain all 1,025 observations instead of silently dropping the oldest extreme at the supported boundary.
The merged patch added mirrored Rust and Python regression coverage for initialization at exactly MAX_PERIOD + 1, retention of the oldest unique high and low, correct Aroon Up/Down/oscillator values at the boundary, and rollover on the next observation. It changed two files across three commits with +139 / -2 lines.
RustPythonCorrectnessRegression coverageAroonOscillator
check_circle Issue · completed
#4995 · fixed by #5037
AroonOscillator accepts MAX_PERIOD but cannot retain its required period + 1 window
FindingAt the accepted maximum period, the oscillator needed 1,025 highs and lows but its wrapping deques could hold only 1,024. That made the public constructor contract disagree with the storage invariant used by the calculation.
The report reproduced the failure against published v2.0.0rc5 and demonstrated a real signal error, not just an internal mismatch: an oldest unique high was evicted too early, changing Aroon Up from the expected 0.0 to 100.0 and the oscillator from -100.0 to 0.0.
Bug reportBoundary invariantRuntime reproductionTrading signal correctness
lightbulb Open RFC
#4996 · performance proposal
Consider amortized O(1) rolling extrema for AroonOscillator
ProposalAfter initialization, every Aroon update rescans the complete high and low windows. The RFC proposes maintaining monotonic deques so each observation enters and leaves once, moving initialized updates from O(p) to amortized O(1) and stream work from O(Np) toward O(N).
The proposal deliberately preserves the existing newest-occurrence tie semantics for equal highs/lows and treats benchmark evidence as a prerequisite for accepting the extra state and complexity. It keeps the optimization separate from the correctness fix.
RFCAlgorithmsPerformanceMonotonic dequeO(1) amortized
ArcherMovingAveragesTrends (AMAT)
A reference investigation that was closed after maintainer review, plus a confirmed reversal-state defect with a merged Rust fix.
4 items
fact_check Issue · closed
#5122 · reference clarified
ArcherMovingAveragesTrends ignores slow moving-average direction when computing trend state
InvestigationThe Rust port appeared to classify from fast-MA direction alone, so I reported the slow-MA path as a possible parity defect. Maintainer review went back to the pandas-ta reference and confirmed that a fast-rising, slow-falling window is intentionally a potential-bottom long signal rather than evidence of a missing agreement check.
The issue was closed as not a bug after that reference check. The investigation remains part of the contribution history because it documented the behavior, surfaced the historical #3017 interpretation, and led to an explicit maintainer clarification of the intended AMAT definition.
Reference investigationRustIndicator parityClosed as not a bug
cancel PR · closed unmerged
#5124 · closed after reference review
Fix ArcherMovingAveragesTrends slow MA direction
Proposed changeThe patch required the fast and slow MA deltas to agree before asserting a run. After re-checking the reference, the maintainer concluded that this would narrow AMAT beyond its intended definition, so the PR was closed without merge.
The code and regression tests were technically validated, but the behavioral premise was rejected. That distinction is recorded explicitly here: #5124 is a reviewed hypothesis and correction to the contribution history, not a merged upstream fix.
RustReference validationClosed unmergedAMAT
check_circle Issue · completed
#5123 · fixed by #5125
ArcherMovingAveragesTrends can report both long_run and short_run after a trend reversal
FindingThe Rust assignments OR-ed each new trend result with the previous boolean state. Once a direction became true, it could not clear without a full indicator reset, so a sustained reversal could leave both opposing flags true.
The report demonstrates both reversal directions and explains why the behavior conflicts with the bounded rolling signal window. After revisiting the AMAT reference, the maintainer confirmed that removing this historical latch is the standalone Rust correction. The issue was closed as completed when #5125 merged on 29 Sep 2026.
Bug reportState transitionRolling windowFixed upstream
merge Merged PR
#5125 · merged 29 Sep 2026
Fix ArcherMovingAveragesTrends reversal state
ChangeThe fix recomputes long_run and short_run from the current fast-MA signal window instead of permanently OR-ing new results into historical state. Sustained reversals can therefore clear the old direction and assert the new one.
Regression coverage includes bullish-to-bearish and bearish-to-bullish reversals. After the requested Clippy cast corrections and validation-description cleanup, maintainer cjdsellers formally approved the PR and it merged on 29 Sep 2026 as merge commit f805a97. Upstream pre-commit, Rust tests, script tests, and the Python 3.12/3.13 matrix passed on the reviewed head; the Python 3.14 job was blocked before checkout by an external ECR rate limit.
RustCorrectnessState transitionsMerged upstream
Historical AMAT context
Closed PR #3017 is relevant prior work but is not counted as one of my contributions. It proposed both a same-direction slow-MA requirement and direct current-window trend classification. During review of #5124, the maintainer revisited the AMAT reference and clarified that #3017 had misread the legacy two-line Cython expression: the first assignment captures the potential-bottom or potential-top case, while the second or combines the second case within the same update rather than intentionally requiring both moving averages to agree. The same-direction interpretation was therefore rejected; the useful surviving thread is removing historical state latching, which is the behavior addressed by merged PR #5125.
Contribution approach
The work separates observation, reference validation, implementation and performance concerns. Reproductions and regression tests are used to make hypotheses reviewable, but upstream reference evidence wins: the rejected slow-MA interpretation is preserved as a closed investigation rather than presented as a fix, while the confirmed reversal-state defect is paired with its merged implementation.