Cycles/docs/analysis.md

107 lines
7.1 KiB
Markdown
Raw Permalink Normal View History

2025-05-20 18:36:59 +08:00
# Analysis Module
This document provides an overview of the `Analysis` module and its components, which are typically used for technical analysis of financial market data.
## Modules
The `Analysis` module includes classes for calculating common technical indicators:
- **Relative Strength Index (RSI)**: Implemented in `cycles/Analysis/rsi.py`.
- **Bollinger Bands**: Implemented in `cycles/Analysis/boillinger_band.py`.
- Note: Trading strategies are detailed in `strategies.md`.
2025-05-20 18:36:59 +08:00
## Class: `RSI`
Found in `cycles/Analysis/rsi.py`.
Calculates the Relative Strength Index.
### Mathematical Model
The standard RSI calculation typically involves Wilder's smoothing for average gains and losses.
1. **Price Change (Delta)**: Difference between consecutive closing prices.
2. **Gain and Loss**: Separate positive (gain) and negative (loss, expressed as positive) price changes.
3. **Average Gain (AvgU)** and **Average Loss (AvgD)**: Smoothed averages of gains and losses over the RSI period. Wilder's smoothing is a specific type of exponential moving average (EMA):
- Initial AvgU/AvgD: Simple Moving Average (SMA) over the first `period` values.
- Subsequent AvgU: `(Previous AvgU * (period - 1) + Current Gain) / period`
- Subsequent AvgD: `(Previous AvgD * (period - 1) + Current Loss) / period`
4. **Relative Strength (RS)**:
2025-05-20 18:36:59 +08:00
$$
RS = \\frac{\\text{AvgU}}{\\text{AvgD}}
2025-05-20 18:36:59 +08:00
$$
5. **RSI**:
2025-05-20 18:36:59 +08:00
$$
RSI = 100 - \\frac{100}{1 + RS}
2025-05-20 18:36:59 +08:00
$$
Special conditions:
- If AvgD is 0: RSI is 100 if AvgU > 0, or 50 if AvgU is also 0 (neutral).
2025-05-20 18:36:59 +08:00
### `__init__(self, config: dict)`
2025-05-20 18:36:59 +08:00
- **Description**: Initializes the RSI calculator.
- **Parameters**:\n - `config` (dict): Configuration dictionary. Must contain an `'rsi_period'` key with a positive integer value (e.g., `{'rsi_period': 14}`).
2025-05-20 18:36:59 +08:00
### `calculate(self, data_df: pd.DataFrame, price_column: str = 'close') -> pd.DataFrame`
- **Description**: Calculates the RSI (using Wilder's smoothing by default) and adds it as an 'RSI' column to the input DataFrame. This method utilizes `calculate_custom_rsi` internally with `smoothing='EMA'`.
- **Parameters**:\n - `data_df` (pd.DataFrame): DataFrame with historical price data. Must contain the `price_column`.\n - `price_column` (str, optional): The name of the column containing price data. Defaults to 'close'.
- **Returns**: `pd.DataFrame` - A copy of the input DataFrame with an added 'RSI' column. If data length is insufficient for the period, the 'RSI' column will contain `np.nan`.
### `calculate_custom_rsi(price_series: pd.Series, window: int = 14, smoothing: str = 'SMA') -> pd.Series` (Static Method)
- **Description**: Calculates RSI with a specified window and smoothing method (SMA or EMA). This is the core calculation engine.
2025-05-20 18:36:59 +08:00
- **Parameters**:
- `price_series` (pd.Series): Series of prices.
- `window` (int, optional): The period for RSI calculation. Defaults to 14. Must be a positive integer.
- `smoothing` (str, optional): Smoothing method, can be 'SMA' (Simple Moving Average) or 'EMA' (Exponential Moving Average, specifically Wilder's smoothing when `alpha = 1/window`). Defaults to 'SMA'.
- **Returns**: `pd.Series` - Series containing the RSI values. Returns a series of NaNs if data length is insufficient.
2025-05-20 18:36:59 +08:00
## Class: `BollingerBands`
Found in `cycles/Analysis/boillinger_band.py`.
Calculates Bollinger Bands.
2025-05-20 18:36:59 +08:00
### Mathematical Model
1. **Middle Band**: Simple Moving Average (SMA) over `period`.
2025-05-20 18:36:59 +08:00
$$
\\text{Middle Band} = \\text{SMA}(\\text{price}, \\text{period})
2025-05-20 18:36:59 +08:00
$$
2. **Standard Deviation (σ)**: Standard deviation of price over `period`.
3. **Upper Band**: Middle Band + `num_std` × σ
2025-05-20 18:36:59 +08:00
$$
\\text{Upper Band} = \\text{Middle Band} + \\text{num_std} \\times \\sigma_{\\text{period}}
2025-05-20 18:36:59 +08:00
$$
4. **Lower Band**: Middle Band `num_std` × σ
2025-05-20 18:36:59 +08:00
$$
\\text{Lower Band} = \\text{Middle Band} - \\text{num_std} \\times \\sigma_{\\text{period}}
2025-05-20 18:36:59 +08:00
$$
For the adaptive calculation in the `calculate` method (when `squeeze=False`):
- **BBWidth**: `(Reference Upper Band - Reference Lower Band) / SMA`, where reference bands are typically calculated using a 2.0 standard deviation multiplier.
- **MarketRegime**: Determined by comparing `BBWidth` to a threshold from the configuration. `1` for sideways, `0` for trending.
- The `num_std` used for the final Upper and Lower Bands then varies based on this `MarketRegime` and the `bb_std_dev_multiplier` values for "trending" and "sideways" markets from the configuration, applied row-wise.
2025-05-20 18:36:59 +08:00
### `__init__(self, config: dict)`
2025-05-20 18:36:59 +08:00
- **Description**: Initializes the BollingerBands calculator.
- **Parameters**:\n - `config` (dict): Configuration dictionary. It must contain:
- `'bb_period'` (int): Positive integer for the moving average and standard deviation period.
- `'trending'` (dict): Containing `'bb_std_dev_multiplier'` (float, positive) for trending markets.
- `'sideways'` (dict): Containing `'bb_std_dev_multiplier'` (float, positive) for sideways markets.
- `'bb_width'` (float): Positive float threshold for determining market regime.
### `calculate(self, data_df: pd.DataFrame, price_column: str = 'close', squeeze: bool = False) -> pd.DataFrame`
- **Description**: Calculates Bollinger Bands and adds relevant columns to the DataFrame.
- If `squeeze` is `False` (default): Calculates adaptive Bollinger Bands. It determines the market regime (trending/sideways) based on `BBWidth` and applies different standard deviation multipliers (from the `config`) on a row-by-row basis. Adds 'SMA', 'UpperBand', 'LowerBand', 'BBWidth', and 'MarketRegime' columns.
- If `squeeze` is `True`: Calculates simpler Bollinger Bands with a fixed window of 14 and a standard deviation multiplier of 1.5 by calling `calculate_custom_bands`. Adds 'SMA', 'UpperBand', 'LowerBand' columns; 'BBWidth' and 'MarketRegime' will be `NaN`.
- **Parameters**:\n - `data_df` (pd.DataFrame): DataFrame with price data. Must include the `price_column`.\n - `price_column` (str, optional): The name of the column containing the price data. Defaults to 'close'.\n - `squeeze` (bool, optional): If `True`, calculates bands with fixed parameters (window 14, std 1.5). Defaults to `False`.
- **Returns**: `pd.DataFrame` - A copy of the original DataFrame with added Bollinger Band related columns.
### `calculate_custom_bands(price_series: pd.Series, window: int = 20, num_std: float = 2.0, min_periods: int = None) -> tuple[pd.Series, pd.Series, pd.Series]` (Static Method)
- **Description**: Calculates Bollinger Bands with a specified window, standard deviation multiplier, and minimum periods.
- **Parameters**:
- `price_series` (pd.Series): Series of prices.
- `window` (int, optional): The period for the moving average and standard deviation. Defaults to 20.
- `num_std` (float, optional): The number of standard deviations for the upper and lower bands. Defaults to 2.0.
- `min_periods` (int, optional): Minimum number of observations in window required to have a value. Defaults to `window` if `None`.
- **Returns**: `tuple[pd.Series, pd.Series, pd.Series]` - A tuple containing the Upper band, SMA, and Lower band series.