Summary
A failed attempt to port a TradingView Pine Script oscillator to cTrader’s C# API resulted in jagged outputs instead of smooth curves. The root cause was incorrect recursion logic in the two-pole filter implementation.
Root Cause
The flawed recursion occurred in the exponential smoothing logic due to two critical errors:
- Misuse of current index values in recursive calculations
- Improper handling of lagged values in the smoothing algorithm
Specifically:
// Original flawed logic:
smooth1[index] = (1 - alpha) * smooth1[index] + alpha * sma_n1[index];
^
// Should use PREVIOUSLY computed smooth1[index-1]
Why This Happens in Real Systems
- Pine Script automatically handles recursive series with
[]operators, while cTrader requires explicit state management - Time-series algorithms relying on recurrence relations are vulnerable to off-by-one errors during translation
- Historical value dependencies aren’t always obvious when porting between languages with different execution models
Real-World Impact
- False trading signals from erratic oscillator values
- Distorted technical analysis due to abnormal price filtering
- Loss of trader confidence in the indicator’s reliability
Example or Code (if necessary and relevant)
Corrected smoothing logic:
if (index == 0)
{
smooth1[index] = sma_n1[index];
smooth2[index] = sma_n1[index];
}
else
{
smooth1[index] = (1 - alpha) * smooth1[index - 1] + alpha * sma_n1[index];
smooth2[index] = (1 - alpha) * smooth2[index - 1] + alpha * smooth1[index];
}
How Senior Engineers Fix It
- Audit dependencies: Map all recursive relationships before porting
- Implement boundary handling: Explicit checks for initial values (
index=0) - Validate state propagation: Ensure all recursions reference
[index-1]not[index] - Backtest with anchors: Verify outputs at specific timestamps against reference implementation
- Parameterize normalization: Confirm calculation equivalence of
sma_n1(z-score vs min/max scaling in Pine Script)
Why Juniors Miss It
- Address-based confusion: Mistaking Pine Script’s relative indexing
[i-1]for literal array indices - Recursion blindness: Not recognizing implicit state management differences between platforms
- Over-reliance on syntax: Focusing on operator translation instead of algorithmic behavior
- Debugging gaps: Insufficient validation of intermediate series (e.g.,
sma_n1,smooth1) - Warmup neglect: Assuming indicators stabilize immediately without initialization period
Key takeaway: Porting indicators requires reconstructing the execution context—not just syntax. The recursive nature of financial filters amplifies small state-handling mistakes into visually obvious distortions.