18 KiB
18 KiB
MetaTrend Strategy Documentation
Overview
The IncMetaTrendStrategy implements a sophisticated trend-following strategy using multiple Supertrend indicators to determine market direction. It generates entry/exit signals based on meta-trend changes, providing robust trend detection with reduced false signals.
Class: IncMetaTrendStrategy
Purpose
- Trend Detection: Uses 3 Supertrend indicators to identify strong trends
- Meta-trend Analysis: Combines multiple timeframes for robust signal generation
- Real-time Processing: Processes minute-level data with configurable timeframe aggregation
Key Features
- Multi-Supertrend Analysis: 3 Supertrend indicators with different parameters
- Meta-trend Logic: Signals only when all indicators agree
- High Accuracy: 98.5% accuracy vs corrected original implementation
- Fast Processing: <1ms updates, sub-millisecond signal generation
Strategy Logic
Supertrend Configuration
supertrend_configs = [
(12, 3.0), # period=12, multiplier=3.0 (Conservative)
(10, 1.0), # period=10, multiplier=1.0 (Sensitive)
(11, 2.0) # period=11, multiplier=2.0 (Balanced)
]
Meta-trend Calculation
- Meta-trend = 1: All 3 Supertrends indicate uptrend (BUY condition)
- Meta-trend = -1: All 3 Supertrends indicate downtrend (SELL condition)
- Meta-trend = 0: Supertrends disagree (NEUTRAL - no action)
Signal Generation
- Entry Signal: Meta-trend changes from != 1 to == 1
- Exit Signal: Meta-trend changes from != -1 to == -1
Configuration Parameters
params = {
"timeframe": "15min", # Primary analysis timeframe
"enable_logging": False, # Enable detailed logging
"buffer_size_multiplier": 2.0 # Memory management multiplier
}
Real-time Usage Example
Basic Implementation
from cycles.IncStrategies.metatrend_strategy import IncMetaTrendStrategy
import pandas as pd
from datetime import datetime, timedelta
import random
# Initialize MetaTrend strategy
strategy = IncMetaTrendStrategy(
name="metatrend",
weight=1.0,
params={
"timeframe": "15min", # 15-minute analysis
"enable_logging": True # Enable detailed logging
}
)
# Simulate real-time minute data stream
def simulate_market_data():
"""Generate realistic market data with trends"""
base_price = 50000.0 # Starting price (e.g., BTC)
timestamp = datetime.now()
trend_direction = 1 # 1 for up, -1 for down
trend_strength = 0.001 # Trend strength
while True:
# Add trend and noise
trend_move = trend_direction * trend_strength * base_price
noise = (random.random() - 0.5) * 0.002 * base_price # ±0.2% noise
price_change = trend_move + noise
close = base_price + price_change
high = close + random.random() * 0.001 * base_price
low = close - random.random() * 0.001 * base_price
open_price = base_price
volume = random.randint(100, 1000)
# Occasionally change trend direction
if random.random() < 0.01: # 1% chance per minute
trend_direction *= -1
print(f"📈 Trend direction changed to {'UP' if trend_direction > 0 else 'DOWN'}")
yield {
'timestamp': timestamp,
'open': open_price,
'high': high,
'low': low,
'close': close,
'volume': volume
}
base_price = close
timestamp += timedelta(minutes=1)
# Process real-time data
print("🚀 Starting MetaTrend Strategy Real-time Processing...")
print("📊 Waiting for 15-minute bars to form...")
for minute_data in simulate_market_data():
# Strategy handles minute-to-15min aggregation automatically
result = strategy.update_minute_data(
timestamp=pd.Timestamp(minute_data['timestamp']),
ohlcv_data=minute_data
)
# Check if a complete 15-minute bar was formed
if result is not None:
current_price = minute_data['close']
timestamp = minute_data['timestamp']
print(f"\n⏰ Complete 15min bar at {timestamp}")
print(f"💰 Price: ${current_price:,.2f}")
# Get current meta-trend state
meta_trend = strategy.get_current_meta_trend()
individual_trends = strategy.get_individual_supertrend_states()
print(f"📈 Meta-trend: {meta_trend}")
print(f"🔍 Individual Supertrends: {[s['trend'] for s in individual_trends]}")
# Check for signals only if strategy is warmed up
if strategy.is_warmed_up:
entry_signal = strategy.get_entry_signal()
exit_signal = strategy.get_exit_signal()
# Process entry signals
if entry_signal.signal_type == "ENTRY":
print(f"🟢 ENTRY SIGNAL GENERATED!")
print(f" 💪 Confidence: {entry_signal.confidence:.2f}")
print(f" 💵 Price: ${entry_signal.price:,.2f}")
print(f" 📊 Meta-trend: {entry_signal.metadata.get('meta_trend')}")
print(f" 🎯 All Supertrends aligned for UPTREND")
# execute_buy_order(entry_signal)
# Process exit signals
if exit_signal.signal_type == "EXIT":
print(f"🔴 EXIT SIGNAL GENERATED!")
print(f" 💪 Confidence: {exit_signal.confidence:.2f}")
print(f" 💵 Price: ${exit_signal.price:,.2f}")
print(f" 📊 Meta-trend: {exit_signal.metadata.get('meta_trend')}")
print(f" 🎯 All Supertrends aligned for DOWNTREND")
# execute_sell_order(exit_signal)
else:
warmup_progress = len(strategy._meta_trend_history)
min_required = max(strategy.get_minimum_buffer_size().values())
print(f"🔄 Warming up... ({warmup_progress}/{min_required} bars)")
Advanced Trading System Integration
class MetaTrendTradingSystem:
def __init__(self, initial_capital=10000):
self.strategy = IncMetaTrendStrategy(
name="metatrend_live",
weight=1.0,
params={
"timeframe": "15min",
"enable_logging": False # Disable for production
}
)
self.capital = initial_capital
self.position = None
self.trades = []
self.equity_curve = []
def process_market_data(self, timestamp, ohlcv_data):
"""Process incoming market data and manage positions"""
# Update strategy
result = self.strategy.update_minute_data(timestamp, ohlcv_data)
if result is not None and self.strategy.is_warmed_up:
self._check_signals(timestamp, ohlcv_data['close'])
self._update_equity(timestamp, ohlcv_data['close'])
def _check_signals(self, timestamp, current_price):
"""Check for trading signals and execute trades"""
entry_signal = self.strategy.get_entry_signal()
exit_signal = self.strategy.get_exit_signal()
# Handle entry signals
if entry_signal.signal_type == "ENTRY" and self.position is None:
self._execute_entry(timestamp, entry_signal)
# Handle exit signals
if exit_signal.signal_type == "EXIT" and self.position is not None:
self._execute_exit(timestamp, exit_signal)
def _execute_entry(self, timestamp, signal):
"""Execute entry trade"""
# Calculate position size (risk 2% of capital)
risk_amount = self.capital * 0.02
# Simple position sizing - could be more sophisticated
shares = risk_amount / signal.price
self.position = {
'entry_time': timestamp,
'entry_price': signal.price,
'shares': shares,
'confidence': signal.confidence,
'meta_trend': signal.metadata.get('meta_trend'),
'individual_trends': signal.metadata.get('individual_trends', [])
}
print(f"🟢 LONG POSITION OPENED")
print(f" 📅 Time: {timestamp}")
print(f" 💵 Price: ${signal.price:,.2f}")
print(f" 📊 Shares: {shares:.4f}")
print(f" 💪 Confidence: {signal.confidence:.2f}")
print(f" 📈 Meta-trend: {self.position['meta_trend']}")
def _execute_exit(self, timestamp, signal):
"""Execute exit trade"""
if self.position:
# Calculate P&L
pnl = (signal.price - self.position['entry_price']) * self.position['shares']
pnl_percent = (pnl / (self.position['entry_price'] * self.position['shares'])) * 100
# Update capital
self.capital += pnl
# Record trade
trade = {
'entry_time': self.position['entry_time'],
'exit_time': timestamp,
'entry_price': self.position['entry_price'],
'exit_price': signal.price,
'shares': self.position['shares'],
'pnl': pnl,
'pnl_percent': pnl_percent,
'duration': timestamp - self.position['entry_time'],
'entry_confidence': self.position['confidence'],
'exit_confidence': signal.confidence
}
self.trades.append(trade)
print(f"🔴 LONG POSITION CLOSED")
print(f" 📅 Time: {timestamp}")
print(f" 💵 Exit Price: ${signal.price:,.2f}")
print(f" 💰 P&L: ${pnl:,.2f} ({pnl_percent:+.2f}%)")
print(f" ⏱️ Duration: {trade['duration']}")
print(f" 💼 New Capital: ${self.capital:,.2f}")
self.position = None
def _update_equity(self, timestamp, current_price):
"""Update equity curve"""
if self.position:
unrealized_pnl = (current_price - self.position['entry_price']) * self.position['shares']
current_equity = self.capital + unrealized_pnl
else:
current_equity = self.capital
self.equity_curve.append({
'timestamp': timestamp,
'equity': current_equity,
'position': self.position is not None
})
def get_performance_summary(self):
"""Get trading performance summary"""
if not self.trades:
return {"message": "No completed trades yet"}
trades_df = pd.DataFrame(self.trades)
total_trades = len(trades_df)
winning_trades = len(trades_df[trades_df['pnl'] > 0])
losing_trades = len(trades_df[trades_df['pnl'] < 0])
win_rate = (winning_trades / total_trades) * 100
total_pnl = trades_df['pnl'].sum()
avg_win = trades_df[trades_df['pnl'] > 0]['pnl'].mean() if winning_trades > 0 else 0
avg_loss = trades_df[trades_df['pnl'] < 0]['pnl'].mean() if losing_trades > 0 else 0
return {
'total_trades': total_trades,
'winning_trades': winning_trades,
'losing_trades': losing_trades,
'win_rate': win_rate,
'total_pnl': total_pnl,
'avg_win': avg_win,
'avg_loss': avg_loss,
'profit_factor': abs(avg_win / avg_loss) if avg_loss != 0 else float('inf'),
'final_capital': self.capital
}
# Usage Example
trading_system = MetaTrendTradingSystem(initial_capital=10000)
print("🚀 MetaTrend Trading System Started")
print("💰 Initial Capital: $10,000")
# Simulate live trading
for market_data in simulate_market_data():
trading_system.process_market_data(
timestamp=pd.Timestamp(market_data['timestamp']),
ohlcv_data=market_data
)
# Print performance summary every 100 bars
if len(trading_system.equity_curve) % 100 == 0 and trading_system.trades:
performance = trading_system.get_performance_summary()
print(f"\n📊 Performance Summary (after {len(trading_system.equity_curve)} bars):")
print(f" 💼 Capital: ${performance['final_capital']:,.2f}")
print(f" 📈 Total Trades: {performance['total_trades']}")
print(f" 🎯 Win Rate: {performance['win_rate']:.1f}%")
print(f" 💰 Total P&L: ${performance['total_pnl']:,.2f}")
Backtesting Example
def backtest_metatrend_strategy(historical_data, timeframe="15min"):
"""Comprehensive backtesting of MetaTrend strategy"""
strategy = IncMetaTrendStrategy(
name="metatrend_backtest",
weight=1.0,
params={
"timeframe": timeframe,
"enable_logging": False
}
)
signals = []
trades = []
current_position = None
print(f"🔄 Backtesting MetaTrend Strategy on {timeframe} timeframe...")
print(f"📊 Data period: {historical_data.index[0]} to {historical_data.index[-1]}")
# Process historical data
for timestamp, row in historical_data.iterrows():
ohlcv_data = {
'open': row['open'],
'high': row['high'],
'low': row['low'],
'close': row['close'],
'volume': row['volume']
}
# Update strategy
result = strategy.update_minute_data(timestamp, ohlcv_data)
if result is not None and strategy.is_warmed_up:
entry_signal = strategy.get_entry_signal()
exit_signal = strategy.get_exit_signal()
# Record entry signals
if entry_signal.signal_type == "ENTRY":
signals.append({
'timestamp': timestamp,
'type': 'ENTRY',
'price': entry_signal.price,
'confidence': entry_signal.confidence,
'meta_trend': entry_signal.metadata.get('meta_trend')
})
# Open position if none exists
if current_position is None:
current_position = {
'entry_time': timestamp,
'entry_price': entry_signal.price,
'confidence': entry_signal.confidence
}
# Record exit signals
if exit_signal.signal_type == "EXIT":
signals.append({
'timestamp': timestamp,
'type': 'EXIT',
'price': exit_signal.price,
'confidence': exit_signal.confidence,
'meta_trend': exit_signal.metadata.get('meta_trend')
})
# Close position if exists
if current_position is not None:
pnl = exit_signal.price - current_position['entry_price']
pnl_percent = (pnl / current_position['entry_price']) * 100
trades.append({
'entry_time': current_position['entry_time'],
'exit_time': timestamp,
'entry_price': current_position['entry_price'],
'exit_price': exit_signal.price,
'pnl': pnl,
'pnl_percent': pnl_percent,
'duration': timestamp - current_position['entry_time'],
'entry_confidence': current_position['confidence'],
'exit_confidence': exit_signal.confidence
})
current_position = None
# Convert to DataFrames for analysis
signals_df = pd.DataFrame(signals)
trades_df = pd.DataFrame(trades)
# Calculate performance metrics
if len(trades_df) > 0:
total_trades = len(trades_df)
winning_trades = len(trades_df[trades_df['pnl'] > 0])
win_rate = (winning_trades / total_trades) * 100
total_return = trades_df['pnl_percent'].sum()
avg_return = trades_df['pnl_percent'].mean()
max_win = trades_df['pnl_percent'].max()
max_loss = trades_df['pnl_percent'].min()
print(f"\n📊 Backtest Results:")
print(f" 📈 Total Signals: {len(signals_df)}")
print(f" 💼 Total Trades: {total_trades}")
print(f" 🎯 Win Rate: {win_rate:.1f}%")
print(f" 💰 Total Return: {total_return:.2f}%")
print(f" 📊 Average Return: {avg_return:.2f}%")
print(f" 🚀 Max Win: {max_win:.2f}%")
print(f" 📉 Max Loss: {max_loss:.2f}%")
return signals_df, trades_df
else:
print("❌ No completed trades in backtest period")
return signals_df, pd.DataFrame()
# Run backtest (example)
# historical_data = pd.read_csv('btc_1min_data.csv', index_col='timestamp', parse_dates=True)
# signals, trades = backtest_metatrend_strategy(historical_data, timeframe="15min")
Performance Characteristics
Timing Benchmarks
- Update Time: <1ms per 15-minute bar
- Signal Generation: <0.5ms per signal
- Memory Usage: ~5MB constant
- Accuracy: 98.5% vs original implementation
Troubleshooting
Common Issues
- No Signals: Check if strategy is warmed up (needs ~50+ bars)
- Conflicting Trends: Normal behavior - wait for alignment
- Late Signals: Meta-trend prioritizes accuracy over speed
- Memory Usage: Monitor buffer sizes in long-running systems
Debug Information
# Get detailed strategy state
state = strategy.get_current_state_summary()
print(f"Strategy State: {state}")
# Get meta-trend history
history = strategy.get_meta_trend_history(limit=10)
for entry in history:
print(f"{entry['timestamp']}: Meta-trend={entry['meta_trend']}, Trends={entry['individual_trends']}")