Hybrid
Hybrid indicators combine multiple analytical approaches to provide comprehensive market analysis. These indicators often merge trend, momentum, volatility, and volume components for enhanced signal quality.
Import Statement
from openalgo import api, ta
# Get data using OpenAlgo API
client = api(api_key='your_api_key_here', host='http://127.0.0.1:5000')
df = client.history(symbol="SBIN", exchange="NSE", interval="5m",
start_date="2025-04-01", end_date="2025-04-08")
Available Hybrid Indicators
Average Directional Index (ADX)
ADX measures the strength of a trend regardless of direction, providing both directional indicators (+DI, -DI) and trend strength (ADX).
Usage
di_plus, di_minus, adx = ta.adx(high, low, close, period=14)
Parameters
high (array-like): High prices
low (array-like): Low prices
close (array-like): Closing prices
period (int, default=14): Period for ADX calculation
Returns
tuple: (+DI, -DI, ADX) arrays in the same format as input
Example
# Calculate ADX system
di_plus, di_minus, adx = ta.adx(df['high'], df['low'], df['close'], period=14)
df['DI_Plus'] = di_plus
df['DI_Minus'] = di_minus
df['ADX'] = adx
# Trend analysis
df['Trend_Strength'] = df['ADX'].apply(lambda x: 'Strong' if x > 25 else 'Weak' if x > 20 else 'No Trend')
df['Trend_Direction'] = df.apply(lambda row: 'Bullish' if row['DI_Plus'] > row['DI_Minus']
else 'Bearish' if row['DI_Minus'] > row['DI_Plus'] else 'Neutral', axis=1)
print(df[['close', 'DI_Plus', 'DI_Minus', 'ADX', 'Trend_Strength', 'Trend_Direction']].tail())
Aroon Indicator
Aroon indicators measure the time since the highest high and lowest low, indicating trend strength and potential reversals.
Usage
aroon_up, aroon_down = ta.aroon(high, low, period=14)
Parameters
high (array-like): High prices
low (array-like): Low prices
period (int, default=14): Period for Aroon calculation
Returns
tuple: (aroon_up, aroon_down) arrays in the same format as input
Example
# Calculate Aroon indicators
aroon_up, aroon_down = ta.aroon(df['high'], df['low'], period=25)
df['Aroon_Up'] = aroon_up
df['Aroon_Down'] = aroon_down
df['Aroon_Oscillator'] = df['Aroon_Up'] - df['Aroon_Down']
# Signal interpretation
df['Aroon_Signal'] = df.apply(lambda row:
'Strong Uptrend' if row['Aroon_Up'] > 70 and row['Aroon_Down'] < 30
else 'Strong Downtrend' if row['Aroon_Down'] > 70 and row['Aroon_Up'] < 30
else 'Sideways' if abs(row['Aroon_Up'] - row['Aroon_Down']) < 20
else 'Trending', axis=1)
print(df[['close', 'Aroon_Up', 'Aroon_Down', 'Aroon_Oscillator', 'Aroon_Signal']].tail())
Pivot Points
Traditional pivot points calculate support and resistance levels based on previous period's high, low, and close.
Usage
pivot, r1, s1, r2, s2, r3, s3 = ta.pivot_points(high, low, close)
Parameters
high (array-like): High prices
low (array-like): Low prices
close (array-like): Closing prices
Returns
tuple: (pivot, r1, s1, r2, s2, r3, s3) arrays
Example
# Calculate Pivot Points
pivot, r1, s1, r2, s2, r3, s3 = ta.pivot_points(df['high'], df['low'], df['close'])
df['Pivot'] = pivot
df['Resistance_1'] = r1
df['Support_1'] = s1
df['Resistance_2'] = r2
df['Support_2'] = s2
df['Resistance_3'] = r3
df['Support_3'] = s3
# Identify price position relative to pivot
df['Price_Position'] = df.apply(lambda row:
'Above R2' if row['close'] > row['Resistance_2']
else 'Above R1' if row['close'] > row['Resistance_1']
else 'Above Pivot' if row['close'] > row['Pivot']
else 'Below Pivot' if row['close'] < row['Support_1']
else 'Below S1' if row['close'] < row['Support_2']
else 'Below S2' if row['close'] < row['Support_2']
else 'Near Pivot', axis=1)
print(df[['close', 'Pivot', 'Resistance_1', 'Support_1', 'Price_Position']].tail())
Parabolic SAR
Parabolic SAR provides trailing stop levels and trend direction signals.
Usage
sar_values, trend_direction = ta.psar(high, low, acceleration=0.02, maximum=0.2)
Parameters
high (array-like): High prices
low (array-like): Low prices
acceleration (float, default=0.02): Acceleration factor
maximum (float, default=0.2): Maximum acceleration factor
Returns
tuple: (sar_values, trend_direction) arrays
Example
# Calculate Parabolic SAR
sar_values, trend_direction = ta.psar(df['high'], df['low'])
df['SAR'] = sar_values
df['SAR_Trend'] = trend_direction
# Generate trading signals
df['SAR_Signal'] = df.apply(lambda row:
'Buy' if row['close'] > row['SAR'] and row['SAR_Trend'] == -1 # Uptrend
else 'Sell' if row['close'] < row['SAR'] and row['SAR_Trend'] == 1 # Downtrend
else 'Hold', axis=1)
# Calculate distance from SAR (risk management)
df['SAR_Distance'] = abs(df['close'] - df['SAR'])
df['SAR_Distance_Pct'] = (df['SAR_Distance'] / df['close']) * 100
print(df[['close', 'SAR', 'SAR_Signal', 'SAR_Distance_Pct']].tail())
Directional Movement Index (DMI)
DMI focuses on the directional indicators (+DI and -DI) without the ADX component.
Usage
di_plus, di_minus = ta.dmi(high, low, close, period=14)
Parameters
high (array-like): High prices
low (array-like): Low prices
close (array-like): Closing prices
period (int, default=14): Period for DMI calculation
Returns
tuple: (+DI, -DI) arrays in the same format as input
Example
# Calculate DMI
di_plus, di_minus = ta.dmi(df['high'], df['low'], df['close'])
df['DI_Plus'] = di_plus
df['DI_Minus'] = di_minus
df['DI_Spread'] = df['DI_Plus'] - df['DI_Minus']
# Generate directional signals
df['DMI_Signal'] = df.apply(lambda row:
'Strong Buy' if row['DI_Plus'] > row['DI_Minus'] and row['DI_Spread'] > 10
else 'Buy' if row['DI_Plus'] > row['DI_Minus']
else 'Strong Sell' if row['DI_Minus'] > row['DI_Plus'] and row['DI_Spread'] < -10
else 'Sell' if row['DI_Minus'] > row['DI_Plus']
else 'Neutral', axis=1)
print(df[['close', 'DI_Plus', 'DI_Minus', 'DI_Spread', 'DMI_Signal']].tail())
Williams Fractals
Williams Fractals identify turning points (fractals) in price action using local highs and lows.
Usage
fractal_up, fractal_down = ta.fractals(high, low, periods=2)
Parameters
high (array-like): High prices
low (array-like): Low prices
periods (int, default=2): Number of periods to check (minimum 2)
Returns
tuple: (fractal_up, fractal_down) boolean arrays indicating fractal points
Example
# Calculate Williams Fractals
fractal_up, fractal_down = ta.fractals(df['high'], df['low'], periods=2)
df['Fractal_Up'] = fractal_up
df['Fractal_Down'] = fractal_down
# Mark fractal levels
df['Fractal_High'] = df['high'].where(df['Fractal_Up'])
df['Fractal_Low'] = df['low'].where(df['Fractal_Down'])
# Count recent fractals for market structure analysis
window = 20
df['Recent_Fractal_Highs'] = df['Fractal_Up'].rolling(window).sum()
df['Recent_Fractal_Lows'] = df['Fractal_Down'].rolling(window).sum()
df['Market_Structure'] = df.apply(lambda row:
'Bullish Structure' if row['Recent_Fractal_Lows'] > row['Recent_Fractal_Highs']
else 'Bearish Structure' if row['Recent_Fractal_Highs'] > row['Recent_Fractal_Lows']
else 'Balanced', axis=1)
print(df[['close', 'Fractal_High', 'Fractal_Low', 'Market_Structure']].dropna().tail())
Random Walk Index (RWI)
RWI measures how much a security's price movement differs from a random walk, helping identify trending vs. random price movements.
Usage
rwi_high, rwi_low = ta.rwi(high, low, close, period=14)
Parameters
high (array-like): High prices
low (array-like): Low prices
close (array-like): Closing prices
period (int, default=14): Period for RWI calculation
Returns
tuple: (rwi_high, rwi_low) arrays in the same format as input
Example
# Calculate Random Walk Index
rwi_high, rwi_low = ta.rwi(df['high'], df['low'], df['close'], period=14)
df['RWI_High'] = rwi_high
df['RWI_Low'] = rwi_low
df['RWI_Max'] = df[['RWI_High', 'RWI_Low']].max(axis=1)
# Interpret RWI signals
df['RWI_Signal'] = df.apply(lambda row:
'Strong Uptrend' if row['RWI_High'] > 1.0 and row['RWI_High'] > row['RWI_Low']
else 'Strong Downtrend' if row['RWI_Low'] > 1.0 and row['RWI_Low'] > row['RWI_High']
else 'Weak Uptrend' if row['RWI_High'] > row['RWI_Low'] and row['RWI_High'] > 0.6
else 'Weak Downtrend' if row['RWI_Low'] > row['RWI_High'] and row['RWI_Low'] > 0.6
else 'Random Walk', axis=1)
# Calculate trend strength
df['Trend_Strength_RWI'] = df['RWI_Max'].apply(lambda x:
'Very Strong' if x > 1.5
else 'Strong' if x > 1.0
else 'Moderate' if x > 0.6
else 'Weak')
print(df[['close', 'RWI_High', 'RWI_Low', 'RWI_Signal', 'Trend_Strength_RWI']].tail())
Complete Example: Comprehensive Trend Analysis
import pandas as pd
from openalgo import api, ta
# Get market data
client = api(api_key='your_api_key_here', host='http://127.0.0.1:5000')
df = client.history(symbol="SBIN", exchange="NSE", interval="5m",
start_date="2025-04-01", end_date="2025-04-08")
# Calculate multiple hybrid indicators
print("Calculating hybrid indicators...")
# ADX System
di_plus, di_minus, adx = ta.adx(df['high'], df['low'], df['close'])
df['DI_Plus'] = di_plus
df['DI_Minus'] = di_minus
df['ADX'] = adx
# Aroon System
aroon_up, aroon_down = ta.aroon(df['high'], df['low'])
df['Aroon_Up'] = aroon_up
df['Aroon_Down'] = aroon_down
df['Aroon_Osc'] = df['Aroon_Up'] - df['Aroon_Down']
# Parabolic SAR
sar_values, sar_trend = ta.psar(df['high'], df['low'])
df['SAR'] = sar_values
df['SAR_Trend'] = sar_trend
# Random Walk Index
rwi_high, rwi_low = ta.rwi(df['high'], df['low'], df['close'])
df['RWI_High'] = rwi_high
df['RWI_Low'] = rwi_low
# Williams Fractals
fractal_up, fractal_down = ta.fractals(df['high'], df['low'])
df['Fractal_Up'] = fractal_up
df['Fractal_Down'] = fractal_down
# Create comprehensive trend signal
def comprehensive_trend_signal(row):
signals = []
# ADX Signal
if row['ADX'] > 25:
if row['DI_Plus'] > row['DI_Minus']:
signals.append('ADX_Bull')
else:
signals.append('ADX_Bear')
# Aroon Signal
if row['Aroon_Up'] > 70:
signals.append('Aroon_Bull')
elif row['Aroon_Down'] > 70:
signals.append('Aroon_Bear')
# SAR Signal
if row['close'] > row['SAR']:
signals.append('SAR_Bull')
else:
signals.append('SAR_Bear')
# RWI Signal
if row['RWI_High'] > 1.0 and row['RWI_High'] > row['RWI_Low']:
signals.append('RWI_Bull')
elif row['RWI_Low'] > 1.0 and row['RWI_Low'] > row['RWI_High']:
signals.append('RWI_Bear')
# Count bullish vs bearish signals
bull_count = len([s for s in signals if 'Bull' in s])
bear_count = len([s for s in signals if 'Bear' in s])
if bull_count > bear_count and bull_count >= 2:
return f'Bullish ({bull_count}/{len(signals)})'
elif bear_count > bull_count and bear_count >= 2:
return f'Bearish ({bear_count}/{len(signals)})'
else:
return f'Neutral ({bull_count}B/{bear_count}B)'
df['Comprehensive_Signal'] = df.apply(comprehensive_trend_signal, axis=1)
# Calculate signal strength
df['Signal_Strength'] = df.apply(lambda row:
row['ADX'] * 0.3 + abs(row['Aroon_Osc']) * 0.3 +
max(row['RWI_High'], row['RWI_Low']) * 40, axis=1)
# Display results
result_columns = ['close', 'ADX', 'Aroon_Osc', 'SAR', 'RWI_High', 'RWI_Low',
'Comprehensive_Signal', 'Signal_Strength']
print("\nComprehensive Trend Analysis:")
print(df[result_columns].tail(10))
# Summary statistics
print(f"\nSignal Distribution:")
print(df['Comprehensive_Signal'].value_counts())
print(f"\nAverage Signal Strength: {df['Signal_Strength'].mean():.2f}")
print(f"Current Signal Strength: {df['Signal_Strength'].iloc[-1]:.2f}")
Advanced Usage: Multi-Timeframe Analysis
# Function to get multiple timeframe data
def get_multi_timeframe_data(symbol, exchange, start_date, end_date):
timeframes = ['1m', '5m', '15m', '1h']
data = {}
for tf in timeframes:
try:
df = client.history(symbol=symbol, exchange=exchange, interval=tf,
start_date=start_date, end_date=end_date)
data[tf] = df
except Exception as e:
print(f"Error fetching {tf} data: {e}")
return data
# Multi-timeframe trend analysis
def analyze_multi_timeframe_trend(data_dict):
results = {}
for timeframe, df in data_dict.items():
# Calculate key hybrid indicators
di_plus, di_minus, adx = ta.adx(df['high'], df['low'], df['close'])
aroon_up, aroon_down = ta.aroon(df['high'], df['low'])
latest_adx = adx.iloc[-1] if not pd.isna(adx.iloc[-1]) else 0
latest_di_plus = di_plus.iloc[-1] if not pd.isna(di_plus.iloc[-1]) else 0
latest_di_minus = di_minus.iloc[-1] if not pd.isna(di_minus.iloc[-1]) else 0
latest_aroon_up = aroon_up.iloc[-1] if not pd.isna(aroon_up.iloc[-1]) else 0
latest_aroon_down = aroon_down.iloc[-1] if not pd.isna(aroon_down.iloc[-1]) else 0
# Determine trend
if latest_adx > 25:
if latest_di_plus > latest_di_minus:
trend = 'Bullish'
else:
trend = 'Bearish'
else:
trend = 'Sideways'
results[timeframe] = {
'Trend': trend,
'ADX': latest_adx,
'Aroon_Strength': abs(latest_aroon_up - latest_aroon_down)
}
return results
# Example usage
# mtf_data = get_multi_timeframe_data("SBIN", "NSE", "2025-04-01", "2025-04-08")
# mtf_analysis = analyze_multi_timeframe_trend(mtf_data)
# print("Multi-Timeframe Analysis:", mtf_analysis)
Performance Tips
Vectorized Operations: Use pandas operations for better performance with large datasets
Memory Optimization: Calculate only needed indicators to reduce memory usage
Caching: Store intermediate calculations for reuse across multiple indicators
Batch Processing: Process multiple symbols together when possible
Common Use Cases
Trend Confirmation: Use ADX with Aroon for trend strength validation
Entry Timing: Combine SAR with DMI for precise entry points
Support/Resistance: Use Pivot Points with Fractals for key levels
Risk Management: Use RWI to distinguish trending from random movements
Multi-Timeframe: Align signals across different timeframes for higher probability trades
Last updated