2025-06-07 14:01:20 +08:00
|
|
|
"""
|
|
|
|
|
Relative Strength Index (RSI) indicator implementation.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from typing import List
|
|
|
|
|
import pandas as pd
|
2025-06-09 16:28:16 +08:00
|
|
|
import numpy as np
|
2025-06-07 14:01:20 +08:00
|
|
|
|
|
|
|
|
from ..base import BaseIndicator
|
|
|
|
|
from ..result import IndicatorResult
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RSIIndicator(BaseIndicator):
|
|
|
|
|
"""
|
|
|
|
|
Relative Strength Index (RSI) technical indicator.
|
|
|
|
|
|
|
|
|
|
Measures momentum by comparing the magnitude of recent gains to recent losses.
|
|
|
|
|
Handles sparse data appropriately without interpolation.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def calculate(self, df: pd.DataFrame, period: int = 14,
|
2025-06-09 16:28:16 +08:00
|
|
|
price_column: str = 'close') -> pd.DataFrame:
|
2025-06-07 14:01:20 +08:00
|
|
|
"""
|
|
|
|
|
Calculate Relative Strength Index (RSI).
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
df: DataFrame with OHLCV data
|
|
|
|
|
period: Number of periods for RSI calculation (default: 14)
|
|
|
|
|
price_column: Price column to use ('open', 'high', 'low', 'close')
|
|
|
|
|
|
|
|
|
|
Returns:
|
2025-06-09 16:28:16 +08:00
|
|
|
DataFrame with RSI values and metadata, indexed by timestamp
|
2025-06-07 14:01:20 +08:00
|
|
|
"""
|
|
|
|
|
# Validate input data
|
2025-06-09 16:28:16 +08:00
|
|
|
if not self.validate_dataframe(df, period):
|
|
|
|
|
return pd.DataFrame()
|
2025-06-07 14:01:20 +08:00
|
|
|
try:
|
2025-06-09 16:28:16 +08:00
|
|
|
df = df.copy()
|
|
|
|
|
delta = df[price_column].diff()
|
|
|
|
|
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
|
|
|
|
|
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
|
|
|
|
|
rs = gain / loss
|
|
|
|
|
rs = rs.replace([np.inf, -np.inf], np.nan)
|
|
|
|
|
df['rsi'] = 100 - (100 / (1 + rs))
|
|
|
|
|
# Only keep rows with valid RSI, and only 'timestamp' and 'rsi' columns
|
|
|
|
|
result_df = df.loc[df['rsi'].notna(), ['timestamp', 'rsi']].copy()
|
|
|
|
|
result_df = result_df.iloc[period-1:]
|
|
|
|
|
result_df.set_index('timestamp', inplace=True)
|
|
|
|
|
return result_df
|
|
|
|
|
except Exception:
|
|
|
|
|
return pd.DataFrame()
|