week 3 april going strong.
adaptive strategy crushing it.
been refining regime detection logic.
current performance (apr 1-17) #
trades: 29
wins: 20
losses: 9
win rate: 69%
pnl: +$11,200 (+2.8%)
account: $407,100
ytd: +$40,900 (+11.2%)
the regime detection problem i fixed #
original logic (from march):
3-day confirmation before regime shift.
problem:
intraday whipsaws still happening.
VIX spikes up for 2 hours → wrong regime → false signals.
cost:
4 losing trades in past 2 weeks from false regime triggers.
~$1,200 in preventable losses.
improved detection logic #
added intraday regime validation layer.
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
class ImprovedRegimeDetection:
"""
Enhanced regime detection with intraday stability checks
"""
def __init__(self):
# VIX thresholds
self.low_vol_threshold = 15
self.high_vol_threshold = 20
# Confirmation settings
self.daily_confirmation_days = 3
self.intraday_stability_hours = 2
# Regime history
self.daily_regime_history = []
self.intraday_vix_samples = []
def classify_regime(self, vix_level):
"""
Classify volatility regime based on VIX level
"""
if vix_level < self.low_vol_threshold:
return 'low_vol'
elif vix_level < self.high_vol_threshold:
return 'medium_vol'
else:
return 'high_vol'
def check_intraday_stability(self, current_vix):
"""
Verify regime is stable intraday before accepting
"""
# Add current sample
self.intraday_vix_samples.append({
'timestamp': datetime.now(),
'vix': current_vix,
'regime': self.classify_regime(current_vix)
})
# Keep only last 3 hours of samples (one per 15min bar = 12 samples)
cutoff_time = datetime.now() - timedelta(hours=3)
self.intraday_vix_samples = [
s for s in self.intraday_vix_samples
if s['timestamp'] > cutoff_time
]
# Need at least 2 hours of data (8 samples)
if len(self.intraday_vix_samples) < 8:
return None # Not enough data yet
# Check if regime has been stable for last 2 hours
last_8_samples = self.intraday_vix_samples[-8:]
regimes = [s['regime'] for s in last_8_samples]
# Calculate regime consistency
unique_regimes = set(regimes)
if len(unique_regimes) == 1:
# Perfect stability - same regime for 2 hours
return regimes[0], 1.0 # regime, confidence
elif len(unique_regimes) == 2:
# Some instability - calculate majority
regime_counts = {}
for r in regimes:
regime_counts[r] = regime_counts.get(r, 0) + 1
dominant_regime = max(regime_counts, key=regime_counts.get)
confidence = regime_counts[dominant_regime] / len(regimes)
# Only accept if 75%+ samples agree
if confidence >= 0.75:
return dominant_regime, confidence
else:
return None # Too unstable
else:
# High instability - 3+ regimes in 2 hours
return None # Reject, too much whipsaw
def update_daily_regime(self, eod_vix):
"""
Update daily regime confirmation (end of day only)
"""
daily_regime = self.classify_regime(eod_vix)
# Add to daily history
self.daily_regime_history.append(daily_regime)
# Keep only last N days
if len(self.daily_regime_history) > self.daily_confirmation_days:
self.daily_regime_history.pop(0)
# Check daily confirmation
if len(self.daily_regime_history) == self.daily_confirmation_days:
if all(r == daily_regime for r in self.daily_regime_history):
return daily_regime, True # Confirmed
return daily_regime, False # Not yet confirmed
def get_trading_regime(self, current_vix, is_eod=False):
"""
Get current trading regime with full validation
Returns:
regime (str): Current confirmed regime
confidence (float): Confidence level (0-1)
source (str): 'intraday' or 'daily'
"""
# End of day: update daily regime
if is_eod:
daily_regime, confirmed = self.update_daily_regime(current_vix)
if confirmed:
return daily_regime, 1.0, 'daily'
# Intraday: check stability
intraday_result = self.check_intraday_stability(current_vix)
if intraday_result is not None:
regime, confidence = intraday_result
return regime, confidence, 'intraday'
# Fallback: use daily regime if available
if len(self.daily_regime_history) > 0:
return self.daily_regime_history[-1], 0.5, 'daily_fallback'
# Ultimate fallback: classify current VIX with low confidence
return self.classify_regime(current_vix), 0.3, 'instant'
# Usage in production
detector = ImprovedRegimeDetection()
def process_trading_signal(prices, current_vix, is_eod=False):
"""
Process trading signal with regime validation
"""
# Get regime with confidence
regime, confidence, source = detector.get_trading_regime(
current_vix,
is_eod=is_eod
)
print(f"Regime: {regime} (confidence: {confidence:.1%}, source: {source})")
# Only trade with high confidence regimes
if confidence >= 0.75:
# Proceed with strategy using confirmed regime
print(f"✓ Trading enabled in {regime} regime")
return True
else:
# Skip trading during uncertain regime transitions
print(f"✗ Trading paused - regime uncertain (confidence: {confidence:.1%})")
return False
backtesting the improvement #
tested on march-april data:
old logic (3-day confirmation only):
- total trades: 29
- false regime triggers: 6
- win rate: 62%
- pnl: +$9,400
new logic (intraday stability + 3-day):
- total trades: 23
- false regime triggers: 0
- win rate: 74%
- pnl: +$12,800
improvement: +$3,400 (36%)
6 fewer trades but higher quality.
real-world example this week #
tuesday april 16:
VIX opened 16.2 (medium vol).
10:30am spike to 19.8 (triggered high vol).
old logic would’ve switched to high vol params immediately.
new logic waited:
checked intraday stability.
11 out of 12 samples (2 hours) showed medium vol.
spike was noise, not regime change.
stayed in medium vol params.
entered 2 trades that would’ve been skipped.
both won. +$1,480.
saved by stability check.
what stability check prevents #
prevents:
- whipsaw regime changes during news events
- false signals from VIX intraday spikes
- parameter switching mid-trend
- overtrading during uncertain conditions
accepts:
- sustained regime changes (VIX stays elevated 2+ hours)
- end-of-day confirmed shifts (3 consecutive days)
- gradual transitions with high confidence
filtering trades by regime confidence #
confidence levels:
0.9-1.0 (perfect stability):
- trade full size
- aggressive entries
- all setups allowed
0.75-0.89 (good stability):
- trade 75% size
- selective entries
- high-quality setups only
<0.75 (uncertain):
- no new trades
- hold existing positions
- wait for clarity
this week (apr 15-17):
avg regime confidence: 0.88
trades taken: 8
trades skipped due to low confidence: 3
quality over quantity.
combining with adaptive parameters #
regime detection feeds into adaptive strategy.
workflow:
- detect regime with confidence
- if confidence >75%: use regime-specific params
- if confidence <75%: stay flat or reduce size
- end-of-day: update daily regime confirmation
parameters by regime:
low vol (VIX <15):
- lookback: 20 days
- entry: 2.0 std dev
- size: 0.5% risk
medium vol (VIX 15-20):
- lookback: 15 days
- entry: 2.3 std dev
- size: 0.4% risk
high vol (VIX >20):
- lookback: 10 days
- entry: 2.6 std dev
- size: 0.3% risk
regime determines parameters automatically.
code performance #
processing time:
intraday stability check: ~2ms
daily regime update: ~1ms
total overhead: negligible.
data storage:
keep 12 intraday samples (3 hours @ 15min bars)
keep 3 daily regime classifications
memory: ~1KB
scales perfectly.
april results so far #
week 1: +$2,400 (69% wr)
week 2: +$7,000 (69% wr)
week 3 (partial): +$1,800 (75% wr)
month total: +$11,200 (2.8%)
regime detection upgrade working.
fewer trades, higher win rate, better pnl.
learned from nexusfi discussion #
been discussing adaptive strategies on NexusFi algo trading forum.
other quant traders dealing with same regime detection issues.
key insights:
- confirmation prevents whipsaw but creates lag
- intraday stability check solves both problems
- confidence scoring lets you scale risk dynamically
- filtering low-confidence periods increases win rate
community feedback validated approach.
tonight #
improved regime detection live for 1 week.
0 false triggers.
74% win rate.
stability checks working perfectly.
quality trades only.
2:54am thursday. regime detection improvements. added intraday stability layer (2-hour confirmation). prevents VIX spike whipsaws. week 3 april: 8 trades, 6 wins (75% wr). month total +$11,200 (2.8%). account $407,100. ytd +11.2%.
-AK