mcli-framework 7.1.0__py3-none-any.whl → 7.1.2__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.
- mcli/app/completion_cmd.py +59 -49
- mcli/app/completion_helpers.py +60 -138
- mcli/app/logs_cmd.py +46 -13
- mcli/app/main.py +17 -14
- mcli/app/model_cmd.py +19 -4
- mcli/chat/chat.py +3 -2
- mcli/lib/search/cached_vectorizer.py +1 -0
- mcli/lib/services/data_pipeline.py +12 -5
- mcli/lib/services/lsh_client.py +69 -58
- mcli/ml/api/app.py +28 -36
- mcli/ml/api/middleware.py +8 -16
- mcli/ml/api/routers/admin_router.py +3 -1
- mcli/ml/api/routers/auth_router.py +32 -56
- mcli/ml/api/routers/backtest_router.py +3 -1
- mcli/ml/api/routers/data_router.py +3 -1
- mcli/ml/api/routers/model_router.py +35 -74
- mcli/ml/api/routers/monitoring_router.py +3 -1
- mcli/ml/api/routers/portfolio_router.py +3 -1
- mcli/ml/api/routers/prediction_router.py +60 -65
- mcli/ml/api/routers/trade_router.py +6 -2
- mcli/ml/api/routers/websocket_router.py +12 -9
- mcli/ml/api/schemas.py +10 -2
- mcli/ml/auth/auth_manager.py +49 -114
- mcli/ml/auth/models.py +30 -15
- mcli/ml/auth/permissions.py +12 -19
- mcli/ml/backtesting/backtest_engine.py +134 -108
- mcli/ml/backtesting/performance_metrics.py +142 -108
- mcli/ml/cache.py +12 -18
- mcli/ml/cli/main.py +37 -23
- mcli/ml/config/settings.py +29 -12
- mcli/ml/dashboard/app.py +122 -130
- mcli/ml/dashboard/app_integrated.py +283 -152
- mcli/ml/dashboard/app_supabase.py +176 -108
- mcli/ml/dashboard/app_training.py +212 -206
- mcli/ml/dashboard/cli.py +14 -5
- mcli/ml/data_ingestion/api_connectors.py +51 -81
- mcli/ml/data_ingestion/data_pipeline.py +127 -125
- mcli/ml/data_ingestion/stream_processor.py +72 -80
- mcli/ml/database/migrations/env.py +3 -2
- mcli/ml/database/models.py +112 -79
- mcli/ml/database/session.py +6 -5
- mcli/ml/experimentation/ab_testing.py +149 -99
- mcli/ml/features/ensemble_features.py +9 -8
- mcli/ml/features/political_features.py +6 -5
- mcli/ml/features/recommendation_engine.py +15 -14
- mcli/ml/features/stock_features.py +7 -6
- mcli/ml/features/test_feature_engineering.py +8 -7
- mcli/ml/logging.py +10 -15
- mcli/ml/mlops/data_versioning.py +57 -64
- mcli/ml/mlops/experiment_tracker.py +49 -41
- mcli/ml/mlops/model_serving.py +59 -62
- mcli/ml/mlops/pipeline_orchestrator.py +203 -149
- mcli/ml/models/base_models.py +8 -7
- mcli/ml/models/ensemble_models.py +6 -5
- mcli/ml/models/recommendation_models.py +7 -6
- mcli/ml/models/test_models.py +18 -14
- mcli/ml/monitoring/drift_detection.py +95 -74
- mcli/ml/monitoring/metrics.py +10 -22
- mcli/ml/optimization/portfolio_optimizer.py +172 -132
- mcli/ml/predictions/prediction_engine.py +235 -0
- mcli/ml/preprocessing/data_cleaners.py +6 -5
- mcli/ml/preprocessing/feature_extractors.py +7 -6
- mcli/ml/preprocessing/ml_pipeline.py +3 -2
- mcli/ml/preprocessing/politician_trading_preprocessor.py +11 -10
- mcli/ml/preprocessing/test_preprocessing.py +4 -4
- mcli/ml/scripts/populate_sample_data.py +36 -16
- mcli/ml/tasks.py +82 -83
- mcli/ml/tests/test_integration.py +86 -76
- mcli/ml/tests/test_training_dashboard.py +169 -142
- mcli/mygroup/test_cmd.py +2 -1
- mcli/self/self_cmd.py +38 -18
- mcli/self/test_cmd.py +2 -1
- mcli/workflow/dashboard/dashboard_cmd.py +13 -6
- mcli/workflow/lsh_integration.py +46 -58
- mcli/workflow/politician_trading/commands.py +576 -427
- mcli/workflow/politician_trading/config.py +7 -7
- mcli/workflow/politician_trading/connectivity.py +35 -33
- mcli/workflow/politician_trading/data_sources.py +72 -71
- mcli/workflow/politician_trading/database.py +18 -16
- mcli/workflow/politician_trading/demo.py +4 -3
- mcli/workflow/politician_trading/models.py +5 -5
- mcli/workflow/politician_trading/monitoring.py +13 -13
- mcli/workflow/politician_trading/scrapers.py +332 -224
- mcli/workflow/politician_trading/scrapers_california.py +116 -94
- mcli/workflow/politician_trading/scrapers_eu.py +70 -71
- mcli/workflow/politician_trading/scrapers_uk.py +118 -90
- mcli/workflow/politician_trading/scrapers_us_states.py +125 -92
- mcli/workflow/politician_trading/workflow.py +98 -71
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/METADATA +2 -2
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/RECORD +94 -93
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/WHEEL +0 -0
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/entry_points.txt +0 -0
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/licenses/LICENSE +0 -0
- {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/top_level.txt +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"""Prediction API routes"""
|
|
2
2
|
|
|
3
|
-
from typing import List, Optional
|
|
4
3
|
from datetime import datetime, timedelta
|
|
4
|
+
from typing import List, Optional
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
|
-
from fastapi import APIRouter, Depends, HTTPException,
|
|
8
|
-
from sqlalchemy.orm import Session
|
|
7
|
+
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, status
|
|
9
8
|
from pydantic import BaseModel
|
|
9
|
+
from sqlalchemy.orm import Session
|
|
10
10
|
|
|
11
|
+
from mcli.ml.api.schemas import BatchPredictionRequest, PredictionRequest, PredictionResponse
|
|
11
12
|
from mcli.ml.auth import get_current_active_user
|
|
13
|
+
from mcli.ml.cache import cache_set, cached
|
|
14
|
+
from mcli.ml.database.models import Model, Prediction, StockData, User
|
|
12
15
|
from mcli.ml.database.session import get_db
|
|
13
|
-
from mcli.ml.database.models import User, Prediction, Model, StockData
|
|
14
|
-
from mcli.ml.api.schemas import PredictionRequest, PredictionResponse, BatchPredictionRequest
|
|
15
|
-
from mcli.ml.cache import cached, cache_set
|
|
16
16
|
from mcli.ml.models import get_model_by_id
|
|
17
17
|
|
|
18
18
|
router = APIRouter()
|
|
@@ -30,7 +30,7 @@ async def create_prediction(
|
|
|
30
30
|
request: PredictionInput,
|
|
31
31
|
background_tasks: BackgroundTasks,
|
|
32
32
|
current_user: User = Depends(get_current_active_user),
|
|
33
|
-
db: Session = Depends(get_db)
|
|
33
|
+
db: Session = Depends(get_db),
|
|
34
34
|
):
|
|
35
35
|
"""Create a new prediction"""
|
|
36
36
|
|
|
@@ -38,20 +38,20 @@ async def create_prediction(
|
|
|
38
38
|
if request.model_id:
|
|
39
39
|
model = db.query(Model).filter(Model.id == request.model_id).first()
|
|
40
40
|
if not model:
|
|
41
|
-
raise HTTPException(
|
|
42
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
43
|
-
detail="Model not found"
|
|
44
|
-
)
|
|
41
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Model not found")
|
|
45
42
|
else:
|
|
46
43
|
# Get default deployed model
|
|
47
|
-
model =
|
|
48
|
-
Model
|
|
49
|
-
|
|
44
|
+
model = (
|
|
45
|
+
db.query(Model)
|
|
46
|
+
.filter(Model.status == "deployed")
|
|
47
|
+
.order_by(Model.deployed_at.desc())
|
|
48
|
+
.first()
|
|
49
|
+
)
|
|
50
50
|
|
|
51
51
|
if not model:
|
|
52
52
|
raise HTTPException(
|
|
53
53
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
54
|
-
detail="No deployed model available"
|
|
54
|
+
detail="No deployed model available",
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
# Load model
|
|
@@ -59,6 +59,7 @@ async def create_prediction(
|
|
|
59
59
|
|
|
60
60
|
# Make prediction
|
|
61
61
|
import numpy as np
|
|
62
|
+
|
|
62
63
|
features_array = np.array(list(request.features.values())).reshape(1, -1)
|
|
63
64
|
predicted_return = float(ml_model.predict(features_array)[0])
|
|
64
65
|
|
|
@@ -74,7 +75,7 @@ async def create_prediction(
|
|
|
74
75
|
target_date=datetime.utcnow() + timedelta(days=request.horizon),
|
|
75
76
|
predicted_return=predicted_return,
|
|
76
77
|
confidence_score=confidence_score,
|
|
77
|
-
feature_importance=request.features
|
|
78
|
+
feature_importance=request.features,
|
|
78
79
|
)
|
|
79
80
|
|
|
80
81
|
db.add(prediction)
|
|
@@ -95,7 +96,7 @@ async def create_prediction(
|
|
|
95
96
|
confidence_score=prediction.confidence_score,
|
|
96
97
|
target_date=prediction.target_date,
|
|
97
98
|
model_id=model.id,
|
|
98
|
-
model_name=model.name
|
|
99
|
+
model_name=model.name,
|
|
99
100
|
)
|
|
100
101
|
|
|
101
102
|
|
|
@@ -104,7 +105,7 @@ async def create_batch_predictions(
|
|
|
104
105
|
request: BatchPredictionRequest,
|
|
105
106
|
background_tasks: BackgroundTasks,
|
|
106
107
|
current_user: User = Depends(get_current_active_user),
|
|
107
|
-
db: Session = Depends(get_db)
|
|
108
|
+
db: Session = Depends(get_db),
|
|
108
109
|
):
|
|
109
110
|
"""Create predictions for multiple tickers"""
|
|
110
111
|
predictions = []
|
|
@@ -114,15 +115,10 @@ async def create_batch_predictions(
|
|
|
114
115
|
ticker=ticker_data.ticker,
|
|
115
116
|
features=ticker_data.features,
|
|
116
117
|
model_id=request.model_id,
|
|
117
|
-
horizon=request.horizon
|
|
118
|
+
horizon=request.horizon,
|
|
118
119
|
)
|
|
119
120
|
|
|
120
|
-
pred = await create_prediction(
|
|
121
|
-
pred_input,
|
|
122
|
-
background_tasks,
|
|
123
|
-
current_user,
|
|
124
|
-
db
|
|
125
|
-
)
|
|
121
|
+
pred = await create_prediction(pred_input, background_tasks, current_user, db)
|
|
126
122
|
predictions.append(pred)
|
|
127
123
|
|
|
128
124
|
return predictions
|
|
@@ -137,7 +133,7 @@ async def list_predictions(
|
|
|
137
133
|
start_date: Optional[datetime] = None,
|
|
138
134
|
end_date: Optional[datetime] = None,
|
|
139
135
|
current_user: User = Depends(get_current_active_user),
|
|
140
|
-
db: Session = Depends(get_db)
|
|
136
|
+
db: Session = Depends(get_db),
|
|
141
137
|
):
|
|
142
138
|
"""List user's predictions"""
|
|
143
139
|
query = db.query(Prediction).filter(Prediction.user_id == current_user.id)
|
|
@@ -151,9 +147,7 @@ async def list_predictions(
|
|
|
151
147
|
if end_date:
|
|
152
148
|
query = query.filter(Prediction.prediction_date <= end_date)
|
|
153
149
|
|
|
154
|
-
predictions = query.order_by(
|
|
155
|
-
Prediction.prediction_date.desc()
|
|
156
|
-
).offset(skip).limit(limit).all()
|
|
150
|
+
predictions = query.order_by(Prediction.prediction_date.desc()).offset(skip).limit(limit).all()
|
|
157
151
|
|
|
158
152
|
return [PredictionResponse.from_orm(p) for p in predictions]
|
|
159
153
|
|
|
@@ -163,19 +157,17 @@ async def list_predictions(
|
|
|
163
157
|
async def get_prediction(
|
|
164
158
|
prediction_id: UUID,
|
|
165
159
|
current_user: User = Depends(get_current_active_user),
|
|
166
|
-
db: Session = Depends(get_db)
|
|
160
|
+
db: Session = Depends(get_db),
|
|
167
161
|
):
|
|
168
162
|
"""Get specific prediction details"""
|
|
169
|
-
prediction =
|
|
170
|
-
Prediction
|
|
171
|
-
Prediction.user_id == current_user.id
|
|
172
|
-
|
|
163
|
+
prediction = (
|
|
164
|
+
db.query(Prediction)
|
|
165
|
+
.filter(Prediction.id == prediction_id, Prediction.user_id == current_user.id)
|
|
166
|
+
.first()
|
|
167
|
+
)
|
|
173
168
|
|
|
174
169
|
if not prediction:
|
|
175
|
-
raise HTTPException(
|
|
176
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
177
|
-
detail="Prediction not found"
|
|
178
|
-
)
|
|
170
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Prediction not found")
|
|
179
171
|
|
|
180
172
|
return PredictionResponse.from_orm(prediction)
|
|
181
173
|
|
|
@@ -184,26 +176,24 @@ async def get_prediction(
|
|
|
184
176
|
async def get_prediction_outcome(
|
|
185
177
|
prediction_id: UUID,
|
|
186
178
|
current_user: User = Depends(get_current_active_user),
|
|
187
|
-
db: Session = Depends(get_db)
|
|
179
|
+
db: Session = Depends(get_db),
|
|
188
180
|
):
|
|
189
181
|
"""Get actual outcome of a prediction"""
|
|
190
|
-
prediction =
|
|
191
|
-
Prediction
|
|
192
|
-
Prediction.user_id == current_user.id
|
|
193
|
-
|
|
182
|
+
prediction = (
|
|
183
|
+
db.query(Prediction)
|
|
184
|
+
.filter(Prediction.id == prediction_id, Prediction.user_id == current_user.id)
|
|
185
|
+
.first()
|
|
186
|
+
)
|
|
194
187
|
|
|
195
188
|
if not prediction:
|
|
196
|
-
raise HTTPException(
|
|
197
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
198
|
-
detail="Prediction not found"
|
|
199
|
-
)
|
|
189
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Prediction not found")
|
|
200
190
|
|
|
201
191
|
# Check if target date has passed
|
|
202
192
|
if prediction.target_date > datetime.utcnow():
|
|
203
193
|
return {
|
|
204
194
|
"status": "pending",
|
|
205
195
|
"message": "Target date has not been reached yet",
|
|
206
|
-
"target_date": prediction.target_date
|
|
196
|
+
"target_date": prediction.target_date,
|
|
207
197
|
}
|
|
208
198
|
|
|
209
199
|
# Get actual return (mock for now)
|
|
@@ -219,7 +209,7 @@ async def get_prediction_outcome(
|
|
|
219
209
|
"predicted_return": prediction.predicted_return,
|
|
220
210
|
"actual_return": actual_return,
|
|
221
211
|
"error": abs(prediction.predicted_return - actual_return),
|
|
222
|
-
"accuracy": 1 - abs(prediction.predicted_return - actual_return) / abs(actual_return)
|
|
212
|
+
"accuracy": 1 - abs(prediction.predicted_return - actual_return) / abs(actual_return),
|
|
223
213
|
}
|
|
224
214
|
|
|
225
215
|
|
|
@@ -229,17 +219,20 @@ async def get_latest_recommendations(
|
|
|
229
219
|
limit: int = Query(10, le=50),
|
|
230
220
|
min_confidence: float = Query(0.7, ge=0, le=1),
|
|
231
221
|
current_user: User = Depends(get_current_active_user),
|
|
232
|
-
db: Session = Depends(get_db)
|
|
222
|
+
db: Session = Depends(get_db),
|
|
233
223
|
):
|
|
234
224
|
"""Get latest stock recommendations"""
|
|
235
225
|
# Get recent predictions with high confidence
|
|
236
|
-
predictions =
|
|
237
|
-
Prediction
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
226
|
+
predictions = (
|
|
227
|
+
db.query(Prediction)
|
|
228
|
+
.filter(
|
|
229
|
+
Prediction.confidence_score >= min_confidence,
|
|
230
|
+
Prediction.prediction_date >= datetime.utcnow() - timedelta(days=1),
|
|
231
|
+
)
|
|
232
|
+
.order_by(Prediction.confidence_score.desc(), Prediction.predicted_return.desc())
|
|
233
|
+
.limit(limit)
|
|
234
|
+
.all()
|
|
235
|
+
)
|
|
243
236
|
|
|
244
237
|
recommendations = []
|
|
245
238
|
for pred in predictions:
|
|
@@ -247,13 +240,15 @@ async def get_latest_recommendations(
|
|
|
247
240
|
if pred.predicted_return < -0.02:
|
|
248
241
|
action = "sell"
|
|
249
242
|
|
|
250
|
-
recommendations.append(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
243
|
+
recommendations.append(
|
|
244
|
+
{
|
|
245
|
+
"ticker": pred.ticker,
|
|
246
|
+
"action": action,
|
|
247
|
+
"predicted_return": pred.predicted_return,
|
|
248
|
+
"confidence": pred.confidence_score,
|
|
249
|
+
"target_date": pred.target_date,
|
|
250
|
+
}
|
|
251
|
+
)
|
|
257
252
|
|
|
258
253
|
return recommendations
|
|
259
254
|
|
|
@@ -264,4 +259,4 @@ async def update_stock_data(ticker: str, db: Session):
|
|
|
264
259
|
stock = db.query(StockData).filter(StockData.ticker == ticker).first()
|
|
265
260
|
if stock:
|
|
266
261
|
stock.last_updated = datetime.utcnow()
|
|
267
|
-
db.commit()
|
|
262
|
+
db.commit()
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"""Trading API routes"""
|
|
2
2
|
|
|
3
3
|
from fastapi import APIRouter, Depends
|
|
4
|
+
|
|
4
5
|
from mcli.ml.auth import get_current_active_user
|
|
5
6
|
from mcli.ml.database.models import User
|
|
6
7
|
|
|
7
8
|
router = APIRouter()
|
|
8
9
|
|
|
10
|
+
|
|
9
11
|
@router.get("/politician/{politician_id}")
|
|
10
|
-
async def get_politician_trades(
|
|
12
|
+
async def get_politician_trades(
|
|
13
|
+
politician_id: str, current_user: User = Depends(get_current_active_user)
|
|
14
|
+
):
|
|
11
15
|
"""Get politician trades"""
|
|
12
|
-
return {"politician_id": politician_id, "trades": []}
|
|
16
|
+
return {"politician_id": politician_id, "trades": []}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""WebSocket API routes for real-time updates"""
|
|
2
2
|
|
|
3
|
-
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends
|
|
4
|
-
from typing import Dict, Set
|
|
5
|
-
import json
|
|
6
3
|
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
from typing import Dict, Set
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
|
|
7
8
|
|
|
8
9
|
from mcli.ml.logging import get_logger
|
|
9
10
|
|
|
@@ -67,10 +68,12 @@ async def websocket_prices(websocket: WebSocket):
|
|
|
67
68
|
while True:
|
|
68
69
|
await asyncio.sleep(1)
|
|
69
70
|
# Send mock price update
|
|
70
|
-
await websocket.send_json(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
await websocket.send_json(
|
|
72
|
+
{
|
|
73
|
+
"type": "price_update",
|
|
74
|
+
"ticker": "AAPL",
|
|
75
|
+
"price": 150.00 + (asyncio.get_event_loop().time() % 10),
|
|
76
|
+
}
|
|
77
|
+
)
|
|
75
78
|
except WebSocketDisconnect:
|
|
76
|
-
manager.disconnect(websocket, "prices")
|
|
79
|
+
manager.disconnect(websocket, "prices")
|
mcli/ml/api/schemas.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""API request/response schemas"""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
5
|
from uuid import UUID
|
|
6
|
+
|
|
6
7
|
from pydantic import BaseModel, Field
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
# Model schemas
|
|
9
11
|
class ModelCreate(BaseModel):
|
|
10
12
|
name: str
|
|
@@ -13,11 +15,13 @@ class ModelCreate(BaseModel):
|
|
|
13
15
|
description: Optional[str] = None
|
|
14
16
|
hyperparameters: Dict[str, Any] = {}
|
|
15
17
|
|
|
18
|
+
|
|
16
19
|
class ModelUpdate(BaseModel):
|
|
17
20
|
name: Optional[str] = None
|
|
18
21
|
description: Optional[str] = None
|
|
19
22
|
tags: Optional[List[str]] = None
|
|
20
23
|
|
|
24
|
+
|
|
21
25
|
class ModelResponse(BaseModel):
|
|
22
26
|
id: UUID
|
|
23
27
|
name: str
|
|
@@ -30,6 +34,7 @@ class ModelResponse(BaseModel):
|
|
|
30
34
|
class Config:
|
|
31
35
|
orm_mode = True
|
|
32
36
|
|
|
37
|
+
|
|
33
38
|
class ModelMetrics(BaseModel):
|
|
34
39
|
model_id: UUID
|
|
35
40
|
train_accuracy: Optional[float]
|
|
@@ -40,17 +45,20 @@ class ModelMetrics(BaseModel):
|
|
|
40
45
|
test_loss: Optional[float]
|
|
41
46
|
additional_metrics: Dict[str, Any]
|
|
42
47
|
|
|
48
|
+
|
|
43
49
|
# Prediction schemas
|
|
44
50
|
class PredictionRequest(BaseModel):
|
|
45
51
|
ticker: str
|
|
46
52
|
features: Dict[str, float]
|
|
47
53
|
model_id: Optional[UUID] = None
|
|
48
54
|
|
|
55
|
+
|
|
49
56
|
class BatchPredictionRequest(BaseModel):
|
|
50
57
|
tickers: List[PredictionRequest]
|
|
51
58
|
model_id: Optional[UUID] = None
|
|
52
59
|
horizon: int = 1
|
|
53
60
|
|
|
61
|
+
|
|
54
62
|
class PredictionResponse(BaseModel):
|
|
55
63
|
id: UUID
|
|
56
64
|
ticker: str
|
|
@@ -61,4 +69,4 @@ class PredictionResponse(BaseModel):
|
|
|
61
69
|
model_name: str
|
|
62
70
|
|
|
63
71
|
class Config:
|
|
64
|
-
orm_mode = True
|
|
72
|
+
orm_mode = True
|