showing trades on realtime chart - chart broken

This commit is contained in:
Dobromir Popov
2025-03-31 14:22:33 +03:00
parent 0ad9484d56
commit a46b2c74f8
14 changed files with 3182 additions and 76 deletions

View File

@ -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: