Files
2026-04-11 17:23:26 +02:00

75 lines
2.5 KiB
Python

class CategoricalStrategy:
def __init__(self, lookback=20, range_threshold=0.4, atr_multiplier=0.5):
self.lookback = lookback
self.range_threshold = range_threshold
self.atr_multiplier = atr_multiplier
def get_atr1(self, candle):
return candle.high - candle.low
def classify(self, history):
if len(history) < self.lookback:
return None
window = history[-self.lookback:]
highest = max(c.high for c in window)
lowest = min(c.low for c in window)
full_range = highest - lowest
# Check how much of the range was used early vs late
first_half = window[:len(window) // 2]
second_half = window[len(window) // 2:]
first_high = max(c.high for c in first_half)
first_low = min(c.low for c in first_half)
second_high = max(c.high for c in second_half)
second_low = min(c.low for c in second_half)
# If second half is expanding beyond first half range, it's direction
expansion = 0
if second_high > first_high:
expansion += second_high - first_high
if second_low < first_low:
expansion += first_low - second_low
avg_candle = sum(self.get_atr1(c) for c in window) / len(window)
if expansion > avg_candle * self.range_threshold:
return "direction"
return "consolidation"
def check_signal(self, history):
if len(history) < self.lookback + 1:
return None
category = self.classify(history)
if category is None:
return None
window = history[-self.lookback:]
highest = max(c.high for c in window)
lowest = min(c.low for c in window)
mid = (highest + lowest) / 2
candle = history[-1]
prev = history[-2]
atr = self.get_atr1(candle)
bracket = atr * self.atr_multiplier
if category == "consolidation":
# Near top of range and candle turning down: sell
if candle.close > mid and candle.close < prev.close:
return "SELL"
# Near bottom of range and candle turning up: buy
if candle.close < mid and candle.close > prev.close:
return "BUY"
elif category == "direction":
# Price pushing up: follow
if candle.close > prev.close and candle.close > mid:
return "BUY"
# Price pushing down: follow
if candle.close < prev.close and candle.close < mid:
return "SELL"
return None