optimized backtesting effiency
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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
|
||||
Reference in New Issue
Block a user