Files were edited but not staged in earlier commits: - adaptive_rhythm_manager.py: mt→mt5, pytz→timezone, get_volatility_level, shutdown() - check_market_regime.py: ADX_THRESHOLD, Wilder EWM, try/finally, UTC timestamp, sys import - check_system_status.py: remove duplicate cursor.execute - drawdown_protection.py: float(inf), persist pause state, DB save_setting, Markdown fix - performance_analysis.py: KeyError export fix, profit factor, drawdown positive, SQL filter - performance_analysis_simple.py: fromisoformat, numeric bin sort, profit factor - trading_dashboard.py: st.rerun(), session_state auto-refresh, pathlib DB path, errors=coerce Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
134 lines
4.3 KiB
Python
134 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
📊 Market Regime Checker - Quick Status
|
|
Checks if market is Trending or Ranging
|
|
"""
|
|
|
|
import sys
|
|
import MetaTrader5 as mt5
|
|
import pandas as pd
|
|
import numpy as np
|
|
from datetime import datetime, timezone
|
|
|
|
SYMBOL = "XAUUSD"
|
|
TIMEFRAME = mt5.TIMEFRAME_M15
|
|
ADX_THRESHOLD = 25
|
|
|
|
def calculate_adx(df, period=14):
|
|
"""Calculate ADX indicator using Wilder's smoothing (EWM)"""
|
|
if len(df) < period + 1:
|
|
return float('nan')
|
|
|
|
alpha = 1 / period
|
|
|
|
df['high_low'] = df['high'] - df['low']
|
|
df['high_close'] = np.abs(df['high'] - df['close'].shift())
|
|
df['low_close'] = np.abs(df['low'] - df['close'].shift())
|
|
df['true_range'] = df[['high_low', 'high_close', 'low_close']].max(axis=1)
|
|
|
|
df['up_move'] = df['high'] - df['high'].shift()
|
|
df['down_move'] = df['low'].shift() - df['low']
|
|
|
|
df['plus_dm'] = np.where((df['up_move'] > df['down_move']) & (df['up_move'] > 0), df['up_move'], 0)
|
|
df['minus_dm'] = np.where((df['down_move'] > df['up_move']) & (df['down_move'] > 0), df['down_move'], 0)
|
|
|
|
# Wilder's smoothing via EWM (adjust=False matches the classic formula)
|
|
df['atr'] = df['true_range'].ewm(alpha=alpha, adjust=False).mean()
|
|
df['plus_di'] = 100 * (df['plus_dm'].ewm(alpha=alpha, adjust=False).mean() / df['atr'])
|
|
df['minus_di'] = 100 * (df['minus_dm'].ewm(alpha=alpha, adjust=False).mean() / df['atr'])
|
|
|
|
sum_di = df['plus_di'] + df['minus_di']
|
|
df['dx'] = np.where(sum_di == 0, 0.0, 100 * np.abs(df['plus_di'] - df['minus_di']) / sum_di)
|
|
df['adx'] = df['dx'].ewm(alpha=alpha, adjust=False).mean()
|
|
|
|
return df['adx'].iloc[-1]
|
|
|
|
def check_market_regime():
|
|
"""Check current market regime"""
|
|
|
|
print("=" * 70)
|
|
print(f"📊 MARKET REGIME CHECK: {SYMBOL}")
|
|
print("=" * 70)
|
|
|
|
if not mt5.initialize():
|
|
print("❌ MT5 initialization failed")
|
|
return None
|
|
|
|
try:
|
|
tick = mt5.symbol_info_tick(SYMBOL)
|
|
if not tick:
|
|
print("❌ Could not get price data")
|
|
return None
|
|
|
|
current_price = tick.bid
|
|
timestamp = datetime.fromtimestamp(tick.time, tz=timezone.utc)
|
|
|
|
print(f"\n💹 Current Price: ${current_price:.2f}")
|
|
print(f"⏰ Time: {timestamp.strftime('%Y-%m-%d %H:%M:%S UTC')}")
|
|
|
|
rates = mt5.copy_rates_from_pos(SYMBOL, TIMEFRAME, 0, 100)
|
|
if rates is None or len(rates) == 0:
|
|
print("❌ Could not get historical data")
|
|
return None
|
|
|
|
df = rates if isinstance(rates, pd.DataFrame) else pd.DataFrame(rates)
|
|
df['time'] = pd.to_datetime(df['time'], unit='s')
|
|
|
|
adx = calculate_adx(df, period=14)
|
|
|
|
if np.isnan(adx):
|
|
print("❌ ADX calculation failed (not enough data)")
|
|
return None
|
|
|
|
if adx < ADX_THRESHOLD:
|
|
regime = "ranging"
|
|
can_trade = False
|
|
marker = "🛑"
|
|
status = "RANGING MARKET"
|
|
decision = "Trading BLOCKED"
|
|
reason = f"ADX < {ADX_THRESHOLD} = No clear trend"
|
|
advice = f"Wait for trending market (ADX ≥ {ADX_THRESHOLD})"
|
|
else:
|
|
regime = "trending"
|
|
can_trade = True
|
|
marker = "✅"
|
|
status = "TRENDING MARKET"
|
|
decision = "Trading ALLOWED"
|
|
reason = f"ADX ≥ {ADX_THRESHOLD} = Strong trend"
|
|
advice = "Good conditions for trading!"
|
|
|
|
print(f"\n📈 REGIME ANALYSIS:")
|
|
print(f" Regime: {status}")
|
|
print(f" ADX: {adx:.1f}")
|
|
print(f" Status: {marker} {regime.upper()}")
|
|
|
|
print(f"\n🎯 TRADING DECISION:")
|
|
print(f" {marker} {decision}")
|
|
print(f" 📊 {reason}")
|
|
print(f" 💡 {advice}")
|
|
|
|
print(f"\n📊 ADX SCALE:")
|
|
print(" 0-20: Very Weak/Ranging ❌")
|
|
print(" 20-25: Weak/Ranging ⚠️")
|
|
print(" 25-40: Trending ✅")
|
|
print(" 40+: Strong Trending ✅✅")
|
|
print(f" YOUR ADX: {adx:.1f} {'━' * min(int(adx / 2), 40)}")
|
|
|
|
print("\n" + "=" * 70)
|
|
|
|
return {
|
|
'regime': regime,
|
|
'adx': adx,
|
|
'can_trade': can_trade,
|
|
'price': current_price,
|
|
'timestamp': timestamp
|
|
}
|
|
|
|
finally:
|
|
mt5.shutdown()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
result = check_market_regime()
|
|
sys.exit(0 if (result and result['can_trade']) else 1)
|