577 lines
20 KiB
Markdown
577 lines
20 KiB
Markdown
|
|
# Trend Indicators
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
|
|||
|
|
Trend indicators help identify the direction and strength of market trends. IncrementalTrader provides Supertrend implementations that combine price action with volatility to generate clear trend signals.
|
|||
|
|
|
|||
|
|
## SupertrendState
|
|||
|
|
|
|||
|
|
Individual Supertrend indicator that tracks trend direction and provides support/resistance levels.
|
|||
|
|
|
|||
|
|
### Features
|
|||
|
|
- **Trend Direction**: Clear bullish/bearish trend identification
|
|||
|
|
- **Dynamic Support/Resistance**: Adaptive levels based on volatility
|
|||
|
|
- **ATR-Based**: Uses Average True Range for volatility adjustment
|
|||
|
|
- **Real-time Updates**: Incremental calculation for live trading
|
|||
|
|
|
|||
|
|
### Mathematical Formula
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Basic Upper Band = (High + Low) / 2 + (Multiplier × ATR)
|
|||
|
|
Basic Lower Band = (High + Low) / 2 - (Multiplier × ATR)
|
|||
|
|
|
|||
|
|
Final Upper Band = Basic Upper Band < Previous Final Upper Band OR Previous Close > Previous Final Upper Band
|
|||
|
|
? Basic Upper Band : Previous Final Upper Band
|
|||
|
|
|
|||
|
|
Final Lower Band = Basic Lower Band > Previous Final Lower Band OR Previous Close < Previous Final Lower Band
|
|||
|
|
? Basic Lower Band : Previous Final Lower Band
|
|||
|
|
|
|||
|
|
Supertrend = Close <= Final Lower Band ? Final Lower Band : Final Upper Band
|
|||
|
|
Trend = Close <= Final Lower Band ? DOWN : UP
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Class Definition
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from IncrementalTrader.strategies.indicators import SupertrendState
|
|||
|
|
|
|||
|
|
class SupertrendState(OHLCIndicatorState):
|
|||
|
|
def __init__(self, period: int, multiplier: float):
|
|||
|
|
super().__init__(period)
|
|||
|
|
self.multiplier = multiplier
|
|||
|
|
self.atr = SimpleATRState(period)
|
|||
|
|
|
|||
|
|
# Supertrend state
|
|||
|
|
self.supertrend_value = 0.0
|
|||
|
|
self.trend = 1 # 1 for up, -1 for down
|
|||
|
|
self.final_upper_band = 0.0
|
|||
|
|
self.final_lower_band = 0.0
|
|||
|
|
self.previous_close = 0.0
|
|||
|
|
|
|||
|
|
def _process_ohlc_data(self, high: float, low: float, close: float):
|
|||
|
|
# Update ATR
|
|||
|
|
self.atr.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
if not self.atr.is_ready():
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# Calculate basic bands
|
|||
|
|
hl2 = (high + low) / 2.0
|
|||
|
|
atr_value = self.atr.get_value()
|
|||
|
|
|
|||
|
|
basic_upper_band = hl2 + (self.multiplier * atr_value)
|
|||
|
|
basic_lower_band = hl2 - (self.multiplier * atr_value)
|
|||
|
|
|
|||
|
|
# Calculate final bands
|
|||
|
|
if self.data_count == 1:
|
|||
|
|
self.final_upper_band = basic_upper_band
|
|||
|
|
self.final_lower_band = basic_lower_band
|
|||
|
|
else:
|
|||
|
|
# Final upper band logic
|
|||
|
|
if basic_upper_band < self.final_upper_band or self.previous_close > self.final_upper_band:
|
|||
|
|
self.final_upper_band = basic_upper_band
|
|||
|
|
|
|||
|
|
# Final lower band logic
|
|||
|
|
if basic_lower_band > self.final_lower_band or self.previous_close < self.final_lower_band:
|
|||
|
|
self.final_lower_band = basic_lower_band
|
|||
|
|
|
|||
|
|
# Determine trend and supertrend value
|
|||
|
|
if close <= self.final_lower_band:
|
|||
|
|
self.trend = -1 # Downtrend
|
|||
|
|
self.supertrend_value = self.final_lower_band
|
|||
|
|
else:
|
|||
|
|
self.trend = 1 # Uptrend
|
|||
|
|
self.supertrend_value = self.final_upper_band
|
|||
|
|
|
|||
|
|
self.previous_close = close
|
|||
|
|
|
|||
|
|
def get_value(self) -> float:
|
|||
|
|
return self.supertrend_value
|
|||
|
|
|
|||
|
|
def get_trend(self) -> int:
|
|||
|
|
"""Get current trend direction: 1 for up, -1 for down."""
|
|||
|
|
return self.trend
|
|||
|
|
|
|||
|
|
def is_bullish(self) -> bool:
|
|||
|
|
"""Check if current trend is bullish."""
|
|||
|
|
return self.trend == 1
|
|||
|
|
|
|||
|
|
def is_bearish(self) -> bool:
|
|||
|
|
"""Check if current trend is bearish."""
|
|||
|
|
return self.trend == -1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Usage Examples
|
|||
|
|
|
|||
|
|
#### Basic Supertrend Usage
|
|||
|
|
```python
|
|||
|
|
# Create Supertrend with 10-period ATR and 3.0 multiplier
|
|||
|
|
supertrend = SupertrendState(period=10, multiplier=3.0)
|
|||
|
|
|
|||
|
|
# OHLC data: (high, low, close)
|
|||
|
|
ohlc_data = [
|
|||
|
|
(105.0, 102.0, 104.0),
|
|||
|
|
(106.0, 103.0, 105.5),
|
|||
|
|
(107.0, 104.0, 106.0),
|
|||
|
|
(108.0, 105.0, 107.5)
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
supertrend.update_ohlc(high, low, close)
|
|||
|
|
if supertrend.is_ready():
|
|||
|
|
trend_direction = "BULLISH" if supertrend.is_bullish() else "BEARISH"
|
|||
|
|
print(f"Supertrend: {supertrend.get_value():.2f}, Trend: {trend_direction}")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Trend Change Detection
|
|||
|
|
```python
|
|||
|
|
class SupertrendSignals:
|
|||
|
|
def __init__(self, period: int = 10, multiplier: float = 3.0):
|
|||
|
|
self.supertrend = SupertrendState(period, multiplier)
|
|||
|
|
self.previous_trend = None
|
|||
|
|
|
|||
|
|
def update(self, high: float, low: float, close: float):
|
|||
|
|
self.supertrend.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
def get_signal(self) -> str:
|
|||
|
|
if not self.supertrend.is_ready():
|
|||
|
|
return "HOLD"
|
|||
|
|
|
|||
|
|
current_trend = self.supertrend.get_trend()
|
|||
|
|
|
|||
|
|
# Check for trend change
|
|||
|
|
if self.previous_trend is not None and self.previous_trend != current_trend:
|
|||
|
|
if current_trend == 1:
|
|||
|
|
signal = "BUY" # Trend changed to bullish
|
|||
|
|
else:
|
|||
|
|
signal = "SELL" # Trend changed to bearish
|
|||
|
|
else:
|
|||
|
|
signal = "HOLD"
|
|||
|
|
|
|||
|
|
self.previous_trend = current_trend
|
|||
|
|
return signal
|
|||
|
|
|
|||
|
|
def get_support_resistance(self) -> float:
|
|||
|
|
"""Get current support/resistance level."""
|
|||
|
|
return self.supertrend.get_value()
|
|||
|
|
|
|||
|
|
# Usage
|
|||
|
|
signals = SupertrendSignals(period=10, multiplier=3.0)
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
signals.update(high, low, close)
|
|||
|
|
signal = signals.get_signal()
|
|||
|
|
support_resistance = signals.get_support_resistance()
|
|||
|
|
|
|||
|
|
if signal != "HOLD":
|
|||
|
|
print(f"Signal: {signal} at {close:.2f}, S/R: {support_resistance:.2f}")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Performance Characteristics
|
|||
|
|
- **Time Complexity**: O(1) per update
|
|||
|
|
- **Space Complexity**: O(ATR_period)
|
|||
|
|
- **Memory Usage**: ~8 bytes per ATR period + constant overhead
|
|||
|
|
|
|||
|
|
## SupertrendCollection
|
|||
|
|
|
|||
|
|
Collection of multiple Supertrend indicators for meta-trend analysis.
|
|||
|
|
|
|||
|
|
### Features
|
|||
|
|
- **Multiple Timeframes**: Combines different Supertrend configurations
|
|||
|
|
- **Consensus Signals**: Requires agreement among multiple indicators
|
|||
|
|
- **Trend Strength**: Measures trend strength through consensus
|
|||
|
|
- **Flexible Configuration**: Customizable periods and multipliers
|
|||
|
|
|
|||
|
|
### Class Definition
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
class SupertrendCollection:
|
|||
|
|
def __init__(self, configs: list):
|
|||
|
|
"""
|
|||
|
|
Initialize with list of (period, multiplier) tuples.
|
|||
|
|
Example: [(10, 3.0), (14, 2.0), (21, 1.5)]
|
|||
|
|
"""
|
|||
|
|
self.supertrendss = []
|
|||
|
|
for period, multiplier in configs:
|
|||
|
|
self.supertrendss.append(SupertrendState(period, multiplier))
|
|||
|
|
|
|||
|
|
self.configs = configs
|
|||
|
|
|
|||
|
|
def update_ohlc(self, high: float, low: float, close: float):
|
|||
|
|
"""Update all Supertrend indicators."""
|
|||
|
|
for st in self.supertrendss:
|
|||
|
|
st.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
def is_ready(self) -> bool:
|
|||
|
|
"""Check if all indicators are ready."""
|
|||
|
|
return all(st.is_ready() for st in self.supertrendss)
|
|||
|
|
|
|||
|
|
def get_consensus_trend(self) -> int:
|
|||
|
|
"""Get consensus trend: 1 for bullish, -1 for bearish, 0 for mixed."""
|
|||
|
|
if not self.is_ready():
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
trends = [st.get_trend() for st in self.supertrendss]
|
|||
|
|
bullish_count = sum(1 for trend in trends if trend == 1)
|
|||
|
|
bearish_count = sum(1 for trend in trends if trend == -1)
|
|||
|
|
|
|||
|
|
if bullish_count > bearish_count:
|
|||
|
|
return 1
|
|||
|
|
elif bearish_count > bullish_count:
|
|||
|
|
return -1
|
|||
|
|
else:
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
def get_trend_strength(self) -> float:
|
|||
|
|
"""Get trend strength as percentage of indicators agreeing."""
|
|||
|
|
if not self.is_ready():
|
|||
|
|
return 0.0
|
|||
|
|
|
|||
|
|
consensus_trend = self.get_consensus_trend()
|
|||
|
|
if consensus_trend == 0:
|
|||
|
|
return 0.0
|
|||
|
|
|
|||
|
|
trends = [st.get_trend() for st in self.supertrendss]
|
|||
|
|
agreeing_count = sum(1 for trend in trends if trend == consensus_trend)
|
|||
|
|
|
|||
|
|
return agreeing_count / len(trends)
|
|||
|
|
|
|||
|
|
def get_supertrend_values(self) -> list:
|
|||
|
|
"""Get all Supertrend values."""
|
|||
|
|
return [st.get_value() for st in self.supertrendss if st.is_ready()]
|
|||
|
|
|
|||
|
|
def get_average_supertrend(self) -> float:
|
|||
|
|
"""Get average Supertrend value."""
|
|||
|
|
values = self.get_supertrend_values()
|
|||
|
|
return sum(values) / len(values) if values else 0.0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Usage Examples
|
|||
|
|
|
|||
|
|
#### Multi-Timeframe Trend Analysis
|
|||
|
|
```python
|
|||
|
|
# Create collection with different configurations
|
|||
|
|
configs = [
|
|||
|
|
(10, 3.0), # Fast Supertrend
|
|||
|
|
(14, 2.5), # Medium Supertrend
|
|||
|
|
(21, 2.0) # Slow Supertrend
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
supertrend_collection = SupertrendCollection(configs)
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
supertrend_collection.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
if supertrend_collection.is_ready():
|
|||
|
|
consensus = supertrend_collection.get_consensus_trend()
|
|||
|
|
strength = supertrend_collection.get_trend_strength()
|
|||
|
|
avg_supertrend = supertrend_collection.get_average_supertrend()
|
|||
|
|
|
|||
|
|
trend_name = {1: "BULLISH", -1: "BEARISH", 0: "MIXED"}[consensus]
|
|||
|
|
print(f"Consensus: {trend_name}, Strength: {strength:.1%}, Avg S/R: {avg_supertrend:.2f}")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Meta-Trend Strategy
|
|||
|
|
```python
|
|||
|
|
class MetaTrendStrategy:
|
|||
|
|
def __init__(self):
|
|||
|
|
# Multiple Supertrend configurations
|
|||
|
|
self.supertrend_collection = SupertrendCollection([
|
|||
|
|
(10, 3.0), # Fast
|
|||
|
|
(14, 2.5), # Medium
|
|||
|
|
(21, 2.0), # Slow
|
|||
|
|
(28, 1.5) # Very slow
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
self.previous_consensus = None
|
|||
|
|
|
|||
|
|
def update(self, high: float, low: float, close: float):
|
|||
|
|
self.supertrend_collection.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
def get_meta_signal(self) -> dict:
|
|||
|
|
if not self.supertrend_collection.is_ready():
|
|||
|
|
return {"signal": "HOLD", "confidence": 0.0, "strength": 0.0}
|
|||
|
|
|
|||
|
|
current_consensus = self.supertrend_collection.get_consensus_trend()
|
|||
|
|
strength = self.supertrend_collection.get_trend_strength()
|
|||
|
|
|
|||
|
|
# Check for consensus change
|
|||
|
|
signal = "HOLD"
|
|||
|
|
if self.previous_consensus is not None and self.previous_consensus != current_consensus:
|
|||
|
|
if current_consensus == 1:
|
|||
|
|
signal = "BUY"
|
|||
|
|
elif current_consensus == -1:
|
|||
|
|
signal = "SELL"
|
|||
|
|
|
|||
|
|
# Calculate confidence based on strength and consensus
|
|||
|
|
confidence = strength if current_consensus != 0 else 0.0
|
|||
|
|
|
|||
|
|
self.previous_consensus = current_consensus
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"signal": signal,
|
|||
|
|
"confidence": confidence,
|
|||
|
|
"strength": strength,
|
|||
|
|
"consensus": current_consensus,
|
|||
|
|
"avg_supertrend": self.supertrend_collection.get_average_supertrend()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Usage
|
|||
|
|
meta_strategy = MetaTrendStrategy()
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
meta_strategy.update(high, low, close)
|
|||
|
|
result = meta_strategy.get_meta_signal()
|
|||
|
|
|
|||
|
|
if result["signal"] != "HOLD":
|
|||
|
|
print(f"Meta Signal: {result['signal']}, Confidence: {result['confidence']:.1%}")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Performance Characteristics
|
|||
|
|
- **Time Complexity**: O(n) per update (where n is number of Supertrends)
|
|||
|
|
- **Space Complexity**: O(sum of all ATR periods)
|
|||
|
|
- **Memory Usage**: Scales with number of indicators
|
|||
|
|
|
|||
|
|
## Advanced Usage Patterns
|
|||
|
|
|
|||
|
|
### Adaptive Supertrend
|
|||
|
|
```python
|
|||
|
|
class AdaptiveSupertrend:
|
|||
|
|
def __init__(self, base_period: int = 14, base_multiplier: float = 2.0):
|
|||
|
|
self.base_period = base_period
|
|||
|
|
self.base_multiplier = base_multiplier
|
|||
|
|
|
|||
|
|
# Volatility measurement for adaptation
|
|||
|
|
self.atr_short = SimpleATRState(period=5)
|
|||
|
|
self.atr_long = SimpleATRState(period=20)
|
|||
|
|
|
|||
|
|
# Current adaptive Supertrend
|
|||
|
|
self.current_supertrend = SupertrendState(base_period, base_multiplier)
|
|||
|
|
|
|||
|
|
# Adaptation parameters
|
|||
|
|
self.min_multiplier = 1.0
|
|||
|
|
self.max_multiplier = 4.0
|
|||
|
|
|
|||
|
|
def update_ohlc(self, high: float, low: float, close: float):
|
|||
|
|
# Update volatility measurements
|
|||
|
|
self.atr_short.update_ohlc(high, low, close)
|
|||
|
|
self.atr_long.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
# Calculate adaptive multiplier
|
|||
|
|
if self.atr_long.is_ready() and self.atr_short.is_ready():
|
|||
|
|
volatility_ratio = self.atr_short.get_value() / self.atr_long.get_value()
|
|||
|
|
|
|||
|
|
# Adjust multiplier based on volatility
|
|||
|
|
adaptive_multiplier = self.base_multiplier * volatility_ratio
|
|||
|
|
adaptive_multiplier = max(self.min_multiplier, min(self.max_multiplier, adaptive_multiplier))
|
|||
|
|
|
|||
|
|
# Update Supertrend if multiplier changed significantly
|
|||
|
|
if abs(adaptive_multiplier - self.current_supertrend.multiplier) > 0.1:
|
|||
|
|
self.current_supertrend = SupertrendState(self.base_period, adaptive_multiplier)
|
|||
|
|
|
|||
|
|
# Update current Supertrend
|
|||
|
|
self.current_supertrend.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
def get_value(self) -> float:
|
|||
|
|
return self.current_supertrend.get_value()
|
|||
|
|
|
|||
|
|
def get_trend(self) -> int:
|
|||
|
|
return self.current_supertrend.get_trend()
|
|||
|
|
|
|||
|
|
def is_ready(self) -> bool:
|
|||
|
|
return self.current_supertrend.is_ready()
|
|||
|
|
|
|||
|
|
def get_current_multiplier(self) -> float:
|
|||
|
|
return self.current_supertrend.multiplier
|
|||
|
|
|
|||
|
|
# Usage
|
|||
|
|
adaptive_st = AdaptiveSupertrend(base_period=14, base_multiplier=2.0)
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
adaptive_st.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
if adaptive_st.is_ready():
|
|||
|
|
trend = "BULLISH" if adaptive_st.get_trend() == 1 else "BEARISH"
|
|||
|
|
multiplier = adaptive_st.get_current_multiplier()
|
|||
|
|
print(f"Adaptive Supertrend: {adaptive_st.get_value():.2f}, "
|
|||
|
|
f"Trend: {trend}, Multiplier: {multiplier:.2f}")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Supertrend with Stop Loss Management
|
|||
|
|
```python
|
|||
|
|
class SupertrendStopLoss:
|
|||
|
|
def __init__(self, period: int = 14, multiplier: float = 2.0, buffer_percent: float = 0.5):
|
|||
|
|
self.supertrend = SupertrendState(period, multiplier)
|
|||
|
|
self.buffer_percent = buffer_percent / 100.0
|
|||
|
|
|
|||
|
|
self.current_position = None # "LONG", "SHORT", or None
|
|||
|
|
self.entry_price = 0.0
|
|||
|
|
self.stop_loss = 0.0
|
|||
|
|
|
|||
|
|
def update(self, high: float, low: float, close: float):
|
|||
|
|
previous_trend = self.supertrend.get_trend() if self.supertrend.is_ready() else None
|
|||
|
|
self.supertrend.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
if not self.supertrend.is_ready():
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
current_trend = self.supertrend.get_trend()
|
|||
|
|
supertrend_value = self.supertrend.get_value()
|
|||
|
|
|
|||
|
|
# Check for trend change (entry signal)
|
|||
|
|
if previous_trend is not None and previous_trend != current_trend:
|
|||
|
|
if current_trend == 1: # Bullish trend
|
|||
|
|
self.enter_long(close, supertrend_value)
|
|||
|
|
else: # Bearish trend
|
|||
|
|
self.enter_short(close, supertrend_value)
|
|||
|
|
|
|||
|
|
# Update stop loss for existing position
|
|||
|
|
if self.current_position:
|
|||
|
|
self.update_stop_loss(supertrend_value)
|
|||
|
|
|
|||
|
|
def enter_long(self, price: float, supertrend_value: float):
|
|||
|
|
self.current_position = "LONG"
|
|||
|
|
self.entry_price = price
|
|||
|
|
self.stop_loss = supertrend_value * (1 - self.buffer_percent)
|
|||
|
|
print(f"LONG entry at {price:.2f}, Stop: {self.stop_loss:.2f}")
|
|||
|
|
|
|||
|
|
def enter_short(self, price: float, supertrend_value: float):
|
|||
|
|
self.current_position = "SHORT"
|
|||
|
|
self.entry_price = price
|
|||
|
|
self.stop_loss = supertrend_value * (1 + self.buffer_percent)
|
|||
|
|
print(f"SHORT entry at {price:.2f}, Stop: {self.stop_loss:.2f}")
|
|||
|
|
|
|||
|
|
def update_stop_loss(self, supertrend_value: float):
|
|||
|
|
if self.current_position == "LONG":
|
|||
|
|
new_stop = supertrend_value * (1 - self.buffer_percent)
|
|||
|
|
if new_stop > self.stop_loss: # Only move stop up
|
|||
|
|
self.stop_loss = new_stop
|
|||
|
|
elif self.current_position == "SHORT":
|
|||
|
|
new_stop = supertrend_value * (1 + self.buffer_percent)
|
|||
|
|
if new_stop < self.stop_loss: # Only move stop down
|
|||
|
|
self.stop_loss = new_stop
|
|||
|
|
|
|||
|
|
def check_stop_loss(self, current_price: float) -> bool:
|
|||
|
|
"""Check if stop loss is hit."""
|
|||
|
|
if not self.current_position:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
if self.current_position == "LONG" and current_price <= self.stop_loss:
|
|||
|
|
print(f"LONG stop loss hit at {current_price:.2f}")
|
|||
|
|
self.current_position = None
|
|||
|
|
return True
|
|||
|
|
elif self.current_position == "SHORT" and current_price >= self.stop_loss:
|
|||
|
|
print(f"SHORT stop loss hit at {current_price:.2f}")
|
|||
|
|
self.current_position = None
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# Usage
|
|||
|
|
st_stop_loss = SupertrendStopLoss(period=14, multiplier=2.0, buffer_percent=0.5)
|
|||
|
|
|
|||
|
|
for high, low, close in ohlc_data:
|
|||
|
|
st_stop_loss.update(high, low, close)
|
|||
|
|
|
|||
|
|
# Check stop loss on each update
|
|||
|
|
if st_stop_loss.check_stop_loss(close):
|
|||
|
|
print("Position closed due to stop loss")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Integration with Strategies
|
|||
|
|
|
|||
|
|
### Supertrend Strategy Example
|
|||
|
|
```python
|
|||
|
|
class SupertrendStrategy(IncStrategyBase):
|
|||
|
|
def __init__(self, name: str, params: dict = None):
|
|||
|
|
super().__init__(name, params)
|
|||
|
|
|
|||
|
|
# Initialize Supertrend collection
|
|||
|
|
configs = self.params.get('supertrend_configs', [(10, 3.0), (14, 2.5), (21, 2.0)])
|
|||
|
|
self.supertrend_collection = SupertrendCollection(configs)
|
|||
|
|
|
|||
|
|
# Strategy parameters
|
|||
|
|
self.min_strength = self.params.get('min_strength', 0.75)
|
|||
|
|
self.previous_consensus = None
|
|||
|
|
|
|||
|
|
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
|
|||
|
|
open_price, high, low, close, volume = ohlcv
|
|||
|
|
|
|||
|
|
# Update Supertrend collection
|
|||
|
|
self.supertrend_collection.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
# Wait for indicators to be ready
|
|||
|
|
if not self.supertrend_collection.is_ready():
|
|||
|
|
return IncStrategySignal.HOLD()
|
|||
|
|
|
|||
|
|
# Get consensus and strength
|
|||
|
|
current_consensus = self.supertrend_collection.get_consensus_trend()
|
|||
|
|
strength = self.supertrend_collection.get_trend_strength()
|
|||
|
|
|
|||
|
|
# Check for strong consensus change
|
|||
|
|
if (self.previous_consensus is not None and
|
|||
|
|
self.previous_consensus != current_consensus and
|
|||
|
|
strength >= self.min_strength):
|
|||
|
|
|
|||
|
|
if current_consensus == 1:
|
|||
|
|
# Strong bullish consensus
|
|||
|
|
return IncStrategySignal.BUY(
|
|||
|
|
confidence=strength,
|
|||
|
|
metadata={
|
|||
|
|
'consensus': current_consensus,
|
|||
|
|
'strength': strength,
|
|||
|
|
'avg_supertrend': self.supertrend_collection.get_average_supertrend()
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
elif current_consensus == -1:
|
|||
|
|
# Strong bearish consensus
|
|||
|
|
return IncStrategySignal.SELL(
|
|||
|
|
confidence=strength,
|
|||
|
|
metadata={
|
|||
|
|
'consensus': current_consensus,
|
|||
|
|
'strength': strength,
|
|||
|
|
'avg_supertrend': self.supertrend_collection.get_average_supertrend()
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
self.previous_consensus = current_consensus
|
|||
|
|
return IncStrategySignal.HOLD()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Performance Optimization Tips
|
|||
|
|
|
|||
|
|
### 1. Choose Appropriate Configurations
|
|||
|
|
```python
|
|||
|
|
# For fast signals (more noise)
|
|||
|
|
fast_configs = [(7, 3.0), (10, 2.5)]
|
|||
|
|
|
|||
|
|
# For balanced signals
|
|||
|
|
balanced_configs = [(10, 3.0), (14, 2.5), (21, 2.0)]
|
|||
|
|
|
|||
|
|
# For slow, reliable signals
|
|||
|
|
slow_configs = [(14, 2.0), (21, 1.5), (28, 1.0)]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Optimize Memory Usage
|
|||
|
|
```python
|
|||
|
|
# Use SimpleATRState for memory efficiency
|
|||
|
|
class MemoryEfficientSupertrend(SupertrendState):
|
|||
|
|
def __init__(self, period: int, multiplier: float):
|
|||
|
|
super().__init__(period, multiplier)
|
|||
|
|
# Replace ATRState with SimpleATRState
|
|||
|
|
self.atr = SimpleATRState(period)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Batch Processing
|
|||
|
|
```python
|
|||
|
|
def update_multiple_supertrends(supertrends: list, high: float, low: float, close: float):
|
|||
|
|
"""Efficiently update multiple Supertrend indicators."""
|
|||
|
|
for st in supertrends:
|
|||
|
|
st.update_ohlc(high, low, close)
|
|||
|
|
|
|||
|
|
return [(st.get_value(), st.get_trend()) for st in supertrends if st.is_ready()]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*Supertrend indicators provide clear trend direction and dynamic support/resistance levels. Use single Supertrend for simple trend following or SupertrendCollection for robust meta-trend analysis.*
|