Spaces:
Running
Running
| from datetime import date, datetime | |
| from typing import Iterable | |
| from database.connection import connect | |
| class PredictionRepository: | |
| def __init__(self, database_url: str): | |
| self.database_url = database_url | |
| def connection(self): | |
| return connect(self.database_url) | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| # Predictions | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| def insert_predictions( | |
| self, | |
| predictions: Iterable[dict], | |
| ) -> int: | |
| sql = """ | |
| INSERT INTO predictions ( | |
| model_version, | |
| feature_version, | |
| prediction_date, | |
| prediction_timestamp, | |
| symbol, | |
| predicted_probability, | |
| rank, | |
| target_threshold, | |
| target_horizon_days, | |
| prediction_close | |
| ) | |
| VALUES ( | |
| :model_version, | |
| :feature_version, | |
| :prediction_date, | |
| :prediction_timestamp, | |
| :symbol, | |
| :predicted_probability, | |
| :rank, | |
| :target_threshold, | |
| :target_horizon_days, | |
| :prediction_close | |
| ) | |
| ON CONFLICT ( | |
| prediction_date, | |
| symbol, | |
| model_version | |
| ) | |
| DO NOTHING | |
| """ | |
| rows = list(predictions) | |
| if not rows: | |
| return 0 | |
| with self.connection() as conn: | |
| with conn.cursor() as cur: | |
| inserted = 0 | |
| for row in rows: | |
| cur.execute(sql.replace("DO NOTHING", "DO NOTHING RETURNING id"), row) | |
| if cur.fetchone() is not None: | |
| inserted += 1 | |
| return inserted | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| # Unresolved predictions | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| def get_unresolved_predictions(self): | |
| sql = """ | |
| SELECT * | |
| FROM predictions | |
| WHERE resolved_at IS NULL | |
| ORDER BY prediction_date, symbol | |
| """ | |
| with self.connection() as conn: | |
| with conn.cursor() as cur: | |
| cur.execute(sql) | |
| return cur.fetchall() | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| # Resolve prediction | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| def resolve_prediction( | |
| self, | |
| prediction_id: int, | |
| entry_date: date, | |
| entry_price: float, | |
| evaluation_end_date: date, | |
| max_future_close: float, | |
| actual_return: float, | |
| actual_label: int, | |
| ): | |
| sql = """ | |
| UPDATE predictions | |
| SET | |
| entry_date = :entry_date, | |
| entry_open = :entry_open, | |
| evaluation_end_date = :evaluation_end_date, | |
| max_close_5d = :max_close_5d, | |
| actual_return = :actual_return, | |
| actual_label = :actual_label, | |
| resolved_at = STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now') | |
| WHERE id = :prediction_id | |
| """ | |
| params = { | |
| "prediction_id": prediction_id, | |
| "entry_date": entry_date, | |
| "entry_open": entry_price, | |
| "evaluation_end_date": evaluation_end_date, | |
| "max_close_5d": max_future_close, | |
| "actual_return": actual_return, | |
| "actual_label": actual_label, | |
| } | |
| with self.connection() as conn: | |
| with conn.cursor() as cur: | |
| cur.execute(sql, params) | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| # Recent resolved predictions | |
| # βββββββββββββββββββββββββββββββββββββββββββββ | |
| def get_recent_resolved( | |
| self, | |
| days: int = 20, | |
| ): | |
| sql = """ | |
| SELECT * | |
| FROM predictions | |
| WHERE | |
| resolved_at IS NOT NULL | |
| AND prediction_date >= date('now', ?) | |
| ORDER BY prediction_date DESC | |
| """ | |
| with self.connection() as conn: | |
| with conn.cursor() as cur: | |
| cur.execute(sql, (f"-{days} days",)) | |
| return cur.fetchall() | |