{"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":"gpu","dataSources":[{"sourceId":96164,"databundleVersionId":12993472,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"389f228f-63b4-4f26-b9be-025f54ab85cd","_cell_guid":"b4f50c71-79c2-4fa4-911a-c5b5f4988f7f","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-07-20T22:25:37.797446Z","iopub.execute_input":"2025-07-20T22:25:37.797711Z","iopub.status.idle":"2025-07-20T22:25:38.071993Z","shell.execute_reply.started":"2025-07-20T22:25:37.797689Z","shell.execute_reply":"2025-07-20T22:25:38.071189Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom xgboost import XGBRegressor\nfrom sklearn.metrics import r2_score, mean_squared_error\n\n# Config\nclass CFG:\n    train_path = \"/kaggle/input/drw-crypto-market-prediction/train.parquet\"\n    test_path = \"/kaggle/input/drw-crypto-market-prediction/test.parquet\"\n    sample_sub_path = \"/kaggle/input/drw-crypto-market-prediction/sample_submission.csv\"\n    target = \"label\"\n\n# 1. Load data\nX_FEATURES = [\n    \"X752\",\n    \"X287\",\n    \"X298\",\n    \"X759\",\n    \"X302\",\n    \"X55\",\n    \"X56\",\n    \"X52\",\n    \"X303\",\n    \"X51\",\n    \"X598\", \"X385\", \"X603\", \"X674\",\n    \"X415\", \"X345\", \"X174\", \"X178\", \"X168\", \"X612\", \"bid_qty\",\n        \"ask_qty\", \"buy_qty\", \"sell_qty\", \"volume\"\n    ]\n","metadata":{"_uuid":"3f2173c0-30ea-4ae2-9eef-9a3b310d3ef4","_cell_guid":"c9b8cc83-ef40-4447-add9-4ef68e0c2677","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-07-20T22:25:38.073091Z","iopub.execute_input":"2025-07-20T22:25:38.073447Z","iopub.status.idle":"2025-07-20T22:25:39.183352Z","shell.execute_reply.started":"2025-07-20T22:25:38.073428Z","shell.execute_reply":"2025-07-20T22:25:39.182582Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def feature_engineering(df):\n    # Original features\n    df['bid_ask_interaction'] = df['bid_qty'] * df['ask_qty']\n    df['bid_buy_interaction'] = df['bid_qty'] * df['buy_qty']\n    df['bid_sell_interaction'] = df['bid_qty'] * df['sell_qty']\n    df['ask_buy_interaction'] = df['ask_qty'] * df['buy_qty']\n    df['ask_sell_interaction'] = df['ask_qty'] * df['sell_qty']\n\n    df['volume_weighted_sell'] = df['sell_qty'] * df['volume']\n    df['buy_sell_ratio'] = df['buy_qty'] / (df['sell_qty'] + 1e-10)\n    df['selling_pressure'] = df['sell_qty'] / (df['volume'] + 1e-10)\n    df['log_volume'] = np.log1p(df['volume'])\n\n    df['effective_spread_proxy'] = np.abs(df['buy_qty'] - df['sell_qty']) / (df['volume'] + 1e-10)\n    df['bid_ask_imbalance'] = (df['bid_qty'] - df['ask_qty']) / (df['bid_qty'] + df['ask_qty'] + 1e-10)\n    df['order_flow_imbalance'] = (df['buy_qty'] - df['sell_qty']) / (df['buy_qty'] + df['sell_qty'] + 1e-10)\n    df['liquidity_ratio'] = (df['bid_qty'] + df['ask_qty']) / (df['volume'] + 1e-10)\n    \n    # Price Pressure Indicators\n    df['net_order_flow'] = df['buy_qty'] - df['sell_qty']\n    df['normalized_net_flow'] = df['net_order_flow'] / (df['volume'] + 1e-10)\n    df['buying_pressure'] = df['buy_qty'] / (df['volume'] + 1e-10)\n    df['volume_weighted_buy'] = df['buy_qty'] * df['volume']\n    \n    # Liquidity Depth Measures\n    df['total_depth'] = df['bid_qty'] + df['ask_qty']\n    df['depth_imbalance'] = (df['bid_qty'] - df['ask_qty']) / (df['total_depth'] + 1e-10)\n    df['relative_spread'] = np.abs(df['bid_qty'] - df['ask_qty']) / (df['total_depth'] + 1e-10)\n    df['log_depth'] = np.log1p(df['total_depth'])\n    \n    # Order Flow Toxicity Proxies\n    df['kyle_lambda'] = np.abs(df['net_order_flow']) / (df['volume'] + 1e-10)\n    df['flow_toxicity'] = np.abs(df['order_flow_imbalance']) * df['volume']\n    df['aggressive_flow_ratio'] = (df['buy_qty'] + df['sell_qty']) / (df['total_depth'] + 1e-10)\n    \n    # Market Activity Indicators\n    df['volume_depth_ratio'] = df['volume'] / (df['total_depth'] + 1e-10)\n    df['activity_intensity'] = (df['buy_qty'] + df['sell_qty']) / (df['volume'] + 1e-10)\n    df['log_buy_qty'] = np.log1p(df['buy_qty'])\n    df['log_sell_qty'] = np.log1p(df['sell_qty'])\n    df['log_bid_qty'] = np.log1p(df['bid_qty'])\n    df['log_ask_qty'] = np.log1p(df['ask_qty'])\n    \n    # Microstructure Volatility Proxies\n    df['realized_spread_proxy'] = 2 * np.abs(df['net_order_flow']) / (df['volume'] + 1e-10)\n    df['price_impact_proxy'] = df['net_order_flow'] / (df['total_depth'] + 1e-10)\n    df['quote_volatility_proxy'] = np.abs(df['depth_imbalance'])\n    \n    # Complex Interaction Terms\n    df['flow_depth_interaction'] = df['net_order_flow'] * df['total_depth']\n    df['imbalance_volume_interaction'] = df['order_flow_imbalance'] * df['volume']\n    df['depth_volume_interaction'] = df['total_depth'] * df['volume']\n    df['buy_sell_spread'] = np.abs(df['buy_qty'] - df['sell_qty'])\n    df['bid_ask_spread'] = np.abs(df['bid_qty'] - df['ask_qty'])\n    \n    # Information Asymmetry Measures\n    df['trade_informativeness'] = df['net_order_flow'] / (df['bid_qty'] + df['ask_qty'] + 1e-10)\n    df['execution_shortfall_proxy'] = df['buy_sell_spread'] / (df['volume'] + 1e-10)\n    df['adverse_selection_proxy'] = df['net_order_flow'] / (df['total_depth'] + 1e-10) * df['volume']\n    \n    # Market Efficiency Indicators\n    df['fill_probability'] = df['volume'] / (df['buy_qty'] + df['sell_qty'] + 1e-10)\n    df['execution_rate'] = (df['buy_qty'] + df['sell_qty']) / (df['total_depth'] + 1e-10)\n    df['market_efficiency'] = df['volume'] / (df['bid_ask_spread'] + 1e-10)\n    \n    # Non-linear Transformations\n    df['sqrt_volume'] = np.sqrt(df['volume'])\n    df['sqrt_depth'] = np.sqrt(df['total_depth'])\n    df['volume_squared'] = df['volume'] ** 2\n    df['imbalance_squared'] = df['order_flow_imbalance'] ** 2\n    \n    # Relative Measures\n    df['bid_ratio'] = df['bid_qty'] / (df['total_depth'] + 1e-10)\n    df['ask_ratio'] = df['ask_qty'] / (df['total_depth'] + 1e-10)\n    df['buy_ratio'] = df['buy_qty'] / (df['buy_qty'] + df['sell_qty'] + 1e-10)\n    df['sell_ratio'] = df['sell_qty'] / (df['buy_qty'] + df['sell_qty'] + 1e-10)\n    \n    # Market Stress Indicators\n    df['liquidity_consumption'] = (df['buy_qty'] + df['sell_qty']) / (df['total_depth'] + 1e-10)\n    df['market_stress'] = df['volume'] / (df['total_depth'] + 1e-10) * np.abs(df['order_flow_imbalance'])\n    df['depth_depletion'] = df['volume'] / (df['bid_qty'] + df['ask_qty'] + 1e-10)\n    \n    # Directional Indicators\n    df['net_buying_ratio'] = df['net_order_flow'] / (df['volume'] + 1e-10)\n    df['directional_volume'] = df['net_order_flow'] * np.log1p(df['volume'])\n    df['signed_volume'] = np.sign(df['net_order_flow']) * df['volume']\n    # Handle infinities and NaN\n    df = df.replace([np.inf, -np.inf], np.nan)\n    \n    # For each column, replace NaN with median for robustness\n    for col in df.columns:\n        if df[col].isna().any():\n            median_val = df[col].median()\n            df[col] = df[col].fillna(median_val if not pd.isna(median_val) else 0)\n    \n    return df","metadata":{"_uuid":"5194fdb4-41d6-4274-b224-90d8b2bae224","_cell_guid":"9ddc020e-c8e1-4a3c-9685-efad3c19cc16","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-07-20T22:25:39.184217Z","iopub.execute_input":"2025-07-20T22:25:39.184614Z","iopub.status.idle":"2025-07-20T22:25:39.208711Z","shell.execute_reply.started":"2025-07-20T22:25:39.184589Z","shell.execute_reply":"2025-07-20T22:25:39.207959Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_parquet(CFG.train_path, columns=['__index_level_0__', CFG.target] + X_FEATURES)\nX_test = pd.read_parquet(CFG.test_path, columns=X_FEATURES)","metadata":{"_uuid":"55647a16-d5e1-4ef1-96bd-554d254e8481","_cell_guid":"ebd61d7a-ab1f-49ad-b5eb-4727df8fc30a","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-07-20T22:26:08.527102Z","iopub.execute_input":"2025-07-20T22:26:08.527720Z","iopub.status.idle":"2025-07-20T22:26:10.893735Z","shell.execute_reply.started":"2025-07-20T22:26:08.527687Z","shell.execute_reply":"2025-07-20T22:26:10.893195Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train = train[X_FEATURES]\ny_train = train[CFG.target]\n\nX_train = feature_engineering(X_train)\nX_test = feature_engineering(X_test)\n\nfrom sklearn.linear_model import Ridge\nfrom sklearn.ensemble import StackingRegressor\nfrom lightgbm import LGBMRegressor\nfrom xgboost import XGBRegressor\nfrom sklearn.model_selection import KFold, cross_val_score\nfrom scipy.stats import pearsonr\n\nbase_models = [\n    (\"xgb\", XGBRegressor(\n        tree_method=\"hist\",\n        device=\"gpu\",\n        colsample_bylevel=0.4778,\n        colsample_bynode=0.3628,\n        colsample_bytree=0.7107,\n        gamma=1.7095,\n        learning_rate=0.02213,\n        max_depth=20,\n        max_leaves=12,\n        min_child_weight=16,\n        n_estimators=1667,\n        subsample=0.06567,\n        reg_alpha=39.3524,\n        reg_lambda=75.4484,\n        verbosity=0,\n        random_state=42,\n        n_jobs=-1\n    )),\n    \n    (\"lgbm\", LGBMRegressor(\n        n_estimators=500,\n        learning_rate=0.03,\n        num_leaves=31,\n        min_child_samples=50,\n        subsample=0.8,\n        colsample_bytree=0.8,\n        reg_alpha=10,\n        reg_lambda=10,\n        random_state=42,\n        device=\"gpu\",\n        verbosity=-1,\n        n_jobs=-1\n    )),\n    \n    (\"ridge\", Ridge(alpha=1.0))\n]\n\nmeta_model = Ridge(alpha=1.0)\n\nstack_model = StackingRegressor(\n    estimators=base_models,\n    final_estimator=meta_model,\n    cv=KFold(n_splits=5, shuffle=False),\n    passthrough=True,\n    n_jobs=-1\n)\n\nstack_model.fit(X_train, y_train)\n\ny_pred = stack_model.predict(X_train)\nprint(\"Stacked R²:\", r2_score(y_train, y_pred))\nprint(\"Stacked MSE:\", mean_squared_error(y_train, y_pred))\npearson_corr, _ = pearsonr(y_train, y_pred)\nprint(\"Pearson Correlation (train):\", round(pearson_corr, 6))\n\ntest_pred = stack_model.predict(X_test)\n\nsub = pd.read_csv(CFG.sample_sub_path)\nsub[\"prediction\"] = test_pred\nsub.to_csv(\"submission.csv\", index=False)\nprint(\"Submission saved as: submission.csv\")","metadata":{"_uuid":"030de06c-314b-4db8-9787-445c6a56bcce","_cell_guid":"7efd7519-6b6d-4d25-8109-5a421bc9ad34","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-07-20T22:26:10.894910Z","iopub.execute_input":"2025-07-20T22:26:10.895154Z","iopub.status.idle":"2025-07-20T22:29:02.403673Z","shell.execute_reply.started":"2025-07-20T22:26:10.895135Z","shell.execute_reply":"2025-07-20T22:29:02.402924Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null}]}