You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Composable Monte Carlo techniques: any MonteCarloMethod now chains decorators fluently: pooledWith(other) pools two techniques 50/50 through derived sub-generators, widenedByRecentVolatility() widens terminal samples by the bounded ratio of recent realized to state volatility, and withStudentTScaleMixing() fattens tails with a mean-normalized Student-t scale-mixing factor; NormalInverseGammaForecastMethod.overResiduals(method) and overSmoothedResiduals() layer posterior parameter uncertainty over another technique's standardized residual paths. For example shockPath.pooledWith(NormalInverseGammaForecastMethod.withEmpiricalPriors().overSmoothedResiduals()).widenedByRecentVolatility().withStudentTScaleMixing() is passed straight to .monteCarloMethod(...). Every composition draws exclusively from MonteCarloContext.random(), so seeded forecasts stay reproducible, and degrades to an unstable forecast when a component returns null, miscounts, or emits non-finite samples. Widening scales around the inner technique's empirical center (dispersion only, never a location shift); Student-t mixing stays finite with bounded expected cost for arbitrarily large degrees of freedom; and foreign-precision inner samples are normalized through the context's NumFactory. WalkForwardCalibrationBakeoffExample builds its arms with this API, forecasts through MonteCarloReturnProjectionIndicator, persists per-arm checkpoints incrementally, and serializes empty volatility regimes as null.
Changed
For contributors: quiet, JUnit 5-only builds (CF-621): all tests now run on JUnit Jupiter (parameterized suites use @ParameterizedClass, and assumptions use org.junit.jupiter.api.Assumptions), so junit-vintage-engine is gone from the build. mvn verify and the quiet build gate now print no discovery notices, compiler notes, coverage warnings or release-script fixture chatter. The JaCoCo minimums for each module (ta4j.jacoco.line.minimum, ta4j.jacoco.branch.minimum) are set to that module's current coverage, so they act as a ratchet that warns when coverage regresses.
Correctly rounded DecimalNum square roots: DecimalNum.sqrt() and sqrt(MathContext) now use the JDK's correctly rounded BigDecimal.sqrt instead of a hand-rolled Newton iteration, so square roots no longer pay for repeated high-precision divisions and trace-log formatting. An unlimited MathContext still computes at the default 16 digits, so perfect squares with a root of at most 16 digits stay exact. Results can differ from earlier releases in the last digit of the requested precision (for example VolumeProfileKDEIndicator weights at the default 16 digits).
Fixed
Security: safer file-backed data loading: users of file-backed data sources should upgrade for protection against path-traversal ticker inputs. Ticker-based loading through AbstractFileBarSeriesDataSource now rejects tickers containing .., / or \ with IllegalArgumentException instead of using them in resource paths. CsvFileBarSeriesDataSource now skips incomplete rows and rows with invalid dates or numeric/OHLC data, allowing later valid bars to load.
EMA-family indicators on moving series match unbounded series again (#1666): since 0.25.0, AbstractEMAIndicator (EMA, MMA, EWMA), ATRIndicator, SMMAIndicator and WildersMAIndicator re-seeded at the new head whenever a bounded series dropped a bar, so values depended on maximumBarCount and the cost per bar grew with it. Their recurrences now continue across head advances, as in 0.24.1, and re-seed at the retained head only when no cached predecessor exists. RSI, MACD, ADX, Keltner, SuperTrend and other consumers read every bar therefore match an unbounded series at a constant per-bar cost, and values on moving series differ from 0.25.0–0.26.0 (Elliott swing and phase results included). Sources that explicitly reset, such as StochasticIndicator, the Klinger oscillator or CusumIndicator, still reset their dependents. Matching needs a long enough window: at least barCount bars for EWMAIndicator, more than barCount for WildersMAIndicator, and more than the warm-up for RSI and ATR. WyckoffPhaseIndicator.getLastPhaseTransitionIndex keeps retained transitions across head advances.
Elliott swing lists and empirical forecasts follow head advances: ElliottSwingIndicator and EmpiricalElliottWaveForecastIndicator register their sources and discard their caches when a bounded series advances its head, so consumers no longer mix cached results with re-evaluated swings or training data from bars that are no longer retained.
Position criteria respect a trading record's logical bounds: for a BaseTradingRecord created with a start or end index, position-based criteria (PnL, returns, position counts and ratios, streaks, commissions and fees, linear transaction costs, risk and statistical helpers, Monte Carlo drawdown) now evaluate only positions entered at or after the start, so trades before the analyzed range no longer leak into results. Positions whose exit falls after the end are treated as open at the end: closed-position metrics skip them and fee criteria charge only their entry, once per entry even when a lot-aware record later closes it in several partial exits. The new TradingRecord.getContainedPositions(BarSeries) exposes this population, and composed criteria and AnalysisWindow evaluations select the same positions. Records without explicit bounds are unchanged.
Gamma boosts exclude the zero endpoint: Shape-below-one gamma sampling now uses an open-closed uniform boost, keeping inverse-gamma forecasts finite for valid low-shape priors even when a supplied generator returns the legal value 0.0. This reflects the boost draw for seeded shape-below-one streams while leaving shape-at-least-one streams unchanged; the uniform distribution and sampler correctness are preserved.
DecimalNum.pow returns NaN for undefined results: raising a DecimalNum to a NaN, infinite, or primitive-backed NaN exponent, a fractional power of a negative number (including at unlimited precision), or zero to a negative power now returns NaN instead of failing with a NumberFormatException, NullPointerException, or ArithmeticException. Negative whole exponents at unlimited precision now return a reciprocal rounded to the default precision instead of throwing. The pow(Num) Javadoc documents this contract and the remaining ArithmeticException cases (a whole-part exponent that overflows int or exceeds BigDecimal's 999999999 limit, or an inexact result under a RoundingMode.UNNECESSARY context).