{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":96164,"databundleVersionId":12993472,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 1. Importing Libraries & Loading the Data\n\nIn this section, we import all essential Python libraries commonly used for data analysis, visualization, and modeling. We also load the training and test datasets from the provided `.parquet` files.\n\nThese datasets contain minute-level trading data for the crypto market, and our objective is to **predict future market price movements**, represented by the `label` column in `train.parquet`.\n\nWe’ll begin by loading and inspecting the shape and structure of both datasets.\n","metadata":{}},{"cell_type":"code","source":"# Core data handling libraries\nimport pandas as pd\nimport numpy as np\n\n# Visualization libraries\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Machine learning tools\nfrom sklearn.model_selection import train_test_split, TimeSeriesSplit\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import mean_squared_error\nimport lightgbm as lgb\nfrom lightgbm import early_stopping, log_evaluation\n# Set default aesthetics for plots\nsns.set(style=\"whitegrid\")\nplt.rcParams['figure.figsize'] = (12, 6)\n\n# Load data\ntrain = pd.read_parquet('/kaggle/input/drw-crypto-market-prediction/train.parquet')\ntest = pd.read_parquet('/kaggle/input/drw-crypto-market-prediction/test.parquet')\n\n# Inspect dimensions and structure\nprint(f\"✅ Training set shape: {train.shape}\")\nprint(f\"✅ Test set shape: {test.shape}\")\ndisplay(train.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:27:12.501064Z","iopub.execute_input":"2025-07-20T06:27:12.501802Z","iopub.status.idle":"2025-07-20T06:27:40.197371Z","shell.execute_reply.started":"2025-07-20T06:27:12.501765Z","shell.execute_reply":"2025-07-20T06:27:40.196618Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Output Analysis\n\n- `train.shape` and `test.shape` show us how many rows and features each dataset has.\n- Use `train.head()` to preview the first few rows — this includes:\n  - Timestamps (minute-level index),\n  - Market signals (`bid_qty`, `ask_qty`, etc.),\n  - 780 anonymized features (`X_1` to `X_780`),\n  - Target: `label` (price movement to predict).\n- This gives us a foundational understanding of the structure before we explore deeper.\n\n- Training set has 525,886 rows and 786 columns\n\n- Test set has 538,150 rows and same 786 features\n\n- label column is at the end\n\n- Features like bid_qty, ask_qty, buy_qty, etc. are present\n\n- Anonymized feature columns: X1 to X780","metadata":{}},{"cell_type":"markdown","source":"# 2. Dataset Summary & Missing Values Check\n\nIn this section, we examine:\n- Summary statistics for key market and anonymized features\n- Any missing values in the training dataset\n\nThis helps us decide if we need data cleaning or imputation steps before modeling.\n","metadata":{}},{"cell_type":"code","source":"# Select key market columns and sample anonymized columns\nmarket_columns = ['bid_qty', 'ask_qty', 'buy_qty', 'sell_qty', 'volume']\nanonymized_sample = [f'X{i}' for i in range(1, 6)]  # Sample only first 5 anonymized features\n\n# Summary statistics\nsummary_stats = train[market_columns + anonymized_sample + ['label']].describe().T\n\n# Check for missing values\nmissing_values = train.isnull().sum()\nmissing_values = missing_values[missing_values > 0].sort_values(ascending=False)\n\n# Display outputs\ndisplay(summary_stats)\ndisplay(missing_values if not missing_values.empty else \"No missing values found.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:19:33.087508Z","iopub.execute_input":"2025-07-20T06:19:33.088134Z","iopub.status.idle":"2025-07-20T06:19:34.845968Z","shell.execute_reply.started":"2025-07-20T06:19:33.088107Z","shell.execute_reply":"2025-07-20T06:19:34.845132Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Summary Statistics – Observations\n\n- **Market Features**:\n  - `bid_qty`, `ask_qty`, `buy_qty`, `sell_qty`, `volume` show significant variance, especially `volume` (std ~588 vs mean ~264), indicating volatility typical of crypto markets.\n  - All quantities start from a minimum of 0 or near 0, which makes sense for sparse minutes.\n  - Some extreme max values (e.g., `volume` > 28,000 and `ask_qty` > 1,300) may represent outliers or high-activity minutes.\n\n- **Anonymized Features (X1–X5)**:\n  - All means are close to zero with standard deviations close to 1, suggesting they are likely **standardized features**.\n  - Values range widely — for example, `X3` ranges from ~-7.4 to ~8.5.\n  - No obvious feature has zero variance, so all contribute potentially useful signals.\n\n- **Target Variable `label`**:\n  - Mean is close to 0 — consistent with predicting change in market price.\n  - High skew and kurtosis: range is wide from -24.41 to +20.74.\n  - Likely a **heavy-tailed distribution**, so we may need robust metrics like MAE or Huber loss.\n\n- No missing values were found, so we can proceed without imputation.\n\n---\n\nNext, we’ll explore the **distribution of the label** and its correlation with selected features.\n","metadata":{}},{"cell_type":"markdown","source":"# 3. Target Variable Exploration\n\nIn this section, we:\n\n- Visualize the distribution of the `label`, which is the value we’re predicting.\n- Analyze how the `label` correlates with market activity features (`bid_qty`, `ask_qty`, `volume`, etc.) and a few anonymized features.\n\nThis helps us understand:\n- Whether the target is skewed.\n- Which features may have predictive power based on linear correlation.","metadata":{}},{"cell_type":"code","source":"# Plot the distribution of the target label\nplt.figure(figsize=(10, 5))\nsns.histplot(train['label'], bins=100, kde=True, color='orange')\nplt.title(\"Distribution of Target Variable: label\", fontsize=14)\nplt.xlabel(\"Label Value\")\nplt.ylabel(\"Frequency\")\nplt.grid(True)\nplt.show()\n\n# Correlation with label (only a few select features to keep it readable)\nselected_features = ['bid_qty', 'ask_qty', 'buy_qty', 'sell_qty', 'volume'] + [f'X{i}' for i in range(1, 6)]\ncorrelation_with_label = train[selected_features + ['label']].corr()['label'].sort_values(ascending=False)\n\n# Display top 10 most positively and negatively correlated\ndisplay(correlation_with_label.head(10))\ndisplay(correlation_with_label.tail(10))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:21:22.529462Z","iopub.execute_input":"2025-07-20T06:21:22.529867Z","iopub.status.idle":"2025-07-20T06:21:25.829896Z","shell.execute_reply.started":"2025-07-20T06:21:22.529827Z","shell.execute_reply":"2025-07-20T06:21:25.828915Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Target Variable Insights\n\n### 🔹 Label Distribution:\n- The `label` (target) is **tightly centered around zero**, forming a sharp peak.\n- This distribution suggests:\n  - Most price movements are small in magnitude (micro-changes per minute).\n  - Only a few data points represent extreme market movements.\n- It has **heavy tails**, indicating the presence of outliers — something to consider for model robustness.\n\n### 🔹 Feature Correlations:\n- All correlations with the `label` are **very weak**, with values close to 0 (both positive and negative).\n- Highest absolute correlations:\n  - `X2` (0.0157), `X3` (0.0122), and `sell_qty` (0.0112).\n- This suggests:\n  - **Linear correlations are low**, but that doesn't rule out **non-linear relationships**.\n  - We'll rely on models that can detect **complex patterns** (e.g., tree-based methods).\n\n\nNext, we’ll engineer a few interpretable features like bid-ask spread, order imbalance, and volume ratios to improve signal for modeling.\n","metadata":{}},{"cell_type":"markdown","source":"# 4. Feature Engineering – Creating Derived Market Features\n\nSince the anonymized features (`X1–X780`) offer no direct interpretability, we enhance the dataset with interpretable features derived from:\n- Market liquidity\n- Supply-demand imbalance\n- Execution volume ratios\n\nThese features can help models detect trading pressure, imbalance, or volatility spikes, all of which may relate to price movement (`label`).","metadata":{}},{"cell_type":"code","source":"# Copy the dataframe to preserve original\ntrain_fe = train.copy()\n\n# 1. Bid-Ask Spread\ntrain_fe['bid_ask_spread'] = train_fe['ask_qty'] - train_fe['bid_qty']\n\n# 2. Buy-Sell Volume Imbalance\ntrain_fe['volume_imbalance'] = (train_fe['buy_qty'] - train_fe['sell_qty']) / (train_fe['buy_qty'] + train_fe['sell_qty'] + 1e-6)\n\n# 3. Normalized volume\ntrain_fe['log_volume'] = np.log1p(train_fe['volume'])\n\n# 4. Ratio-based features\ntrain_fe['buy_to_volume_ratio'] = train_fe['buy_qty'] / (train_fe['volume'] + 1e-6)\ntrain_fe['sell_to_volume_ratio'] = train_fe['sell_qty'] / (train_fe['volume'] + 1e-6)\n\n# Display new feature distributions\nnew_features = ['bid_ask_spread', 'volume_imbalance', 'log_volume', 'buy_to_volume_ratio', 'sell_to_volume_ratio']\ndisplay(train_fe[new_features].describe().T)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:23:20.461832Z","iopub.execute_input":"2025-07-20T06:23:20.462177Z","iopub.status.idle":"2025-07-20T06:23:23.813563Z","shell.execute_reply.started":"2025-07-20T06:23:20.462147Z","shell.execute_reply":"2025-07-20T06:23:23.812739Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Engineered Feature Summary\n\nWe've derived 5 new interpretable features from raw market signals:\n\n### 🔹 `bid_ask_spread`\n- Measures the difference between seller ask and buyer bid volumes.\n- High standard deviation and wide range (from -1096 to +1143) — some extreme mismatches suggest unusual trading conditions or outliers.\n\n### 🔹 `volume_imbalance`\n- Reflects supply-demand pressure: values closer to ±1 indicate one-sided trading (either strong buying or strong selling).\n- Median close to 0 → market is usually balanced.\n\n### 🔹 `log_volume`\n- Log-transform of volume to reduce skew and outlier impact.\n- Appears well-behaved and scaled for modeling.\n\n### 🔹 `buy_to_volume_ratio` & `sell_to_volume_ratio`\n- Normalized measures of directional trading pressure.\n- Median ~0.5 for both — consistent with a mostly balanced market.\n\nThese engineered features add intuitive signals beyond the anonymized `X` variables and will be part of our final model.","metadata":{}},{"cell_type":"markdown","source":"# 5. Baseline LightGBM Model – Time-Aware Validation\n\nWe’ll now build a baseline regression model using **LightGBM**.\n\nKey considerations:\n- We use a **time-based split** to avoid data leakage.\n- Only a **subset of features** is used: the engineered ones and a few anonymized features.\n- The target variable is `label`, which is continuous.\n\nThis baseline gives us a starting point for model performance and later hyperparameter tuning.\n","metadata":{}},{"cell_type":"code","source":"# Step 1: Feature selection (same)\nfeature_cols = [\n    'bid_ask_spread', 'volume_imbalance', 'log_volume',\n    'buy_to_volume_ratio', 'sell_to_volume_ratio',\n    'X1', 'X2', 'X3', 'X4', 'X5'\n]\n\n# Step 2: Time-based split\ntrain_cutoff = int(len(train_fe) * 0.8)\nX_train, X_val = train_fe[feature_cols].iloc[:train_cutoff], train_fe[feature_cols].iloc[train_cutoff:]\ny_train, y_val = train_fe['label'].iloc[:train_cutoff], train_fe['label'].iloc[train_cutoff:]\n\n# Step 3: Train model with callbacks\nmodel = lgb.LGBMRegressor(n_estimators=200, learning_rate=0.05, random_state=42)\n\nmodel.fit(\n    X_train, y_train,\n    eval_set=[(X_val, y_val)],\n    eval_metric='rmse',\n    callbacks=[\n        early_stopping(stopping_rounds=20),\n        log_evaluation(period=50)  # Logs every 50 iterations\n    ]\n)\n\n# Step 4: Evaluate\ny_pred = model.predict(X_val)\nrmse = mean_squared_error(y_val, y_pred, squared=False)\nprint(f\"📉 Validation RMSE: {rmse:.5f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:28:41.671741Z","iopub.execute_input":"2025-07-20T06:28:41.672389Z","iopub.status.idle":"2025-07-20T06:28:42.857181Z","shell.execute_reply.started":"2025-07-20T06:28:41.672358Z","shell.execute_reply":"2025-07-20T06:28:42.856295Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Baseline LightGBM Results\n\n- Model trained with early stopping after just **5 boosting rounds**.\n- **Validation RMSE = 1.04047**, which represents the average magnitude of prediction error on unseen data.\n\n### Observations:\n- The model converged quickly, which may imply:\n  - The feature signal is limited in this subset.\n  - A small learning rate with early stopping halts before full learning.\n- Only **10 features** were used — we’re keeping it intentionally simple to benchmark future improvements.\n\nThis result establishes a baseline. We’ll now apply this model to the test set and generate a submission file.\n","metadata":{}},{"cell_type":"markdown","source":"# 6. Generate Test Predictions & Submission File\n\nIn this step:\n- We apply the trained LightGBM model to the test set using the same selected features.\n- We then construct a valid `submission.csv` in the format required by the competition:\n  - Column 1: `ID` (from test set)\n  - Column 2: `prediction` (our model's output)\n\nThis file can now be submitted to Kaggle for evaluation on the private test set.\n","metadata":{}},{"cell_type":"code","source":"# Step 1: Load sample submission\nsample_submission = pd.read_csv('/kaggle/input/drw-crypto-market-prediction/sample_submission.csv')\n\n# Create engineered features in the test set\ntest_fe = test.copy()\n\ntest_fe['bid_ask_spread'] = test_fe['ask_qty'] - test_fe['bid_qty']\ntest_fe['volume_imbalance'] = (test_fe['buy_qty'] - test_fe['sell_qty']) / (test_fe['buy_qty'] + test_fe['sell_qty'] + 1e-6)\ntest_fe['log_volume'] = np.log1p(test_fe['volume'])\ntest_fe['buy_to_volume_ratio'] = test_fe['buy_qty'] / (test_fe['volume'] + 1e-6)\ntest_fe['sell_to_volume_ratio'] = test_fe['sell_qty'] / (test_fe['volume'] + 1e-6)\n\n# Step 2: Apply same features to test set\nX_test = test_fe[feature_cols]\n\n# Step 3: Predict\ntest_preds = model.predict(X_test)\n\n# Step 4: Fill submission dataframe\nsample_submission['prediction'] = test_preds\n\n# Step 5: Save to CSV\nsample_submission.to_csv('submission.csv', index=False)\nprint(\"submission.csv file created successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:33:32.091233Z","iopub.execute_input":"2025-07-20T06:33:32.091599Z","iopub.status.idle":"2025-07-20T06:33:37.506380Z","shell.execute_reply.started":"2025-07-20T06:33:32.091570Z","shell.execute_reply":"2025-07-20T06:33:37.505350Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_submission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:34:28.504061Z","iopub.execute_input":"2025-07-20T06:34:28.504409Z","iopub.status.idle":"2025-07-20T06:34:28.513355Z","shell.execute_reply.started":"2025-07-20T06:34:28.504350Z","shell.execute_reply":"2025-07-20T06:34:28.512250Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Final Thoughts\n\nWe’ve successfully built a complete pipeline to predict crypto price movements using minute-level market data:\n\n### 🔹 Summary of Steps:\n1. **Data Loading** from `.parquet`\n2. **EDA**: Distribution analysis & correlation checks\n3. **Feature Engineering**: Bid-ask spread, volume imbalance, etc.\n4. **Modeling**: Baseline LightGBM with time-based validation\n5. **Test Prediction** & Submission File Creation\n\n","metadata":{}},{"cell_type":"markdown","source":"# Model Improvement Step 1: Feature Expansion\n\nWe now expand our feature set by including the first 100 anonymized features (`X1` to `X100`) in addition to the engineered market features.\n\nThis gives the model more signal and improves learning capacity.\n","metadata":{}},{"cell_type":"code","source":"# Define new feature set\nengineered_features = [\n    'bid_ask_spread', 'volume_imbalance', 'log_volume',\n    'buy_to_volume_ratio', 'sell_to_volume_ratio'\n]\n\nanonymized_features = [f'X{i}' for i in range(1, 101)]\n\nfeature_cols = engineered_features + anonymized_features\n\n# Split again\nX_train, X_val = train_fe[feature_cols].iloc[:train_cutoff], train_fe[feature_cols].iloc[train_cutoff:]\ny_train, y_val = train_fe['label'].iloc[:train_cutoff], train_fe['label'].iloc[train_cutoff:]\n\n# Retrain model\nmodel = lgb.LGBMRegressor(n_estimators=500, learning_rate=0.05, random_state=42)\n\nmodel.fit(\n    X_train, y_train,\n    eval_set=[(X_val, y_val)],\n    eval_metric='rmse',\n    callbacks=[\n        early_stopping(stopping_rounds=20),\n        log_evaluation(period=50)\n    ]\n)\n\n# Evaluate\ny_pred = model.predict(X_val)\nrmse = mean_squared_error(y_val, y_pred, squared=False)\nprint(f\"📉 Expanded Feature Set - Validation RMSE: {rmse:.5f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:43:11.950567Z","iopub.execute_input":"2025-07-20T06:43:11.951696Z","iopub.status.idle":"2025-07-20T06:43:22.192614Z","shell.execute_reply.started":"2025-07-20T06:43:11.951662Z","shell.execute_reply":"2025-07-20T06:43:22.191580Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Result After Expanding Features to X1–X100\n\n- 📉 Validation RMSE: **1.04086**\n- 🔁 Early stopping occurred after just 1 iteration again.\n- 🔬 Despite adding 100 anonymized features + engineered ones (105 total), there's **no performance gain** over the baseline.\n\n### Possible Reasons:\n- Many of the `X_` features may be uninformative or noisy.\n- Model may be underfitting due to limited training depth (early stopping too early).\n- Better results likely require:\n  - **Feature selection or dimensionality reduction** (e.g. PCA)\n  - **Hyperparameter tuning** to fully utilize signal\n","metadata":{}},{"cell_type":"markdown","source":"# Model Improvement Step 2: LightGBM Hyperparameter Tuning with Optuna\n\nNow we tune the LightGBM model using **Optuna**, an automatic hyperparameter optimization library.\n\n### Why Optuna?\n- Efficient exploration of parameter space\n- Learns from past trials to suggest better future configurations\n- Finds combinations that manual tuning often misses\n\nWe’ll tune over 30 trials using time-based validation RMSE as the optimization target.\n","metadata":{}},{"cell_type":"code","source":"import optuna\nfrom lightgbm import LGBMRegressor\n\ndef objective(trial):\n    params = {\n        'n_estimators': 1000,\n        'learning_rate': trial.suggest_float('learning_rate', 0.005, 0.1, log=True),\n        'num_leaves': trial.suggest_int('num_leaves', 20, 150),\n        'max_depth': trial.suggest_int('max_depth', 3, 12),\n        'min_child_samples': trial.suggest_int('min_child_samples', 10, 100),\n        'subsample': trial.suggest_float('subsample', 0.5, 1.0),\n        'colsample_bytree': trial.suggest_float('colsample_bytree', 0.5, 1.0),\n        'reg_alpha': trial.suggest_float('reg_alpha', 1e-8, 10.0, log=True),\n        'reg_lambda': trial.suggest_float('reg_lambda', 1e-8, 10.0, log=True),\n        'random_state': 42,\n        'n_jobs': -1\n    }\n\n    model = LGBMRegressor(**params)\n\n    model.fit(\n        X_train, y_train,\n        eval_set=[(X_val, y_val)],\n        eval_metric='rmse',\n        callbacks=[\n            early_stopping(stopping_rounds=20),\n            log_evaluation(period=0)\n        ]\n    )\n\n    preds = model.predict(X_val)\n    rmse = mean_squared_error(y_val, preds, squared=False)\n    return rmse\n\nstudy = optuna.create_study(direction='minimize')\nstudy.optimize(objective, n_trials=30)\n\nprint(f\"🔍 Best RMSE: {study.best_value:.5f}\")\nprint(\"✅ Best Params:\")\nprint(study.best_params)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:46:50.911063Z","iopub.execute_input":"2025-07-20T06:46:50.911536Z","iopub.status.idle":"2025-07-20T06:49:44.291172Z","shell.execute_reply.started":"2025-07-20T06:46:50.911492Z","shell.execute_reply":"2025-07-20T06:49:44.290157Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Hyperparameter Tuning Summary\n\n-  **Best RMSE achieved**: 1.03933\n-  Tuned using 30 trials of Optuna\n-  **Best Parameters** found:\n  - `learning_rate`: 0.0676\n  - `num_leaves`: 97\n  - `max_depth`: 4\n  - `min_child_samples`: 98\n  - `subsample`: 0.5186\n  - `colsample_bytree`: 0.6457\n  - `reg_alpha`: 0.1215\n  - `reg_lambda`: 0.1979\n\nThese hyperparameters gave a modest improvement over the baseline. We’ll now use them to train the final model and make test predictions.\n","metadata":{}},{"cell_type":"code","source":"# Use best parameters from Optuna\nbest_params = {\n    'n_estimators': 1000,\n    'learning_rate': 0.06762745224761675,\n    'num_leaves': 97,\n    'max_depth': 4,\n    'min_child_samples': 98,\n    'subsample': 0.5185830564077009,\n    'colsample_bytree': 0.6456671540143484,\n    'reg_alpha': 0.12148076904003635,\n    'reg_lambda': 0.19786770408218737,\n    'random_state': 42,\n    'n_jobs': -1\n}\n\n# Train on full dataset\nX_full = train_fe[feature_cols]\ny_full = train_fe['label']\n\nfinal_model = lgb.LGBMRegressor(**best_params)\nfinal_model.fit(X_full, y_full)\n\n# Predict on test\nX_test = test_fe[feature_cols]\nfinal_preds = final_model.predict(X_test)\n\n# Load submission template\nsample_submission = pd.read_csv('/kaggle/input/drw-crypto-market-prediction/sample_submission.csv')\nsample_submission['prediction'] = final_preds\n\n# Save submission file\nsample_submission.to_csv('/kaggle/working/submission.csv', index=False)\nprint(\"Final submission file saved to /kaggle/working/submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-20T06:54:01.769067Z","iopub.execute_input":"2025-07-20T06:54:01.769686Z","iopub.status.idle":"2025-07-20T06:55:08.411616Z","shell.execute_reply.started":"2025-07-20T06:54:01.769656Z","shell.execute_reply":"2025-07-20T06:55:08.410490Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}