mcli-framework 7.12.2__py3-none-any.whl → 7.12.4__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 +30 -26
  3. mcli/app/completion_helpers.py +5 -5
  4. mcli/app/init_cmd.py +10 -10
  5. mcli/app/lock_cmd.py +29 -24
  6. mcli/app/main.py +2 -8
  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 +10 -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.2.dist-info → mcli_framework-7.12.4.dist-info}/METADATA +1 -1
  211. mcli_framework-7.12.4.dist-info/RECORD +279 -0
  212. mcli_framework-7.12.2.dist-info/RECORD +0 -279
  213. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/WHEEL +0 -0
  214. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/entry_points.txt +0 -0
  215. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/licenses/LICENSE +0 -0
  216. {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
- """Unit tests for training dashboard functionality"""
1
+ """Unit tests for training dashboard functionality."""
2
2
 
3
3
  from datetime import datetime, timedelta
4
- from unittest.mock import MagicMock, Mock, patch
4
+ from unittest.mock import MagicMock, Mock
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
@@ -12,17 +12,17 @@ from mcli.ml.database.models import Experiment, Model, ModelStatus
12
12
 
13
13
 
14
14
  class TestTrainingDashboard:
15
- """Test suite for training dashboard functions"""
15
+ """Test suite for training dashboard functions."""
16
16
 
17
17
  @pytest.fixture
18
18
  def mock_db_session(self):
19
- """Create mock database session"""
19
+ """Create mock database session."""
20
20
  session = MagicMock(spec=Session)
21
21
  return session
22
22
 
23
23
  @pytest.fixture
24
24
  def sample_models(self):
25
- """Create sample model data"""
25
+ """Create sample model data."""
26
26
  models = []
27
27
 
28
28
  # Bitcoin-style model comparison data
@@ -120,7 +120,7 @@ class TestTrainingDashboard:
120
120
 
121
121
  @pytest.fixture
122
122
  def sample_experiments(self):
123
- """Create sample experiment data"""
123
+ """Create sample experiment data."""
124
124
  experiments = []
125
125
 
126
126
  for i in range(10):
@@ -147,7 +147,7 @@ class TestTrainingDashboard:
147
147
  return experiments
148
148
 
149
149
  def test_model_comparison_metrics(self, sample_models):
150
- """Test model comparison metrics calculation"""
150
+ """Test model comparison metrics calculation."""
151
151
  # Convert to DataFrame as the dashboard would
152
152
  df = pd.DataFrame(
153
153
  [
@@ -176,7 +176,7 @@ class TestTrainingDashboard:
176
176
  assert sorted_by_mae.iloc[0]["test_mae"] < 125
177
177
 
178
178
  def test_model_performance_aggregation(self, sample_models):
179
- """Test aggregation of model performance"""
179
+ """Test aggregation of model performance."""
180
180
  metrics = {
181
181
  "total_models": len(sample_models),
182
182
  "deployed_models": sum(1 for m in sample_models if m.status == ModelStatus.DEPLOYED),
@@ -190,7 +190,7 @@ class TestTrainingDashboard:
190
190
  assert 0.75 < metrics["avg_r2"] < 0.85
191
191
 
192
192
  def test_feature_importance_calculation(self, sample_models):
193
- """Test feature importance extraction and ranking"""
193
+ """Test feature importance extraction and ranking."""
194
194
  model = sample_models[0]
195
195
 
196
196
  # Simulate feature importance
@@ -208,7 +208,7 @@ class TestTrainingDashboard:
208
208
  assert all(top_5["importance"] > 0)
209
209
 
210
210
  def test_residuals_analysis(self):
211
- """Test residual analysis calculations"""
211
+ """Test residual analysis calculations."""
212
212
  # Generate sample predictions and actuals
213
213
  np.random.seed(42)
214
214
  n = 500
@@ -234,7 +234,7 @@ class TestTrainingDashboard:
234
234
  assert 0 <= p_value <= 1
235
235
 
236
236
  def test_cross_validation_metrics(self):
237
- """Test cross-validation metrics calculation"""
237
+ """Test cross-validation metrics calculation."""
238
238
  # Simulate CV scores
239
239
  cv_scores = [0.80, 0.82, 0.78, 0.85, 0.79]
240
240
 
@@ -248,7 +248,7 @@ class TestTrainingDashboard:
248
248
  assert cv_std / cv_mean < 0.1 # Coefficient of variation < 10%
249
249
 
250
250
  def test_training_duration_analysis(self, sample_experiments):
251
- """Test training duration analysis"""
251
+ """Test training duration analysis."""
252
252
  completed = [exp for exp in sample_experiments if exp.status == "completed"]
253
253
 
254
254
  durations = [exp.duration_seconds for exp in completed]
@@ -260,7 +260,7 @@ class TestTrainingDashboard:
260
260
  assert min_duration <= avg_duration <= max_duration
261
261
 
262
262
  def test_model_comparison_ranking(self, sample_models):
263
- """Test ranking models by multiple metrics"""
263
+ """Test ranking models by multiple metrics."""
264
264
  df = pd.DataFrame(
265
265
  [
266
266
  {
@@ -289,7 +289,7 @@ class TestTrainingDashboard:
289
289
  assert best_overall["test_rmse"] < 160
290
290
 
291
291
  def test_feature_categorization(self):
292
- """Test feature categorization (lag, MA, volatility, etc.)"""
292
+ """Test feature categorization (lag, MA, volatility, etc.)."""
293
293
  features = [
294
294
  "lag_1",
295
295
  "lag_7",
@@ -329,7 +329,7 @@ class TestTrainingDashboard:
329
329
  assert len(categories["Technical"]) == 3
330
330
 
331
331
  def test_mape_calculation(self):
332
- """Test Mean Absolute Percentage Error calculation"""
332
+ """Test Mean Absolute Percentage Error calculation."""
333
333
  actual = np.array([100, 200, 150, 300, 250])
334
334
  predicted = np.array([105, 195, 160, 295, 245])
335
335
 
@@ -339,7 +339,7 @@ class TestTrainingDashboard:
339
339
  assert mape < 10 # Should be reasonably low for good predictions
340
340
 
341
341
  def test_error_metrics_comparison(self):
342
- """Test that RMSE >= MAE for any predictions"""
342
+ """Test that RMSE >= MAE for any predictions."""
343
343
  # This is a mathematical property: RMSE is always >= MAE
344
344
 
345
345
  errors = np.array([5, 3, 8, 2, 10])
@@ -350,7 +350,7 @@ class TestTrainingDashboard:
350
350
  assert rmse >= mae
351
351
 
352
352
  def test_r2_score_properties(self):
353
- """Test R² score properties"""
353
+ """Test R² score properties."""
354
354
  # Perfect predictions
355
355
  y_true = np.array([1, 2, 3, 4, 5])
356
356
  y_pred = np.array([1, 2, 3, 4, 5])
@@ -369,7 +369,7 @@ class TestTrainingDashboard:
369
369
  assert r2_random < 1.0
370
370
 
371
371
  def test_experiment_status_distribution(self, sample_experiments):
372
- """Test experiment status distribution"""
372
+ """Test experiment status distribution."""
373
373
  status_counts = {}
374
374
  for exp in sample_experiments:
375
375
  status_counts[exp.status] = status_counts.get(exp.status, 0) + 1
@@ -381,10 +381,10 @@ class TestTrainingDashboard:
381
381
 
382
382
 
383
383
  class TestModelVersioning:
384
- """Test model versioning functionality"""
384
+ """Test model versioning functionality."""
385
385
 
386
386
  def test_version_comparison(self):
387
- """Test semantic version comparison"""
387
+ """Test semantic version comparison."""
388
388
  versions = ["1.0.0", "1.1.0", "1.0.1", "2.0.0", "1.2.0"]
389
389
 
390
390
  # Parse and sort versions
@@ -395,7 +395,7 @@ class TestModelVersioning:
395
395
  assert sorted_versions[-1] == (2, 0, 0)
396
396
 
397
397
  def test_model_deployment_tracking(self):
398
- """Test tracking which models are deployed"""
398
+ """Test tracking which models are deployed."""
399
399
  models = [
400
400
  {"name": "model-a", "version": "1.0.0", "deployed": True},
401
401
  {"name": "model-a", "version": "1.1.0", "deployed": False},
@@ -1,4 +1,4 @@
1
- """Trading module for portfolio management and trade execution"""
1
+ """Trading module for portfolio management and trade execution."""
2
2
 
3
3
  from mcli.ml.trading.alpaca_client import (
4
4
  AlpacaTradingClient,
@@ -1,4 +1,4 @@
1
- """Database migrations for trading functionality"""
1
+ """Database migrations for trading functionality."""
2
2
 
3
3
  import logging
4
4
 
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  def create_trading_tables():
15
- """Create trading-related tables in the database"""
15
+ """Create trading-related tables in the database."""
16
16
  try:
17
17
  # Get database URL from settings
18
18
  settings = get_settings()
@@ -30,7 +30,7 @@ def create_trading_tables():
30
30
 
31
31
 
32
32
  def drop_trading_tables():
33
- """Drop trading-related tables from the database"""
33
+ """Drop trading-related tables from the database."""
34
34
  try:
35
35
  # Get database URL from settings
36
36
  settings = get_settings()
@@ -48,7 +48,7 @@ def drop_trading_tables():
48
48
 
49
49
 
50
50
  def migrate_trading_data():
51
- """Migrate existing data to new trading schema"""
51
+ """Migrate existing data to new trading schema."""
52
52
  try:
53
53
  # Get database URL from settings
54
54
  settings = get_settings()
@@ -69,7 +69,7 @@ def migrate_trading_data():
69
69
 
70
70
 
71
71
  def verify_trading_schema():
72
- """Verify that trading schema is properly set up"""
72
+ """Verify that trading schema is properly set up."""
73
73
  try:
74
74
  # Get database URL from settings
75
75
  settings = get_settings()
mcli/ml/trading/models.py CHANGED
@@ -1,10 +1,8 @@
1
- """Trading and portfolio models for the ML system"""
1
+ """Trading and portfolio models for the ML system."""
2
2
 
3
- from dataclasses import dataclass, field
4
3
  from datetime import datetime
5
- from decimal import Decimal
6
4
  from enum import Enum
7
- from typing import Any, Dict, List, Optional, Union
5
+ from typing import List, Optional
8
6
  from uuid import UUID, uuid4
9
7
 
10
8
  from pydantic import BaseModel, Field
@@ -19,7 +17,7 @@ Base = declarative_base()
19
17
 
20
18
 
21
19
  class OrderStatus(Enum):
22
- """Order status enumeration"""
20
+ """Order status enumeration."""
23
21
 
24
22
  PENDING = "pending"
25
23
  SUBMITTED = "submitted"
@@ -31,7 +29,7 @@ class OrderStatus(Enum):
31
29
 
32
30
 
33
31
  class OrderType(Enum):
34
- """Order type enumeration"""
32
+ """Order type enumeration."""
35
33
 
36
34
  MARKET = "market"
37
35
  LIMIT = "limit"
@@ -41,21 +39,21 @@ class OrderType(Enum):
41
39
 
42
40
 
43
41
  class OrderSide(Enum):
44
- """Order side enumeration"""
42
+ """Order side enumeration."""
45
43
 
46
44
  BUY = "buy"
47
45
  SELL = "sell"
48
46
 
49
47
 
50
48
  class PositionSide(Enum):
51
- """Position side enumeration"""
49
+ """Position side enumeration."""
52
50
 
53
51
  LONG = "long"
54
52
  SHORT = "short"
55
53
 
56
54
 
57
55
  class PortfolioType(Enum):
58
- """Portfolio type enumeration"""
56
+ """Portfolio type enumeration."""
59
57
 
60
58
  TEST = "test"
61
59
  LIVE = "live"
@@ -63,7 +61,7 @@ class PortfolioType(Enum):
63
61
 
64
62
 
65
63
  class RiskLevel(Enum):
66
- """Risk level enumeration"""
64
+ """Risk level enumeration."""
67
65
 
68
66
  CONSERVATIVE = "conservative"
69
67
  MODERATE = "moderate"
@@ -72,7 +70,7 @@ class RiskLevel(Enum):
72
70
 
73
71
  # Database Models
74
72
  class TradingAccount(Base):
75
- """Trading account information"""
73
+ """Trading account information."""
76
74
 
77
75
  __tablename__ = "trading_accounts"
78
76
 
@@ -103,7 +101,7 @@ class TradingAccount(Base):
103
101
 
104
102
 
105
103
  class Portfolio(Base):
106
- """Portfolio information"""
104
+ """Portfolio information."""
107
105
 
108
106
  __tablename__ = "portfolios"
109
107
 
@@ -148,7 +146,7 @@ class Portfolio(Base):
148
146
 
149
147
 
150
148
  class Position(Base):
151
- """Individual position in a portfolio"""
149
+ """Individual position in a portfolio."""
152
150
 
153
151
  __tablename__ = "positions"
154
152
 
@@ -186,7 +184,7 @@ class Position(Base):
186
184
 
187
185
 
188
186
  class TradingOrder(Base):
189
- """Trading order information"""
187
+ """Trading order information."""
190
188
 
191
189
  __tablename__ = "trading_orders"
192
190
 
@@ -238,7 +236,7 @@ class TradingOrder(Base):
238
236
 
239
237
 
240
238
  class PortfolioPerformanceSnapshot(Base):
241
- """Daily portfolio performance snapshots"""
239
+ """Daily portfolio performance snapshots."""
242
240
 
243
241
  __tablename__ = "portfolio_performance_snapshots"
244
242
 
@@ -277,7 +275,7 @@ class PortfolioPerformanceSnapshot(Base):
277
275
 
278
276
 
279
277
  class TradingSignal(Base):
280
- """Trading signals generated by ML models"""
278
+ """Trading signals generated by ML models."""
281
279
 
282
280
  __tablename__ = "trading_signals"
283
281
 
@@ -318,7 +316,7 @@ class TradingSignal(Base):
318
316
 
319
317
  # Pydantic Models for API
320
318
  class TradingAccountCreate(BaseModel):
321
- """Create trading account request"""
319
+ """Create trading account request."""
322
320
 
323
321
  account_name: str = Field(..., min_length=1, max_length=100)
324
322
  account_type: PortfolioType = Field(default=PortfolioType.TEST)
@@ -331,7 +329,7 @@ class TradingAccountCreate(BaseModel):
331
329
 
332
330
 
333
331
  class PortfolioCreate(BaseModel):
334
- """Create portfolio request"""
332
+ """Create portfolio request."""
335
333
 
336
334
  name: str = Field(..., min_length=1, max_length=100)
337
335
  description: Optional[str] = None
@@ -339,7 +337,7 @@ class PortfolioCreate(BaseModel):
339
337
 
340
338
 
341
339
  class OrderCreate(BaseModel):
342
- """Create order request"""
340
+ """Create order request."""
343
341
 
344
342
  symbol: str = Field(..., min_length=1, max_length=10)
345
343
  side: OrderSide
@@ -352,7 +350,7 @@ class OrderCreate(BaseModel):
352
350
 
353
351
 
354
352
  class PositionResponse(BaseModel):
355
- """Position response model"""
353
+ """Position response model."""
356
354
 
357
355
  id: UUID
358
356
  symbol: str
@@ -372,7 +370,7 @@ class PositionResponse(BaseModel):
372
370
 
373
371
 
374
372
  class OrderResponse(BaseModel):
375
- """Order response model"""
373
+ """Order response model."""
376
374
 
377
375
  id: UUID
378
376
  symbol: str
@@ -395,7 +393,7 @@ class OrderResponse(BaseModel):
395
393
 
396
394
 
397
395
  class PortfolioResponse(BaseModel):
398
- """Portfolio response model"""
396
+ """Portfolio response model."""
399
397
 
400
398
  id: UUID
401
399
  name: str
@@ -418,7 +416,7 @@ class PortfolioResponse(BaseModel):
418
416
 
419
417
 
420
418
  class TradingSignalResponse(BaseModel):
421
- """Trading signal response model"""
419
+ """Trading signal response model."""
422
420
 
423
421
  id: UUID
424
422
  symbol: str
@@ -1,9 +1,9 @@
1
- """Paper trading implementation for testing portfolios without real money"""
1
+ """Paper trading implementation for testing portfolios without real money."""
2
2
 
3
3
  import logging
4
4
  from datetime import datetime, timedelta
5
5
  from decimal import Decimal
6
- from typing import Dict, List, Optional, Tuple
6
+ from typing import Dict, Optional
7
7
  from uuid import UUID
8
8
 
9
9
  import pandas as pd
@@ -15,6 +15,7 @@ from mcli.ml.trading.models import (
15
15
  OrderStatus,
16
16
  OrderType,
17
17
  Portfolio,
18
+ PortfolioCreate,
18
19
  Position,
19
20
  PositionSide,
20
21
  TradingOrder,
@@ -25,14 +26,14 @@ logger = logging.getLogger(__name__)
25
26
 
26
27
 
27
28
  class PaperTradingEngine:
28
- """Paper trading engine for testing strategies without real money"""
29
+ """Paper trading engine for testing strategies without real money."""
29
30
 
30
31
  def __init__(self, trading_service: TradingService):
31
32
  self.trading_service = trading_service
32
33
  self.db = trading_service.db
33
34
 
34
35
  def execute_paper_order(self, order: TradingOrder) -> bool:
35
- """Execute a paper trade order"""
36
+ """Execute a paper trade order."""
36
37
  try:
37
38
  # Get current market price
38
39
  current_price = self._get_current_price(order.symbol)
@@ -44,7 +45,9 @@ class PaperTradingEngine:
44
45
  if order.order_type == OrderType.MARKET:
45
46
  execution_price = current_price
46
47
  elif order.order_type == OrderType.LIMIT:
47
- if order.side == OrderSide.BUY and order.limit_price >= current_price:
48
+ if (
49
+ order.side == OrderSide.BUY and order.limit_price >= current_price
50
+ ): # noqa: SIM114
48
51
  execution_price = current_price
49
52
  elif order.side == OrderSide.SELL and order.limit_price <= current_price:
50
53
  execution_price = current_price
@@ -80,7 +83,7 @@ class PaperTradingEngine:
80
83
  return False
81
84
 
82
85
  def _get_current_price(self, symbol: str) -> Optional[float]:
83
- """Get current market price for a symbol"""
86
+ """Get current market price for a symbol."""
84
87
  try:
85
88
  ticker = yf.Ticker(symbol)
86
89
  data = ticker.history(period="1d", interval="1m")
@@ -92,7 +95,7 @@ class PaperTradingEngine:
92
95
  return None
93
96
 
94
97
  def _update_portfolio_positions(self, order: TradingOrder, execution_price: float):
95
- """Update portfolio positions after order execution"""
98
+ """Update portfolio positions after order execution."""
96
99
  try:
97
100
  portfolio = self.trading_service.get_portfolio(order.portfolio_id)
98
101
  if not portfolio:
@@ -190,7 +193,7 @@ class PaperTradingEngine:
190
193
  raise
191
194
 
192
195
  def _update_portfolio_value(self, portfolio: Portfolio):
193
- """Update portfolio value and metrics"""
196
+ """Update portfolio value and metrics."""
194
197
  try:
195
198
  # Get all positions
196
199
  positions = self.db.query(Position).filter(Position.portfolio_id == portfolio.id).all()
@@ -218,7 +221,7 @@ class PaperTradingEngine:
218
221
  raise
219
222
 
220
223
  def simulate_market_movement(self, portfolio_id: UUID, days: int = 1):
221
- """Simulate market movement for paper trading"""
224
+ """Simulate market movement for paper trading."""
222
225
  try:
223
226
  portfolio = self.trading_service.get_portfolio(portfolio_id)
224
227
  if not portfolio:
@@ -261,7 +264,7 @@ class PaperTradingEngine:
261
264
  def create_test_portfolio(
262
265
  self, user_id: UUID, name: str = "Test Portfolio", initial_capital: float = 100000.0
263
266
  ) -> Portfolio:
264
- """Create a test portfolio for paper trading"""
267
+ """Create a test portfolio for paper trading."""
265
268
  try:
266
269
  # Create trading account
267
270
  from mcli.ml.trading.models import TradingAccountCreate
@@ -293,7 +296,7 @@ class PaperTradingEngine:
293
296
  end_date: datetime,
294
297
  initial_capital: float = 100000.0,
295
298
  ) -> Dict:
296
- """Run a backtest on historical data"""
299
+ """Run a backtest on historical data."""
297
300
  try:
298
301
  portfolio = self.trading_service.get_portfolio(portfolio_id)
299
302
  if not portfolio:
@@ -309,7 +312,7 @@ class PaperTradingEngine:
309
312
  self.db.query(Position).filter(Position.portfolio_id == portfolio_id).delete()
310
313
 
311
314
  # Get historical data for the period
312
- date_range = pd.date_range(start=start_date, end=end_date, freq="D")
315
+ _date_range = pd.date_range(start=start_date, end=end_date, freq="D") # noqa: F841
313
316
 
314
317
  # This is a simplified backtest - in practice you'd want to:
315
318
  # 1. Get historical signals
@@ -339,6 +342,6 @@ class PaperTradingEngine:
339
342
 
340
343
 
341
344
  def create_paper_trading_engine(db_session: Session) -> PaperTradingEngine:
342
- """Create a paper trading engine"""
345
+ """Create a paper trading engine."""
343
346
  trading_service = TradingService(db_session)
344
347
  return PaperTradingEngine(trading_service)
@@ -1,29 +1,28 @@
1
- """Risk management module for trading portfolios"""
1
+ """Risk management module for trading portfolios."""
2
2
 
3
3
  import logging
4
- from datetime import datetime, timedelta
5
- from typing import Dict, List, Optional, Tuple
4
+ from datetime import datetime
5
+ from typing import Dict, List, Tuple
6
6
  from uuid import UUID
7
7
 
8
8
  import numpy as np
9
- import pandas as pd
10
9
  from sqlalchemy.orm import Session
11
10
 
12
- from mcli.ml.trading.models import Portfolio, Position, RiskLevel, TradingOrder
11
+ from mcli.ml.trading.models import Position, RiskLevel
13
12
  from mcli.ml.trading.trading_service import TradingService
14
13
 
15
14
  logger = logging.getLogger(__name__)
16
15
 
17
16
 
18
17
  class RiskManager:
19
- """Risk management system for trading portfolios"""
18
+ """Risk management system for trading portfolios."""
20
19
 
21
20
  def __init__(self, trading_service: TradingService):
22
21
  self.trading_service = trading_service
23
22
  self.db = trading_service.db
24
23
 
25
24
  def calculate_portfolio_risk(self, portfolio_id: UUID) -> Dict:
26
- """Calculate comprehensive risk metrics for a portfolio"""
25
+ """Calculate comprehensive risk metrics for a portfolio."""
27
26
  try:
28
27
  portfolio = self.trading_service.get_portfolio(portfolio_id)
29
28
  if not portfolio:
@@ -60,7 +59,7 @@ class RiskManager:
60
59
  return {}
61
60
 
62
61
  def _calculate_position_risk(self, position: Position, total_market_value: float) -> Dict:
63
- """Calculate risk metrics for an individual position"""
62
+ """Calculate risk metrics for an individual position."""
64
63
  try:
65
64
  # Position size as percentage of portfolio
66
65
  position_size_pct = (position.market_value / total_market_value) * 100
@@ -88,7 +87,7 @@ class RiskManager:
88
87
  return {}
89
88
 
90
89
  def _estimate_volatility(self, symbol: str, days: int = 30) -> float:
91
- """Estimate volatility for a symbol (simplified)"""
90
+ """Estimate volatility for a symbol (simplified)."""
92
91
  try:
93
92
  # In practice, you would calculate historical volatility
94
93
  # For now, use a simplified approach based on market cap and sector
@@ -117,7 +116,7 @@ class RiskManager:
117
116
  def _calculate_portfolio_risk_metrics(
118
117
  self, positions: List, position_risks: List[Dict]
119
118
  ) -> Dict:
120
- """Calculate portfolio-level risk metrics"""
119
+ """Calculate portfolio-level risk metrics."""
121
120
  try:
122
121
  if not positions or not position_risks:
123
122
  return {}
@@ -162,7 +161,7 @@ class RiskManager:
162
161
  return {}
163
162
 
164
163
  def _estimate_beta(self, symbol: str) -> float:
165
- """Estimate beta for a symbol (simplified)"""
164
+ """Estimate beta for a symbol (simplified)."""
166
165
  try:
167
166
  # In practice, calculate beta against market index
168
167
  # For now, use simplified estimates
@@ -186,7 +185,7 @@ class RiskManager:
186
185
  return 1.0
187
186
 
188
187
  def check_risk_limits(self, portfolio_id: UUID, new_order: Dict) -> Tuple[bool, List[str]]:
189
- """Check if a new order would violate risk limits"""
188
+ """Check if a new order would violate risk limits."""
190
189
  try:
191
190
  portfolio = self.trading_service.get_portfolio(portfolio_id)
192
191
  if not portfolio:
@@ -215,7 +214,7 @@ class RiskManager:
215
214
 
216
215
  # Check if adding to existing position
217
216
  existing_position = next((pos for pos in positions if pos.symbol == symbol), None)
218
- if existing_position:
217
+ if existing_position: # noqa: SIM102
219
218
  if side == "buy":
220
219
  new_total_size = (
221
220
  (existing_position.market_value + order_value)
@@ -248,7 +247,7 @@ class RiskManager:
248
247
  return False, [f"Risk check failed: {e}"]
249
248
 
250
249
  def _estimate_order_value(self, symbol: str, quantity: int) -> float:
251
- """Estimate the value of an order"""
250
+ """Estimate the value of an order."""
252
251
  try:
253
252
  import yfinance as yf
254
253
 
@@ -269,7 +268,7 @@ class RiskManager:
269
268
  signal_strength: float,
270
269
  risk_level: RiskLevel = RiskLevel.MODERATE,
271
270
  ) -> float:
272
- """Calculate recommended position size based on signal strength and risk level"""
271
+ """Calculate recommended position size based on signal strength and risk level."""
273
272
  try:
274
273
  portfolio = self.trading_service.get_portfolio(portfolio_id)
275
274
  if not portfolio:
@@ -303,7 +302,7 @@ class RiskManager:
303
302
  return 0.0
304
303
 
305
304
  def generate_risk_report(self, portfolio_id: UUID) -> Dict:
306
- """Generate comprehensive risk report for a portfolio"""
305
+ """Generate comprehensive risk report for a portfolio."""
307
306
  try:
308
307
  portfolio = self.trading_service.get_portfolio(portfolio_id)
309
308
  if not portfolio:
@@ -352,7 +351,7 @@ class RiskManager:
352
351
  return {}
353
352
 
354
353
  def _generate_risk_recommendations(self, risk_metrics: Dict, max_drawdown: float) -> List[str]:
355
- """Generate risk management recommendations"""
354
+ """Generate risk management recommendations."""
356
355
  recommendations = []
357
356
 
358
357
  # Concentration risk
@@ -386,6 +385,6 @@ class RiskManager:
386
385
 
387
386
 
388
387
  def create_risk_manager(db_session: Session) -> RiskManager:
389
- """Create a risk manager instance"""
388
+ """Create a risk manager instance."""
390
389
  trading_service = TradingService(db_session)
391
390
  return RiskManager(trading_service)