showing trades on realtime chart - chart broken
This commit is contained in:
@ -72,6 +72,9 @@ class CNNPyTorch(nn.Module):
|
||||
"""
|
||||
super(CNNPyTorch, self).__init__()
|
||||
|
||||
# Set device
|
||||
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
|
||||
window_size, num_features = input_shape
|
||||
self.window_size = window_size
|
||||
|
||||
@ -225,74 +228,93 @@ class CNNModelPyTorch:
|
||||
predictions with the CNN model, optimized for short-term trading opportunities.
|
||||
"""
|
||||
|
||||
def __init__(self, window_size, num_features, output_size=3, timeframes=None):
|
||||
def __init__(self, window_size=20, timeframes=None, output_size=3, num_pairs=3):
|
||||
"""
|
||||
Initialize the CNN model.
|
||||
|
||||
Args:
|
||||
window_size (int): Size of the input window
|
||||
num_features (int): Number of features in the input data
|
||||
output_size (int): Size of the output (default: 3 for BUY/HOLD/SELL)
|
||||
timeframes (list): List of timeframes used (for logging)
|
||||
window_size (int): Size of the sliding window
|
||||
timeframes (list): List of timeframes used
|
||||
output_size (int): Number of output classes (3 for BUY/HOLD/SELL)
|
||||
num_pairs (int): Number of trading pairs to analyze in parallel (default 3)
|
||||
"""
|
||||
# Action tracking
|
||||
self.action_counts = {
|
||||
'BUY': 0,
|
||||
'SELL': 0,
|
||||
'HOLD': 0
|
||||
}
|
||||
self.window_size = window_size
|
||||
self.num_features = num_features
|
||||
self.timeframes = timeframes if timeframes else ["1m", "5m", "15m"]
|
||||
self.output_size = output_size
|
||||
self.timeframes = timeframes or []
|
||||
self.num_pairs = num_pairs
|
||||
|
||||
# Determine device (GPU or CPU)
|
||||
self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
||||
logger.info(f"Using device: {self.device}")
|
||||
# Calculate total features (5 OHLCV features per timeframe per pair)
|
||||
self.total_features = len(self.timeframes) * 5 * self.num_pairs
|
||||
|
||||
# Initialize model
|
||||
self.model = None
|
||||
self.build_model()
|
||||
# Build the model
|
||||
logger.info(f"Building PyTorch CNN model with window_size={window_size}, "
|
||||
f"num_features={self.total_features}, output_size={output_size}, "
|
||||
f"num_pairs={num_pairs}")
|
||||
|
||||
# Initialize training history
|
||||
self.history = {
|
||||
'loss': [],
|
||||
'val_loss': [],
|
||||
'accuracy': [],
|
||||
'val_accuracy': []
|
||||
}
|
||||
|
||||
# Sensitivity parameters for high-leverage trading
|
||||
self.confidence_threshold = 0.65 # Minimum confidence for trading actions
|
||||
self.max_consecutive_same_action = 3 # Limit consecutive identical actions
|
||||
self.last_actions = [] # Track recent actions
|
||||
|
||||
def build_model(self):
|
||||
"""Build the CNN model architecture"""
|
||||
logger.info(f"Building PyTorch CNN model with window_size={self.window_size}, "
|
||||
f"num_features={self.num_features}, output_size={self.output_size}")
|
||||
|
||||
# Ensure window size is not less than the actual input
|
||||
input_window_size = max(self.window_size, 20) # Use at least 20 as minimum window size
|
||||
|
||||
self.model = CNNPyTorch(
|
||||
input_shape=(input_window_size, self.num_features),
|
||||
output_size=self.output_size
|
||||
# Calculate channel sizes that are divisible by num_pairs
|
||||
base_channels = 96 # 96 is divisible by 3
|
||||
self.model = nn.Sequential(
|
||||
# First convolutional layer - process each pair's features
|
||||
nn.Sequential(
|
||||
nn.Conv1d(self.total_features, base_channels, kernel_size=5, padding=2, groups=num_pairs),
|
||||
nn.ReLU(),
|
||||
nn.BatchNorm1d(base_channels),
|
||||
nn.Dropout(0.2)
|
||||
),
|
||||
|
||||
# Second convolutional layer - start mixing pair information
|
||||
nn.Sequential(
|
||||
nn.Conv1d(base_channels, base_channels*2, kernel_size=3, padding=1),
|
||||
nn.ReLU(),
|
||||
nn.BatchNorm1d(base_channels*2),
|
||||
nn.Dropout(0.2)
|
||||
),
|
||||
|
||||
# Third convolutional layer - deeper feature extraction
|
||||
nn.Sequential(
|
||||
nn.Conv1d(base_channels*2, base_channels*4, kernel_size=3, padding=1),
|
||||
nn.ReLU(),
|
||||
nn.BatchNorm1d(base_channels*4),
|
||||
nn.Dropout(0.2)
|
||||
),
|
||||
|
||||
# Global average pooling
|
||||
nn.AdaptiveAvgPool1d(1),
|
||||
|
||||
# Flatten
|
||||
nn.Flatten(),
|
||||
|
||||
# Dense layers for action prediction with cross-pair attention
|
||||
nn.Sequential(
|
||||
nn.Linear(base_channels*4, base_channels*2),
|
||||
nn.ReLU(),
|
||||
nn.Dropout(0.2),
|
||||
nn.Linear(base_channels*2, base_channels),
|
||||
nn.ReLU(),
|
||||
nn.Dropout(0.2),
|
||||
nn.Linear(base_channels, output_size * num_pairs) # Output for each pair
|
||||
)
|
||||
).to(self.device)
|
||||
|
||||
# Initialize optimizer with higher learning rate for faster adaptation
|
||||
self.optimizer = optim.Adam(self.model.parameters(), lr=0.002)
|
||||
|
||||
# Learning rate scheduler with faster decay
|
||||
# Initialize optimizer and loss function
|
||||
self.optimizer = optim.Adam(self.model.parameters(), lr=0.0005)
|
||||
self.scheduler = optim.lr_scheduler.ReduceLROnPlateau(
|
||||
self.optimizer, mode='max', factor=0.6, patience=6, verbose=True
|
||||
self.optimizer, mode='max', factor=0.5, patience=5, verbose=True
|
||||
)
|
||||
self.criterion = nn.CrossEntropyLoss()
|
||||
|
||||
# Initialize loss function with higher weights for BUY/SELL
|
||||
class_weights = torch.tensor([7.0, 1.0, 7.0]).to(self.device) # Even higher weights for BUY/SELL
|
||||
self.criterion = nn.CrossEntropyLoss(weight=class_weights)
|
||||
# Initialize metrics tracking
|
||||
self.train_losses = []
|
||||
self.val_losses = []
|
||||
self.train_accuracies = []
|
||||
self.val_accuracies = []
|
||||
|
||||
logger.info(f"Model built successfully with {sum(p.numel() for p in self.model.parameters())} parameters")
|
||||
|
||||
# Sensitivity parameters for high-leverage trading
|
||||
self.confidence_threshold = 0.65
|
||||
self.max_consecutive_same_action = 3
|
||||
self.last_actions = [[] for _ in range(num_pairs)] # Track recent actions per pair
|
||||
|
||||
def compute_trading_loss(self, action_probs, price_pred, targets, future_prices=None):
|
||||
"""
|
||||
@ -644,12 +666,12 @@ class CNNModelPyTorch:
|
||||
action_probs_np[:, 2] *= 1.3 # Boost BUY probabilities
|
||||
|
||||
# Implement signal filtering based on previous actions to avoid oscillation
|
||||
if len(self.last_actions) >= self.max_consecutive_same_action:
|
||||
if len(self.last_actions[0]) >= self.max_consecutive_same_action:
|
||||
# Check for too many consecutive identical actions
|
||||
if all(a == 0 for a in self.last_actions[-self.max_consecutive_same_action:]):
|
||||
if all(a == 0 for a in self.last_actions[0][-self.max_consecutive_same_action:]):
|
||||
# Too many consecutive SELL - reduce sell probability
|
||||
action_probs_np[:, 0] *= 0.7
|
||||
elif all(a == 2 for a in self.last_actions[-self.max_consecutive_same_action:]):
|
||||
elif all(a == 2 for a in self.last_actions[0][-self.max_consecutive_same_action:]):
|
||||
# Too many consecutive BUY - reduce buy probability
|
||||
action_probs_np[:, 2] *= 0.7
|
||||
|
||||
@ -666,9 +688,9 @@ class CNNModelPyTorch:
|
||||
# Store the predicted action for the most recent input
|
||||
if action_probs_np.shape[0] > 0:
|
||||
latest_action = np.argmax(action_probs_np[-1])
|
||||
self.last_actions.append(int(latest_action))
|
||||
self.last_actions[0].append(int(latest_action))
|
||||
# Keep only the most recent actions
|
||||
self.last_actions = self.last_actions[-10:] # Store last 10 actions
|
||||
self.last_actions[0] = self.last_actions[0][-10:] # Store last 10 actions
|
||||
|
||||
# Update action counts for stats
|
||||
actions = np.argmax(action_probs_np, axis=1)
|
||||
@ -676,11 +698,11 @@ class CNNModelPyTorch:
|
||||
action_dict = dict(zip(unique, counts))
|
||||
|
||||
if 0 in action_dict:
|
||||
self.action_counts['SELL'] += action_dict[0]
|
||||
self.action_counts['SELL'][0] += action_dict[0]
|
||||
if 1 in action_dict:
|
||||
self.action_counts['HOLD'] += action_dict[1]
|
||||
self.action_counts['HOLD'][0] += action_dict[1]
|
||||
if 2 in action_dict:
|
||||
self.action_counts['BUY'] += action_dict[2]
|
||||
self.action_counts['BUY'][0] += action_dict[2]
|
||||
|
||||
# Get the current close prices from the input
|
||||
current_prices = X_tensor[:, -1, 3].cpu().numpy() if X_tensor.shape[2] > 3 else np.zeros(X_tensor.shape[0])
|
||||
@ -838,20 +860,25 @@ class CNNModelPyTorch:
|
||||
f"val_loss: {val_loss:.4f} - val_acc: {val_acc:.4f}")
|
||||
|
||||
# Update history
|
||||
self.history['loss'].append(epoch_loss)
|
||||
self.history['accuracy'].append(epoch_acc)
|
||||
self.history['val_loss'].append(val_loss)
|
||||
self.history['val_accuracy'].append(val_acc)
|
||||
self.train_losses.append(epoch_loss)
|
||||
self.train_accuracies.append(epoch_acc)
|
||||
self.val_losses.append(val_loss)
|
||||
self.val_accuracies.append(val_acc)
|
||||
else:
|
||||
logger.info(f"Epoch {epoch+1}/{epochs} - "
|
||||
f"loss: {epoch_loss:.4f} - acc: {epoch_acc:.4f}")
|
||||
|
||||
# Update history without validation
|
||||
self.history['loss'].append(epoch_loss)
|
||||
self.history['accuracy'].append(epoch_acc)
|
||||
self.train_losses.append(epoch_loss)
|
||||
self.train_accuracies.append(epoch_acc)
|
||||
|
||||
logger.info("Training completed")
|
||||
return self.history
|
||||
return {
|
||||
'loss': self.train_losses,
|
||||
'accuracy': self.train_accuracies,
|
||||
'val_loss': self.val_losses,
|
||||
'val_accuracy': self.val_accuracies
|
||||
}
|
||||
|
||||
def evaluate_metrics(self, X_test, y_test):
|
||||
"""
|
||||
@ -892,9 +919,14 @@ class CNNModelPyTorch:
|
||||
model_state = {
|
||||
'model_state_dict': self.model.state_dict(),
|
||||
'optimizer_state_dict': self.optimizer.state_dict(),
|
||||
'history': self.history,
|
||||
'history': {
|
||||
'loss': self.train_losses,
|
||||
'accuracy': self.train_accuracies,
|
||||
'val_loss': self.val_losses,
|
||||
'val_accuracy': self.val_accuracies
|
||||
},
|
||||
'window_size': self.window_size,
|
||||
'num_features': self.num_features,
|
||||
'num_features': self.total_features,
|
||||
'output_size': self.output_size,
|
||||
'timeframes': self.timeframes,
|
||||
# Save trading configuration
|
||||
@ -930,12 +962,12 @@ class CNNModelPyTorch:
|
||||
|
||||
# Update model parameters
|
||||
self.window_size = model_state['window_size']
|
||||
self.num_features = model_state['num_features']
|
||||
self.total_features = model_state['num_features']
|
||||
self.output_size = model_state['output_size']
|
||||
self.timeframes = model_state.get('timeframes', ["1m"])
|
||||
|
||||
# Load model state dict
|
||||
self.load_state_dict(model_state['model_state_dict'])
|
||||
self.model.load_state_dict(model_state['model_state_dict'])
|
||||
|
||||
# Load optimizer state if available
|
||||
if 'optimizer_state_dict' in model_state:
|
||||
|
Reference in New Issue
Block a user