Files
quantumbotx/testing/bollinger_squeeze_test.py
T
Reynov Christian a24fa8637b 🚀 REVOLUTIONARY FEATURE: Indonesian AI Trading Mentor System
 CORE AI MENTOR SYSTEM:
  - Complete Indonesian language AI trading mentor
  - Real-time trading psychology analysis with cultural context
  - Emotional intelligence for Indonesian trading behavior
  - Personal feedback with Islamic context ('Alhamdulillah profit!')
  - Jakarta timezone optimization and BI rate awareness

 DATABASE INTEGRATION:
  - New trading_sessions, ai_mentor_reports, daily_trading_data tables
  - Real-time capture of trading data for AI analysis
  - Historical performance tracking and emotional state logging
  - Seamless integration with existing bot architecture

 WEB INTERFACE:
  - Beautiful Indonesian AI mentor dashboard
  - Interactive emotion selection with cultural sensitivity
  - Real-time feedback generation and instant AI consultation
  - Daily report generation with comprehensive analysis
  - Quick feedback modal for emotional check-ins

 TRADING BOT INTEGRATION:
  - Automatic trade logging for AI mentor analysis
  - Risk management scoring (1-10 scale)
  - Strategy performance correlation with emotional states
  - Stop loss and take profit usage tracking

 REVOLUTIONARY FEATURES:
  - First-ever Indonesian AI trading mentor in the world
  - Combines trading psychology with Islamic values
  - Market-specific guidance for Indonesian traders
  - Progressive learning path from beginner to expert
  - Cultural trading wisdom (Jakarta hours, Ramadan considerations)

IMPACT: This transforms QuantumBotX into the world's first culturally-aware
AI trading mentor specifically designed for Indonesian retail traders.

Indonesian beginners now have personal AI guidance in their native language
with full understanding of local market conditions and cultural context.
2025-08-26 09:02:03 +08:00

169 lines
5.8 KiB
Python

# core/strategies/bollinger_squeeze.py
import pandas_ta as ta
def analyze(df):
"""
Bollinger Squeeze Strategy Analysis
Squeeze occurs when:
1. Bollinger Bands width is narrow (low volatility)
2. Price is consolidating
Breakout occurs when:
1. Price breaks above/below Bollinger Bands
2. After a squeeze period
"""
if df is None or len(df) < 21:
return 'HOLD'
try:
# Calculate Bollinger Bands
bb = ta.bbands(df['close'], length=20, std=2)
if bb is None or bb.empty:
return 'HOLD'
# Get latest values
latest = df.iloc[-1]
current_price = latest['close']
# Bollinger Band values
bb_upper = bb['BBU_20_2.0'].iloc[-1]
bb_middle = bb['BBM_20_2.0'].iloc[-1] # SMA
bb_lower = bb['BBL_20_2.0'].iloc[-1]
# Calculate bandwidth (volatility measure)
bandwidth = (bb_upper - bb_lower) / bb_middle * 100
# Get historical bandwidth for comparison
bb_bandwidth = (bb['BBU_20_2.0'] - bb['BBL_20_2.0']) / bb['BBM_20_2.0'] * 100
avg_bandwidth = bb_bandwidth.rolling(window=10).mean().iloc[-1]
# Squeeze Detection
# Squeeze occurs when current bandwidth is significantly lower than average
squeeze_threshold = avg_bandwidth * 0.7 # 30% below average
is_squeezing = bandwidth < squeeze_threshold
# Price position relative to bands
price_position = (current_price - bb_lower) / (bb_upper - bb_lower)
# Momentum indicator (simple)
rsi = ta.rsi(df['close'], length=14).iloc[-1]
# Volume analysis (if available)
volume_surge = False
if 'volume' in df.columns:
avg_volume = df['volume'].rolling(window=10).mean().iloc[-1]
current_volume = df['volume'].iloc[-1]
volume_surge = current_volume > avg_volume * 1.5
# === SIGNAL LOGIC ===
# 1. Breakout from Squeeze (HIGH PRIORITY)
if is_squeezing:
# During squeeze, wait for breakout
if current_price > bb_upper and rsi < 70:
return 'BUY' # Bullish breakout
elif current_price < bb_lower and rsi > 30:
return 'SELL' # Bearish breakout
else:
return 'HOLD' # Still squeezing
# 2. Post-Squeeze Momentum
elif bandwidth > avg_bandwidth * 1.2: # Bands expanding
if price_position > 0.8 and volume_surge: # Near upper band with volume
return 'BUY'
elif price_position < 0.2 and volume_surge: # Near lower band with volume
return 'SELL'
# 3. Mean Reversion (when not squeezing)
else:
if current_price > bb_upper and rsi > 70:
return 'SELL' # Overbought
elif current_price < bb_lower and rsi < 30:
return 'BUY' # Oversold
return 'HOLD'
except Exception as e:
print(f"Bollinger Squeeze Analysis Error: {e}")
return 'HOLD'
def get_analysis_data(df):
"""
Return detailed analysis data for dashboard
"""
if df is None or len(df) < 21:
return {
'signal': 'HOLD',
'explanation': 'Insufficient data for Bollinger analysis',
'indicators': {}
}
try:
bb = ta.bbands(df['close'], length=20, std=2)
if bb is None or bb.empty:
return {
'signal': 'HOLD',
'explanation': 'Unable to calculate Bollinger Bands',
'indicators': {}
}
# Get latest values
latest = df.iloc[-1]
current_price = latest['close']
bb_upper = bb['BBU_20_2.0'].iloc[-1]
bb_middle = bb['BBM_20_2.0'].iloc[-1]
bb_lower = bb['BBL_20_2.0'].iloc[-1]
bandwidth = (bb_upper - bb_lower) / bb_middle * 100
bb_bandwidth = (bb['BBU_20_2.0'] - bb['BBL_20_2.0']) / bb['BBM_20_2.0'] * 100
avg_bandwidth = bb_bandwidth.rolling(window=10).mean().iloc[-1]
is_squeezing = bandwidth < avg_bandwidth * 0.7
price_position = (current_price - bb_lower) / (bb_upper - bb_lower)
signal = analyze(df)
# Generate explanation
explanation = ""
if is_squeezing:
explanation = f"🔄 SQUEEZE detected! Bandwidth: {bandwidth:.2f}% (Avg: {avg_bandwidth:.2f}%). "
if signal == 'BUY':
explanation += "Bullish breakout above upper band!"
elif signal == 'SELL':
explanation += "Bearish breakout below lower band!"
else:
explanation += "Waiting for breakout..."
else:
explanation = f"📊 Normal volatility. Bandwidth: {bandwidth:.2f}%. "
if signal == 'BUY':
explanation += "Bullish momentum or oversold bounce."
elif signal == 'SELL':
explanation += "Bearish momentum or overbought correction."
else:
explanation += "No clear signal."
return {
'signal': signal,
'explanation': explanation,
'indicators': {
'bb_upper': round(bb_upper, 4),
'bb_middle': round(bb_middle, 4),
'bb_lower': round(bb_lower, 4),
'bandwidth': round(bandwidth, 2),
'avg_bandwidth': round(avg_bandwidth, 2),
'is_squeezing': is_squeezing,
'price_position': round(price_position * 100, 1)
}
}
except Exception as e:
return {
'signal': 'HOLD',
'explanation': f'Analysis error: {str(e)}',
'indicators': {}
}