backtrader.indicators.deviation 源代码

#!/usr/bin/env python
"""Deviation Indicator Module - Standard deviation and mean deviation.

This module provides deviation indicators for measuring data dispersion.

Classes:
    StandardDeviation: Standard deviation indicator (alias: StdDev).
    MeanDeviation: Mean absolute deviation (alias: MeanDev).

Example:
    class MyStrategy(bt.Strategy):
        def __init__(self):
            self.sma = bt.indicators.SMA(self.data.close, period=20)
            self.stddev = bt.indicators.StdDev(self.data.close, period=20)
            self.upper_band = self.sma + 2 * self.stddev
            self.lower_band = self.sma - 2 * self.stddev

        def next(self):
            if self.data.close[0] > self.upper_band[0]:
                self.sell()
            elif self.data.close[0] < self.lower_band[0]:
                self.buy()
"""

import math

from . import Indicator, MovAv


[文档] class StandardDeviation(Indicator): """ Calculates the standard deviation of the passed data for a given period Note: - If 2 datas are provided as parameters, the second is considered to be the mean of the first - ``safepow`` (default: False) If this parameter is True, the standard deviation will be calculated as pow (abs(meansq - sqmean), 0.5) to safeguard for possible negative results of ``meansq - sqmean`` caused by the floating point representation. Formula: - meansquared = SimpleMovingAverage(pow (data, 2), period) - squaredmean = pow(SimpleMovingAverage(data, period), 2) - stddev = pow(meansquared - squaredmean, 0.5) # square root See: - http://en.wikipedia.org/wiki/Standard_deviation """ alias = ("StdDev",) lines = ("stddev",) params = ( ("period", 20), ("movav", MovAv.Simple), ("safepow", True), ) def _plotlabel(self): plabels = [self.p.period] plabels += [self.p.movav] * self.p.notdefault("movav") return plabels def __init__(self): """Initialize the Standard Deviation indicator. Sets minimum period and checks for external mean data source. """ super().__init__() self.addminperiod(self.p.period) # Store mean indicator if provided as second data self._use_external_mean = len(self.datas) > 1
[文档] def next(self): """Calculate standard deviation for the current bar. Uses the formula: sqrt(E[x^2] - E[x]^2) """ period = self.p.period data_sum = 0.0 data_sq_sum = 0.0 for i in range(period): val = self.data[-i] data_sum += val data_sq_sum += val * val mean = data_sum / period meansq = data_sq_sum / period sqmean = mean * mean diff = meansq - sqmean if self.p.safepow: diff = abs(diff) self.lines.stddev[0] = math.sqrt(max(0, diff))
[文档] def once(self, start, end): """Calculate standard deviation in runonce mode.""" darray = self.data.array larray = self.lines.stddev.array period = self.p.period safepow = self.p.safepow actual_end = min(end, len(darray)) while len(larray) < end: larray.append(0.0) # PERFORMANCE: Cache constants and functions nan_val = float("nan") sqrt = math.sqrt # Pre-fill warmup with NaN for i in range(min(period - 1, len(darray))): if i < len(larray): larray[i] = nan_val for i in range(period - 1, actual_end): data_sum = 0.0 data_sq_sum = 0.0 has_nan = False # PERFORMANCE: Simplified loop with faster NaN check for j in range(period): idx = i - j if 0 <= idx < len(darray): val = darray[idx] # PERFORMANCE: Use val != val for NaN check (faster) if val != val: has_nan = True break data_sum += val data_sq_sum += val * val if has_nan: if i < len(larray): larray[i] = nan_val continue mean = data_sum / period meansq = data_sq_sum / period sqmean = mean * mean diff = meansq - sqmean if safepow: diff = abs(diff) if i < len(larray): larray[i] = sqrt(max(0, diff))
# Average deviation
[文档] class MeanDeviation(Indicator): """MeanDeviation (alias MeanDev) Calculates the Mean Deviation of the passed data for a given period Note: - If 2 datas are provided as parameters, the second is considered to be the mean of the first Formula: - mean = MovingAverage(data, period) (or provided mean) - absdeviation = abs (data - mean) - meandev = MovingAverage(absdeviation, period) See: - https://en.wikipedia.org/wiki/Average_absolute_deviation """ alias = ("MeanDev",) lines = ("meandev",) params = ( ("period", 20), ("movav", MovAv.Simple), ) def _plotlabel(self): plabels = [self.p.period] plabels += [self.p.movav] * self.p.notdefault("movav") return plabels def __init__(self): """Initialize the Mean Deviation indicator. Creates the mean deviation calculation using either external mean or calculated moving average. """ # CRITICAL: Match master branch behavior # If 2 datas are provided, the 2nd is considered to be the mean of the first if len(self.datas) > 1: mean = self.data1 else: mean = self.p.movav(self.data, period=self.p.period) absdev = abs(self.data - mean) self.lines.meandev = self.p.movav(absdev, period=self.p.period)
StdDev = StandardDeviation MeanDev = MeanDeviation