mcli-framework 7.12.0__py3-none-any.whl → 7.12.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

Files changed (216) hide show
  1. mcli/app/__init__.py +0 -2
  2. mcli/app/commands_cmd.py +19 -23
  3. mcli/app/completion_helpers.py +5 -5
  4. mcli/app/init_cmd.py +10 -10
  5. mcli/app/lock_cmd.py +82 -27
  6. mcli/app/main.py +4 -50
  7. mcli/app/model/model.py +5 -10
  8. mcli/app/store_cmd.py +8 -8
  9. mcli/app/video/__init__.py +0 -2
  10. mcli/app/video/video.py +1 -14
  11. mcli/chat/chat.py +90 -108
  12. mcli/chat/command_rag.py +0 -4
  13. mcli/chat/enhanced_chat.py +32 -41
  14. mcli/chat/system_controller.py +37 -37
  15. mcli/chat/system_integration.py +4 -5
  16. mcli/cli.py +2 -3
  17. mcli/lib/api/api.py +4 -9
  18. mcli/lib/api/daemon_client.py +19 -20
  19. mcli/lib/api/daemon_client_local.py +1 -3
  20. mcli/lib/api/daemon_decorator.py +6 -6
  21. mcli/lib/api/mcli_decorators.py +4 -8
  22. mcli/lib/auth/__init__.py +0 -1
  23. mcli/lib/auth/auth.py +4 -5
  24. mcli/lib/auth/mcli_manager.py +7 -12
  25. mcli/lib/auth/token_util.py +5 -5
  26. mcli/lib/config/__init__.py +29 -1
  27. mcli/lib/config/config.py +0 -1
  28. mcli/lib/custom_commands.py +1 -1
  29. mcli/lib/discovery/command_discovery.py +15 -15
  30. mcli/lib/erd/erd.py +7 -7
  31. mcli/lib/files/files.py +1 -1
  32. mcli/lib/fs/__init__.py +31 -1
  33. mcli/lib/fs/fs.py +12 -13
  34. mcli/lib/lib.py +0 -1
  35. mcli/lib/logger/logger.py +7 -10
  36. mcli/lib/performance/optimizer.py +25 -27
  37. mcli/lib/performance/rust_bridge.py +22 -27
  38. mcli/lib/performance/uvloop_config.py +0 -1
  39. mcli/lib/pickles/__init__.py +0 -1
  40. mcli/lib/pickles/pickles.py +0 -2
  41. mcli/lib/secrets/commands.py +0 -2
  42. mcli/lib/secrets/manager.py +0 -1
  43. mcli/lib/secrets/repl.py +2 -3
  44. mcli/lib/secrets/store.py +1 -2
  45. mcli/lib/services/data_pipeline.py +34 -34
  46. mcli/lib/services/lsh_client.py +38 -40
  47. mcli/lib/shell/shell.py +2 -2
  48. mcli/lib/toml/__init__.py +0 -1
  49. mcli/lib/ui/styling.py +0 -1
  50. mcli/lib/ui/visual_effects.py +33 -41
  51. mcli/lib/watcher/watcher.py +0 -1
  52. mcli/ml/__init__.py +1 -1
  53. mcli/ml/api/__init__.py +1 -1
  54. mcli/ml/api/app.py +8 -9
  55. mcli/ml/api/middleware.py +10 -10
  56. mcli/ml/api/routers/__init__.py +1 -1
  57. mcli/ml/api/routers/admin_router.py +3 -3
  58. mcli/ml/api/routers/auth_router.py +17 -18
  59. mcli/ml/api/routers/backtest_router.py +2 -2
  60. mcli/ml/api/routers/data_router.py +2 -2
  61. mcli/ml/api/routers/model_router.py +14 -15
  62. mcli/ml/api/routers/monitoring_router.py +2 -2
  63. mcli/ml/api/routers/portfolio_router.py +2 -2
  64. mcli/ml/api/routers/prediction_router.py +10 -9
  65. mcli/ml/api/routers/trade_router.py +2 -2
  66. mcli/ml/api/routers/websocket_router.py +6 -7
  67. mcli/ml/api/schemas.py +2 -2
  68. mcli/ml/auth/__init__.py +1 -1
  69. mcli/ml/auth/auth_manager.py +22 -23
  70. mcli/ml/auth/models.py +17 -17
  71. mcli/ml/auth/permissions.py +17 -17
  72. mcli/ml/backtesting/__init__.py +1 -1
  73. mcli/ml/backtesting/backtest_engine.py +31 -35
  74. mcli/ml/backtesting/performance_metrics.py +12 -14
  75. mcli/ml/backtesting/run.py +1 -2
  76. mcli/ml/cache.py +35 -36
  77. mcli/ml/cli/__init__.py +1 -1
  78. mcli/ml/cli/main.py +21 -24
  79. mcli/ml/config/__init__.py +1 -1
  80. mcli/ml/config/settings.py +28 -29
  81. mcli/ml/configs/__init__.py +1 -1
  82. mcli/ml/configs/dvc_config.py +14 -15
  83. mcli/ml/configs/mlflow_config.py +12 -13
  84. mcli/ml/configs/mlops_manager.py +19 -21
  85. mcli/ml/dashboard/__init__.py +4 -4
  86. mcli/ml/dashboard/app.py +20 -30
  87. mcli/ml/dashboard/app_supabase.py +16 -19
  88. mcli/ml/dashboard/app_training.py +11 -14
  89. mcli/ml/dashboard/cli.py +2 -2
  90. mcli/ml/dashboard/common.py +2 -3
  91. mcli/ml/dashboard/components/__init__.py +1 -1
  92. mcli/ml/dashboard/components/charts.py +13 -11
  93. mcli/ml/dashboard/components/metrics.py +7 -7
  94. mcli/ml/dashboard/components/tables.py +12 -9
  95. mcli/ml/dashboard/overview.py +2 -2
  96. mcli/ml/dashboard/pages/__init__.py +1 -1
  97. mcli/ml/dashboard/pages/cicd.py +15 -18
  98. mcli/ml/dashboard/pages/debug_dependencies.py +7 -7
  99. mcli/ml/dashboard/pages/monte_carlo_predictions.py +11 -18
  100. mcli/ml/dashboard/pages/predictions_enhanced.py +24 -32
  101. mcli/ml/dashboard/pages/scrapers_and_logs.py +22 -24
  102. mcli/ml/dashboard/pages/test_portfolio.py +3 -6
  103. mcli/ml/dashboard/pages/trading.py +16 -18
  104. mcli/ml/dashboard/pages/workflows.py +20 -30
  105. mcli/ml/dashboard/utils.py +9 -9
  106. mcli/ml/dashboard/warning_suppression.py +3 -3
  107. mcli/ml/data_ingestion/__init__.py +1 -1
  108. mcli/ml/data_ingestion/api_connectors.py +41 -46
  109. mcli/ml/data_ingestion/data_pipeline.py +36 -46
  110. mcli/ml/data_ingestion/stream_processor.py +43 -46
  111. mcli/ml/database/__init__.py +1 -1
  112. mcli/ml/database/migrations/env.py +2 -2
  113. mcli/ml/database/models.py +22 -24
  114. mcli/ml/database/session.py +14 -14
  115. mcli/ml/experimentation/__init__.py +1 -1
  116. mcli/ml/experimentation/ab_testing.py +45 -46
  117. mcli/ml/features/__init__.py +1 -1
  118. mcli/ml/features/ensemble_features.py +22 -27
  119. mcli/ml/features/recommendation_engine.py +30 -30
  120. mcli/ml/features/stock_features.py +29 -32
  121. mcli/ml/features/test_feature_engineering.py +10 -11
  122. mcli/ml/logging.py +4 -4
  123. mcli/ml/mlops/__init__.py +1 -1
  124. mcli/ml/mlops/data_versioning.py +29 -30
  125. mcli/ml/mlops/experiment_tracker.py +24 -24
  126. mcli/ml/mlops/model_serving.py +31 -34
  127. mcli/ml/mlops/pipeline_orchestrator.py +27 -35
  128. mcli/ml/models/__init__.py +5 -6
  129. mcli/ml/models/base_models.py +23 -23
  130. mcli/ml/models/ensemble_models.py +31 -31
  131. mcli/ml/models/recommendation_models.py +18 -19
  132. mcli/ml/models/test_models.py +14 -16
  133. mcli/ml/monitoring/__init__.py +1 -1
  134. mcli/ml/monitoring/drift_detection.py +32 -36
  135. mcli/ml/monitoring/metrics.py +2 -2
  136. mcli/ml/optimization/__init__.py +1 -1
  137. mcli/ml/optimization/optimize.py +1 -2
  138. mcli/ml/optimization/portfolio_optimizer.py +30 -32
  139. mcli/ml/predictions/__init__.py +1 -1
  140. mcli/ml/preprocessing/__init__.py +1 -1
  141. mcli/ml/preprocessing/data_cleaners.py +22 -23
  142. mcli/ml/preprocessing/feature_extractors.py +23 -26
  143. mcli/ml/preprocessing/ml_pipeline.py +23 -23
  144. mcli/ml/preprocessing/test_preprocessing.py +7 -8
  145. mcli/ml/scripts/populate_sample_data.py +0 -4
  146. mcli/ml/serving/serve.py +1 -2
  147. mcli/ml/tasks.py +17 -17
  148. mcli/ml/tests/test_integration.py +29 -30
  149. mcli/ml/tests/test_training_dashboard.py +21 -21
  150. mcli/ml/trading/__init__.py +1 -1
  151. mcli/ml/trading/migrations.py +5 -5
  152. mcli/ml/trading/models.py +21 -23
  153. mcli/ml/trading/paper_trading.py +16 -13
  154. mcli/ml/trading/risk_management.py +17 -18
  155. mcli/ml/trading/trading_service.py +25 -28
  156. mcli/ml/training/__init__.py +1 -1
  157. mcli/ml/training/train.py +0 -1
  158. mcli/public/oi/oi.py +1 -2
  159. mcli/self/completion_cmd.py +6 -10
  160. mcli/self/logs_cmd.py +19 -24
  161. mcli/self/migrate_cmd.py +22 -20
  162. mcli/self/redis_cmd.py +10 -11
  163. mcli/self/self_cmd.py +62 -18
  164. mcli/self/store_cmd.py +10 -12
  165. mcli/self/visual_cmd.py +9 -14
  166. mcli/self/zsh_cmd.py +2 -4
  167. mcli/workflow/daemon/async_command_database.py +23 -24
  168. mcli/workflow/daemon/async_process_manager.py +27 -29
  169. mcli/workflow/daemon/client.py +27 -33
  170. mcli/workflow/daemon/daemon.py +32 -36
  171. mcli/workflow/daemon/enhanced_daemon.py +24 -33
  172. mcli/workflow/daemon/process_cli.py +11 -12
  173. mcli/workflow/daemon/process_manager.py +23 -26
  174. mcli/workflow/daemon/test_daemon.py +4 -5
  175. mcli/workflow/dashboard/dashboard_cmd.py +0 -1
  176. mcli/workflow/doc_convert.py +15 -17
  177. mcli/workflow/gcloud/__init__.py +0 -1
  178. mcli/workflow/gcloud/gcloud.py +11 -8
  179. mcli/workflow/git_commit/ai_service.py +14 -15
  180. mcli/workflow/lsh_integration.py +9 -11
  181. mcli/workflow/model_service/client.py +26 -31
  182. mcli/workflow/model_service/download_and_run_efficient_models.py +10 -14
  183. mcli/workflow/model_service/lightweight_embedder.py +25 -35
  184. mcli/workflow/model_service/lightweight_model_server.py +26 -32
  185. mcli/workflow/model_service/lightweight_test.py +7 -10
  186. mcli/workflow/model_service/model_service.py +80 -91
  187. mcli/workflow/model_service/ollama_efficient_runner.py +14 -18
  188. mcli/workflow/model_service/openai_adapter.py +23 -23
  189. mcli/workflow/model_service/pdf_processor.py +21 -26
  190. mcli/workflow/model_service/test_efficient_runner.py +12 -16
  191. mcli/workflow/model_service/test_example.py +11 -13
  192. mcli/workflow/model_service/test_integration.py +3 -5
  193. mcli/workflow/model_service/test_new_features.py +7 -8
  194. mcli/workflow/notebook/converter.py +1 -1
  195. mcli/workflow/notebook/notebook_cmd.py +5 -6
  196. mcli/workflow/notebook/schema.py +0 -1
  197. mcli/workflow/notebook/validator.py +7 -3
  198. mcli/workflow/openai/openai.py +1 -2
  199. mcli/workflow/registry/registry.py +4 -1
  200. mcli/workflow/repo/repo.py +6 -7
  201. mcli/workflow/scheduler/cron_parser.py +16 -19
  202. mcli/workflow/scheduler/job.py +10 -10
  203. mcli/workflow/scheduler/monitor.py +15 -15
  204. mcli/workflow/scheduler/persistence.py +17 -18
  205. mcli/workflow/scheduler/scheduler.py +37 -38
  206. mcli/workflow/secrets/__init__.py +1 -1
  207. mcli/workflow/sync/test_cmd.py +0 -1
  208. mcli/workflow/wakatime/__init__.py +5 -9
  209. mcli/workflow/wakatime/wakatime.py +1 -2
  210. {mcli_framework-7.12.0.dist-info → mcli_framework-7.12.3.dist-info}/METADATA +1 -1
  211. mcli_framework-7.12.3.dist-info/RECORD +279 -0
  212. mcli_framework-7.12.0.dist-info/RECORD +0 -279
  213. {mcli_framework-7.12.0.dist-info → mcli_framework-7.12.3.dist-info}/WHEEL +0 -0
  214. {mcli_framework-7.12.0.dist-info → mcli_framework-7.12.3.dist-info}/entry_points.txt +0 -0
  215. {mcli_framework-7.12.0.dist-info → mcli_framework-7.12.3.dist-info}/licenses/LICENSE +0 -0
  216. {mcli_framework-7.12.0.dist-info → mcli_framework-7.12.3.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- """Base classes for ML models"""
1
+ """Base classes for ML models."""
2
2
 
3
3
  import logging
4
4
  from abc import ABC, abstractmethod
@@ -15,7 +15,7 @@ logger = logging.getLogger(__name__)
15
15
 
16
16
  @dataclass
17
17
  class ModelMetrics:
18
- """Container for model performance metrics"""
18
+ """Container for model performance metrics."""
19
19
 
20
20
  accuracy: float
21
21
  precision: float
@@ -30,7 +30,7 @@ class ModelMetrics:
30
30
  avg_loss: Optional[float] = None
31
31
 
32
32
  def to_dict(self) -> Dict[str, float]:
33
- """Convert metrics to dictionary"""
33
+ """Convert metrics to dictionary."""
34
34
  return {
35
35
  "accuracy": self.accuracy,
36
36
  "precision": self.precision,
@@ -48,7 +48,7 @@ class ModelMetrics:
48
48
 
49
49
  @dataclass
50
50
  class ValidationResult:
51
- """Container for validation results"""
51
+ """Container for validation results."""
52
52
 
53
53
  train_metrics: ModelMetrics
54
54
  val_metrics: ModelMetrics
@@ -60,7 +60,7 @@ class ValidationResult:
60
60
 
61
61
 
62
62
  class BaseStockModel(nn.Module, ABC):
63
- """Abstract base class for all stock prediction models"""
63
+ """Abstract base class for all stock prediction models."""
64
64
 
65
65
  def __init__(self, input_dim: int, config: Optional[Dict[str, Any]] = None):
66
66
  super().__init__()
@@ -73,21 +73,21 @@ class BaseStockModel(nn.Module, ABC):
73
73
 
74
74
  @abstractmethod
75
75
  def forward(self, x: torch.Tensor) -> torch.Tensor:
76
- """Forward pass through the model"""
76
+ """Forward pass through the model."""
77
77
  pass
78
78
 
79
79
  @abstractmethod
80
80
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
81
- """Predict class probabilities"""
81
+ """Predict class probabilities."""
82
82
  pass
83
83
 
84
84
  def predict(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
85
- """Make binary predictions"""
85
+ """Make binary predictions."""
86
86
  probas = self.predict_proba(X)
87
87
  return (probas[:, 1] > 0.5).astype(int)
88
88
 
89
89
  def preprocess_input(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> torch.Tensor:
90
- """Preprocess input data for model"""
90
+ """Preprocess input data for model."""
91
91
  if isinstance(X, pd.DataFrame):
92
92
  X = X.values
93
93
 
@@ -102,13 +102,13 @@ class BaseStockModel(nn.Module, ABC):
102
102
  return X.to(self.device)
103
103
 
104
104
  def get_feature_importance(self) -> Optional[Dict[str, float]]:
105
- """Get feature importance scores"""
105
+ """Get feature importance scores."""
106
106
  # Base implementation returns None
107
107
  # Override in specific models that support feature importance
108
108
  return None
109
109
 
110
110
  def save_model(self, path: str) -> None:
111
- """Save model state"""
111
+ """Save model state."""
112
112
  state = {
113
113
  "model_state_dict": self.state_dict(),
114
114
  "config": self.config,
@@ -121,7 +121,7 @@ class BaseStockModel(nn.Module, ABC):
121
121
  logger.info(f"Model saved to {path}")
122
122
 
123
123
  def load_model(self, path: str) -> None:
124
- """Load model state"""
124
+ """Load model state."""
125
125
  state = torch.load(path, map_location=self.device)
126
126
  self.load_state_dict(state["model_state_dict"])
127
127
  self.config = state["config"]
@@ -134,7 +134,7 @@ class BaseStockModel(nn.Module, ABC):
134
134
  def calculate_metrics(
135
135
  self, y_true: np.ndarray, y_pred: np.ndarray, y_proba: Optional[np.ndarray] = None
136
136
  ) -> ModelMetrics:
137
- """Calculate comprehensive model metrics"""
137
+ """Calculate comprehensive model metrics."""
138
138
  from sklearn.metrics import (
139
139
  accuracy_score,
140
140
  f1_score,
@@ -173,13 +173,13 @@ class BaseStockModel(nn.Module, ABC):
173
173
  )
174
174
 
175
175
  def to(self, device):
176
- """Move model to device and update internal device reference"""
176
+ """Move model to device and update internal device reference."""
177
177
  self.device = device
178
178
  return super().to(device)
179
179
 
180
180
 
181
181
  class MLPBaseModel(BaseStockModel):
182
- """Basic Multi-Layer Perceptron base model"""
182
+ """Basic Multi-Layer Perceptron base model."""
183
183
 
184
184
  def __init__(
185
185
  self,
@@ -220,18 +220,18 @@ class MLPBaseModel(BaseStockModel):
220
220
  self.apply(self._init_weights)
221
221
 
222
222
  def _init_weights(self, module):
223
- """Initialize model weights"""
223
+ """Initialize model weights."""
224
224
  if isinstance(module, nn.Linear):
225
225
  torch.nn.init.xavier_uniform_(module.weight)
226
226
  if module.bias is not None:
227
227
  torch.nn.init.zeros_(module.bias)
228
228
 
229
229
  def forward(self, x: torch.Tensor) -> torch.Tensor:
230
- """Forward pass"""
230
+ """Forward pass."""
231
231
  return self.network(x)
232
232
 
233
233
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
234
- """Predict class probabilities"""
234
+ """Predict class probabilities."""
235
235
  self.eval()
236
236
  with torch.no_grad():
237
237
  X_tensor = self.preprocess_input(X)
@@ -241,7 +241,7 @@ class MLPBaseModel(BaseStockModel):
241
241
 
242
242
 
243
243
  class ResidualBlock(nn.Module):
244
- """Residual block for deeper networks"""
244
+ """Residual block for deeper networks."""
245
245
 
246
246
  def __init__(self, dim: int, dropout_rate: float = 0.1):
247
247
  super().__init__()
@@ -263,7 +263,7 @@ class ResidualBlock(nn.Module):
263
263
 
264
264
 
265
265
  class ResNetModel(BaseStockModel):
266
- """ResNet-style model for tabular data"""
266
+ """ResNet-style model for tabular data."""
267
267
 
268
268
  def __init__(
269
269
  self,
@@ -300,14 +300,14 @@ class ResNetModel(BaseStockModel):
300
300
  self.apply(self._init_weights)
301
301
 
302
302
  def _init_weights(self, module):
303
- """Initialize weights"""
303
+ """Initialize weights."""
304
304
  if isinstance(module, nn.Linear):
305
305
  torch.nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu")
306
306
  if module.bias is not None:
307
307
  torch.nn.init.zeros_(module.bias)
308
308
 
309
309
  def forward(self, x: torch.Tensor) -> torch.Tensor:
310
- """Forward pass"""
310
+ """Forward pass."""
311
311
  x = self.input_proj(x)
312
312
 
313
313
  for block in self.blocks:
@@ -316,7 +316,7 @@ class ResNetModel(BaseStockModel):
316
316
  return self.output_layer(x)
317
317
 
318
318
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
319
- """Predict class probabilities"""
319
+ """Predict class probabilities."""
320
320
  self.eval()
321
321
  with torch.no_grad():
322
322
  X_tensor = self.preprocess_input(X)
@@ -1,4 +1,4 @@
1
- """Ensemble models for stock prediction"""
1
+ """Ensemble models for stock prediction."""
2
2
 
3
3
  import logging
4
4
  from dataclasses import dataclass
@@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
17
17
 
18
18
  @dataclass
19
19
  class ModelConfig:
20
- """Configuration for individual models"""
20
+ """Configuration for individual models."""
21
21
 
22
22
  model_type: str
23
23
  hidden_dims: List[int]
@@ -30,7 +30,7 @@ class ModelConfig:
30
30
 
31
31
  @dataclass
32
32
  class EnsembleConfig:
33
- """Configuration for ensemble model"""
33
+ """Configuration for ensemble model."""
34
34
 
35
35
  base_models: List[ModelConfig]
36
36
  ensemble_method: str = "weighted_average" # weighted_average, stacking, voting
@@ -41,7 +41,7 @@ class EnsembleConfig:
41
41
 
42
42
 
43
43
  class AttentionStockPredictor(BaseStockModel):
44
- """Attention-based stock predictor"""
44
+ """Attention-based stock predictor."""
45
45
 
46
46
  def __init__(
47
47
  self,
@@ -104,7 +104,7 @@ class AttentionStockPredictor(BaseStockModel):
104
104
  self.softmax = nn.Softmax(dim=1)
105
105
 
106
106
  def forward(self, x: torch.Tensor) -> torch.Tensor:
107
- """Forward pass with attention mechanism"""
107
+ """Forward pass with attention mechanism."""
108
108
  # Project input
109
109
  x = self.input_proj(x)
110
110
 
@@ -131,7 +131,7 @@ class AttentionStockPredictor(BaseStockModel):
131
131
  return self.output_layer(x)
132
132
 
133
133
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
134
- """Predict class probabilities"""
134
+ """Predict class probabilities."""
135
135
  self.eval()
136
136
  with torch.no_grad():
137
137
  X_tensor = self.preprocess_input(X)
@@ -141,7 +141,7 @@ class AttentionStockPredictor(BaseStockModel):
141
141
 
142
142
 
143
143
  class TransformerStockModel(BaseStockModel):
144
- """Transformer model for stock prediction"""
144
+ """Transformer model for stock prediction."""
145
145
 
146
146
  def __init__(
147
147
  self,
@@ -185,7 +185,7 @@ class TransformerStockModel(BaseStockModel):
185
185
  self.softmax = nn.Softmax(dim=1)
186
186
 
187
187
  def forward(self, x: torch.Tensor) -> torch.Tensor:
188
- """Forward pass through transformer"""
188
+ """Forward pass through transformer."""
189
189
  # Embed input
190
190
  x = self.input_embedding(x)
191
191
 
@@ -205,7 +205,7 @@ class TransformerStockModel(BaseStockModel):
205
205
  return self.classifier(x)
206
206
 
207
207
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
208
- """Predict class probabilities"""
208
+ """Predict class probabilities."""
209
209
  self.eval()
210
210
  with torch.no_grad():
211
211
  X_tensor = self.preprocess_input(X)
@@ -215,7 +215,7 @@ class TransformerStockModel(BaseStockModel):
215
215
 
216
216
 
217
217
  class PositionalEncoding(nn.Module):
218
- """Positional encoding for transformer"""
218
+ """Positional encoding for transformer."""
219
219
 
220
220
  def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000):
221
221
  super().__init__()
@@ -235,7 +235,7 @@ class PositionalEncoding(nn.Module):
235
235
 
236
236
 
237
237
  class LSTMStockPredictor(BaseStockModel):
238
- """LSTM-based stock predictor"""
238
+ """LSTM-based stock predictor."""
239
239
 
240
240
  def __init__(
241
241
  self,
@@ -272,7 +272,7 @@ class LSTMStockPredictor(BaseStockModel):
272
272
  self.softmax = nn.Softmax(dim=1)
273
273
 
274
274
  def forward(self, x: torch.Tensor) -> torch.Tensor:
275
- """Forward pass through LSTM"""
275
+ """Forward pass through LSTM."""
276
276
  # Add sequence dimension if needed
277
277
  if x.dim() == 2:
278
278
  x = x.unsqueeze(1)
@@ -286,7 +286,7 @@ class LSTMStockPredictor(BaseStockModel):
286
286
  return self.classifier(x)
287
287
 
288
288
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
289
- """Predict class probabilities"""
289
+ """Predict class probabilities."""
290
290
  self.eval()
291
291
  with torch.no_grad():
292
292
  X_tensor = self.preprocess_input(X)
@@ -296,7 +296,7 @@ class LSTMStockPredictor(BaseStockModel):
296
296
 
297
297
 
298
298
  class CNNFeatureExtractor(BaseStockModel):
299
- """CNN-based feature extractor for tabular data"""
299
+ """CNN-based feature extractor for tabular data."""
300
300
 
301
301
  def __init__(
302
302
  self,
@@ -350,8 +350,8 @@ class CNNFeatureExtractor(BaseStockModel):
350
350
  self.softmax = nn.Softmax(dim=1)
351
351
 
352
352
  def forward(self, x: torch.Tensor) -> torch.Tensor:
353
- """Forward pass through CNN"""
354
- batch_size = x.size(0)
353
+ """Forward pass through CNN."""
354
+ batch_size = x.size(0) # noqa: F841
355
355
 
356
356
  # Apply padding if needed
357
357
  if self.input_padding is not None:
@@ -373,7 +373,7 @@ class CNNFeatureExtractor(BaseStockModel):
373
373
  return self.classifier(x)
374
374
 
375
375
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
376
- """Predict class probabilities"""
376
+ """Predict class probabilities."""
377
377
  self.eval()
378
378
  with torch.no_grad():
379
379
  X_tensor = self.preprocess_input(X)
@@ -383,7 +383,7 @@ class CNNFeatureExtractor(BaseStockModel):
383
383
 
384
384
 
385
385
  class DeepEnsembleModel(BaseStockModel):
386
- """Deep ensemble combining multiple models"""
386
+ """Deep ensemble combining multiple models."""
387
387
 
388
388
  def __init__(self, input_dim: int, config: EnsembleConfig):
389
389
  super().__init__(input_dim, config.__dict__)
@@ -406,7 +406,7 @@ class DeepEnsembleModel(BaseStockModel):
406
406
  self.softmax = nn.Softmax(dim=1)
407
407
 
408
408
  def _create_model(self, model_config: ModelConfig, input_dim: int) -> BaseStockModel:
409
- """Create individual model based on configuration"""
409
+ """Create individual model based on configuration."""
410
410
  if model_config.model_type == "attention":
411
411
  return AttentionStockPredictor(
412
412
  input_dim=input_dim,
@@ -442,7 +442,7 @@ class DeepEnsembleModel(BaseStockModel):
442
442
  )
443
443
 
444
444
  def forward(self, x: torch.Tensor) -> torch.Tensor:
445
- """Forward pass through ensemble"""
445
+ """Forward pass through ensemble."""
446
446
  model_outputs = []
447
447
 
448
448
  for model in self.models:
@@ -480,7 +480,7 @@ class DeepEnsembleModel(BaseStockModel):
480
480
  return ensemble_output
481
481
 
482
482
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
483
- """Predict class probabilities"""
483
+ """Predict class probabilities."""
484
484
  self.eval()
485
485
  with torch.no_grad():
486
486
  X_tensor = self.preprocess_input(X)
@@ -489,13 +489,13 @@ class DeepEnsembleModel(BaseStockModel):
489
489
  return probas.cpu().numpy()
490
490
 
491
491
  def set_model_weights(self, weights: List[float]):
492
- """Set weights for weighted ensemble"""
492
+ """Set weights for weighted ensemble."""
493
493
  self.model_weights = torch.FloatTensor(weights)
494
494
 
495
495
  def get_individual_predictions(
496
496
  self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]
497
497
  ) -> List[np.ndarray]:
498
- """Get predictions from individual models"""
498
+ """Get predictions from individual models."""
499
499
  predictions = []
500
500
  self.eval()
501
501
 
@@ -508,7 +508,7 @@ class DeepEnsembleModel(BaseStockModel):
508
508
 
509
509
 
510
510
  class EnsembleTrainer:
511
- """Trainer for ensemble models"""
511
+ """Trainer for ensemble models."""
512
512
 
513
513
  def __init__(self, ensemble_model: DeepEnsembleModel, config: EnsembleConfig):
514
514
  self.ensemble_model = ensemble_model
@@ -523,7 +523,7 @@ class EnsembleTrainer:
523
523
  X_val: Optional[np.ndarray] = None,
524
524
  y_val: Optional[np.ndarray] = None,
525
525
  ) -> ValidationResult:
526
- """Train the ensemble model"""
526
+ """Train the ensemble model."""
527
527
  logger.info("Training ensemble model...")
528
528
 
529
529
  # Train individual models first
@@ -568,7 +568,7 @@ class EnsembleTrainer:
568
568
  def _create_subset(
569
569
  self, X: np.ndarray, y: np.ndarray, model_config: ModelConfig
570
570
  ) -> Tuple[np.ndarray, np.ndarray]:
571
- """Create data subset for individual model training"""
571
+ """Create data subset for individual model training."""
572
572
  if self.config.bootstrap_samples:
573
573
  # Bootstrap sampling
574
574
  n_samples = len(X)
@@ -586,7 +586,7 @@ class EnsembleTrainer:
586
586
  X_val: Optional[np.ndarray],
587
587
  y_val: Optional[np.ndarray],
588
588
  ) -> Dict[str, Any]:
589
- """Train individual model"""
589
+ """Train individual model."""
590
590
  from torch.utils.data import DataLoader, TensorDataset
591
591
 
592
592
  # Convert to tensors
@@ -629,7 +629,7 @@ class EnsembleTrainer:
629
629
  return {"train_losses": train_losses}
630
630
 
631
631
  def _calculate_ensemble_weights(self, X_val: np.ndarray, y_val: np.ndarray):
632
- """Calculate optimal ensemble weights based on validation performance"""
632
+ """Calculate optimal ensemble weights based on validation performance."""
633
633
  individual_predictions = self.ensemble_model.get_individual_predictions(X_val)
634
634
 
635
635
  # Calculate individual model accuracies
@@ -653,21 +653,21 @@ class EnsembleTrainer:
653
653
  X_val: Optional[np.ndarray],
654
654
  y_val: Optional[np.ndarray],
655
655
  ):
656
- """Train meta-learner for stacking ensemble"""
656
+ """Train meta-learner for stacking ensemble."""
657
657
  # Get predictions from base models
658
658
  train_predictions = self.ensemble_model.get_individual_predictions(X_train)
659
659
  meta_X_train = np.concatenate(train_predictions, axis=1)
660
660
 
661
661
  # Train meta-learner
662
662
  meta_config = self.config.meta_learner_config
663
- result = self._train_individual_model(
663
+ result = self._train_individual_model( # noqa: F841
664
664
  self.ensemble_model.meta_learner, meta_config, meta_X_train, y_train, None, None
665
665
  )
666
666
 
667
667
  logger.info("Meta-learner training completed")
668
668
 
669
669
  def _evaluate(self, X: np.ndarray, y: np.ndarray) -> ModelMetrics:
670
- """Evaluate ensemble model"""
670
+ """Evaluate ensemble model."""
671
671
  if X is None or y is None:
672
672
  return ModelMetrics(0, 0, 0, 0, 0)
673
673
 
@@ -1,25 +1,24 @@
1
- """Stock recommendation models"""
1
+ """Stock recommendation models."""
2
2
 
3
3
  import logging
4
4
  from dataclasses import dataclass
5
5
  from datetime import datetime
6
- from typing import Any, Dict, List, Optional, Tuple, Union
6
+ from typing import Dict, List, Optional, Union
7
7
 
8
8
  import numpy as np
9
9
  import pandas as pd
10
10
  import torch
11
11
  import torch.nn as nn
12
- import torch.nn.functional as F
13
12
 
14
13
  from mcli.ml.models.base_models import BaseStockModel, ModelMetrics, ValidationResult
15
- from mcli.ml.models.ensemble_models import DeepEnsembleModel, EnsembleConfig, ModelConfig
14
+ from mcli.ml.models.ensemble_models import DeepEnsembleModel, EnsembleConfig
16
15
 
17
16
  logger = logging.getLogger(__name__)
18
17
 
19
18
 
20
19
  @dataclass
21
20
  class RecommendationConfig:
22
- """Configuration for recommendation model"""
21
+ """Configuration for recommendation model."""
23
22
 
24
23
  ensemble_config: EnsembleConfig
25
24
  risk_adjustment: bool = True
@@ -32,7 +31,7 @@ class RecommendationConfig:
32
31
 
33
32
  @dataclass
34
33
  class PortfolioRecommendation:
35
- """Portfolio recommendation result"""
34
+ """Portfolio recommendation result."""
36
35
 
37
36
  ticker: str
38
37
  recommendation_score: float
@@ -59,7 +58,7 @@ class PortfolioRecommendation:
59
58
 
60
59
 
61
60
  class StockRecommendationModel(BaseStockModel):
62
- """Main stock recommendation model combining ensemble prediction with portfolio optimization"""
61
+ """Main stock recommendation model combining ensemble prediction with portfolio optimization."""
63
62
 
64
63
  def __init__(self, input_dim: int, config: RecommendationConfig):
65
64
  super().__init__(input_dim, config.__dict__)
@@ -104,7 +103,7 @@ class StockRecommendationModel(BaseStockModel):
104
103
  self.softmax = nn.Softmax(dim=1)
105
104
 
106
105
  def forward(self, x: torch.Tensor) -> Dict[str, torch.Tensor]:
107
- """Forward pass returning multiple outputs"""
106
+ """Forward pass returning multiple outputs."""
108
107
  # Main prediction
109
108
  main_prediction = self.ensemble_model(x)
110
109
 
@@ -132,7 +131,7 @@ class StockRecommendationModel(BaseStockModel):
132
131
  }
133
132
 
134
133
  def predict_proba(self, X: Union[torch.Tensor, np.ndarray, pd.DataFrame]) -> np.ndarray:
135
- """Predict class probabilities"""
134
+ """Predict class probabilities."""
136
135
  self.eval()
137
136
  with torch.no_grad():
138
137
  X_tensor = self.preprocess_input(X)
@@ -146,7 +145,7 @@ class StockRecommendationModel(BaseStockModel):
146
145
  tickers: List[str],
147
146
  market_data: Optional[pd.DataFrame] = None,
148
147
  ) -> List[PortfolioRecommendation]:
149
- """Generate portfolio recommendations"""
148
+ """Generate portfolio recommendations."""
150
149
  self.eval()
151
150
  recommendations = []
152
151
 
@@ -187,7 +186,7 @@ class StockRecommendationModel(BaseStockModel):
187
186
  features: np.ndarray,
188
187
  market_data: Optional[pd.DataFrame],
189
188
  ) -> PortfolioRecommendation:
190
- """Create individual stock recommendation"""
189
+ """Create individual stock recommendation."""
191
190
 
192
191
  # Basic recommendation score (probability of positive outcome)
193
192
  recommendation_score = main_prob[1] # Assuming class 1 is positive
@@ -253,7 +252,7 @@ class StockRecommendationModel(BaseStockModel):
253
252
  def _generate_recommendation_reason(
254
253
  self, score: float, risk: str, confidence: float, expected_return: float
255
254
  ) -> str:
256
- """Generate human-readable recommendation reason"""
255
+ """Generate human-readable recommendation reason."""
257
256
  if score > 0.7:
258
257
  strength = "Strong"
259
258
  elif score > 0.6:
@@ -267,12 +266,12 @@ class StockRecommendationModel(BaseStockModel):
267
266
  )
268
267
 
269
268
  def _extract_key_features(self, features: np.ndarray) -> List[str]:
270
- """Extract key features driving the recommendation"""
269
+ """Extract key features driving the recommendation."""
271
270
  # Simplified implementation - would use feature importance in practice
272
271
  return ["technical_indicators", "political_influence", "market_regime"]
273
272
 
274
273
  def _generate_warnings(self, risk_level: str, confidence: float, score: float) -> List[str]:
275
- """Generate warnings for the recommendation"""
274
+ """Generate warnings for the recommendation."""
276
275
  warnings = []
277
276
 
278
277
  if confidence < 0.5:
@@ -289,7 +288,7 @@ class StockRecommendationModel(BaseStockModel):
289
288
  def _optimize_portfolio(
290
289
  self, recommendations: List[PortfolioRecommendation]
291
290
  ) -> List[PortfolioRecommendation]:
292
- """Apply portfolio-level optimization"""
291
+ """Apply portfolio-level optimization."""
293
292
  # Sort by risk-adjusted score
294
293
  recommendations.sort(key=lambda x: x.risk_adjusted_score, reverse=True)
295
294
 
@@ -319,7 +318,7 @@ class StockRecommendationModel(BaseStockModel):
319
318
 
320
319
 
321
320
  class RecommendationTrainer:
322
- """Trainer for recommendation model"""
321
+ """Trainer for recommendation model."""
323
322
 
324
323
  def __init__(self, model: StockRecommendationModel, config: RecommendationConfig):
325
324
  self.model = model
@@ -340,7 +339,7 @@ class RecommendationTrainer:
340
339
  epochs: int = 100,
341
340
  batch_size: int = 64,
342
341
  ) -> ValidationResult:
343
- """Train the recommendation model"""
342
+ """Train the recommendation model."""
344
343
 
345
344
  from torch.utils.data import DataLoader, TensorDataset
346
345
 
@@ -442,7 +441,7 @@ class RecommendationTrainer:
442
441
  returns_val: np.ndarray,
443
442
  risk_labels_val: np.ndarray,
444
443
  ) -> float:
445
- """Validate model during training"""
444
+ """Validate model during training."""
446
445
  self.model.eval()
447
446
 
448
447
  with torch.no_grad():
@@ -466,7 +465,7 @@ class RecommendationTrainer:
466
465
  return total_loss.item()
467
466
 
468
467
  def _evaluate(self, X: np.ndarray, y: np.ndarray) -> ModelMetrics:
469
- """Evaluate model performance"""
468
+ """Evaluate model performance."""
470
469
  if X is None or y is None:
471
470
  return ModelMetrics(0, 0, 0, 0, 0)
472
471