{"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":11418275,"sourceType":"competition"},{"sourceId":12405352,"sourceType":"datasetVersion","datasetId":7823194}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"It is based on [All You Need is Random State 700](https://www.kaggle.com/code/shinchen93/all-you-need-is-random-state-700), [ShinC](https://www.kaggle.com/shinchen93)","metadata":{}},{"cell_type":"code","source":"def sort_test_df_by_time(df):\n    assert len(df.shape) == 2\n    assert df.shape[0] == 538150\n\n    n = df.shape[0]\n    t = pd.Series(np.arange(n))\n    t = t.sample(n=n, random_state=700)\n\n    t = pd.Series(np.arange(n), index=t.to_numpy()).sort_index()\n    return df.iloc[t.to_numpy()]","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-09T02:09:07.438670Z","iopub.execute_input":"2025-07-09T02:09:07.442171Z","iopub.status.idle":"2025-07-09T02:09:07.459995Z","shell.execute_reply.started":"2025-07-09T02:09:07.442028Z","shell.execute_reply":"2025-07-09T02:09:07.458428Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import KFold\nfrom sklearn.linear_model import Ridge\nimport warnings\n\nwarnings.filterwarnings(\"ignore\")\n\n\nclass Config:\n    TRAIN_PATH = \"/kaggle/input/drw-crypto-market-prediction/train.parquet\"\n    TEST_PATH = \"/kaggle/input/drw-crypto-market-prediction/test.parquet\"\n    # use the submission file with reset order\n    SUBMISSION_PATH = \"/kaggle/input/drw-submission-order-reset/sample_submission_idx.csv\"\n\n    FEATURES = list(set([\n        \"X863\", \"X856\", \"X344\", \"X598\", \"X862\", \"X385\", \"X852\", \"X603\", \"X860\", \"X674\",\n        \"X415\", \"X345\", \"X137\", \"X855\", \"X174\", \"X302\", \"X178\", \"X532\", \"X168\", \"X612\",\n        \"bid_qty\", \"ask_qty\", \"buy_qty\", \"sell_qty\", \"volume\", \"X888\", \"X421\", \"X333\",\n    ]))\n\n    LABEL_COLUMN = \"label\"\n    N_FOLDS = 3\n    RANDOM_STATE = 42\n    lags = [1,3,5,10,20,60,120,180,240,60*24,60*24*2,60*24*3]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T02:09:07.462498Z","iopub.execute_input":"2025-07-09T02:09:07.462812Z","iopub.status.idle":"2025-07-09T02:09:07.482345Z","shell.execute_reply.started":"2025-07-09T02:09:07.462778Z","shell.execute_reply":"2025-07-09T02:09:07.481225Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_time_decay_weights(n: int, decay: float = 0.9) -> np.ndarray:\n    positions = np.arange(n)\n    normalized = positions / (n - 1)\n    weights = decay ** (1.0 - normalized)\n    return weights * n / weights.sum()\n\n\ndef add_features(df):\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'])\n    df['selling_pressure'] = df['sell_qty'] / (df['volume'])\n    df['log_volume'] = np.log1p(df['volume'])\n\n    df['effective_spread_proxy'] = np.abs(df['buy_qty'] - df['sell_qty']) / (df['volume'])\n    df['bid_ask_imbalance'] = (df['bid_qty'] - df['ask_qty']) / (df['bid_qty'] + df['ask_qty'])\n    df['order_flow_imbalance'] = (df['buy_qty'] - df['sell_qty']) / (df['buy_qty'] + df['sell_qty'])\n    df['liquidity_ratio'] = (df['bid_qty'] + df['ask_qty']) / (df['volume'])\n\n    FEATURES = [\n        \"X863\", \"X856\", \"X598\", \"X862\", \"X385\", \"X603\", \"X860\", \"X674\", \"X415\", \"X345\", \"X855\", \"X174\", \"X302\",\n        \"X178\", \"X168\", \"X612\", \"X333\", \"bid_qty\", \"ask_qty\", \"buy_qty\", \"sell_qty\", \"volume\", 'log_volume',\n        'bid_ask_interaction', 'bid_buy_interaction', 'bid_sell_interaction', 'ask_buy_interaction',\n        'ask_sell_interaction']\n\n    for col in FEATURES:\n        for lag in Config.lags:\n            df[f'{col}_lag_{lag}'] = df[col].shift(lag)\n            df[f'{col}_lead_{lag}'] = df[col].shift(-lag)\n\n    df = df.fillna(df.mean())\n\n    return df\n\n\ndef sort_test_df_by_time(df):\n    assert len(df.shape) == 2\n    assert df.shape[0] == 538150\n\n    n = df.shape[0]\n    t = pd.Series(np.arange(n))\n    t = t.sample(n=n, random_state=700)\n\n    t = pd.Series(np.arange(n), index=t.to_numpy()).sort_index()\n    return df.iloc[t.to_numpy()]\n\ndef load_data():\n    train_df = pd.read_parquet(Config.TRAIN_PATH, columns=Config.FEATURES + [Config.LABEL_COLUMN])\n    test_df = pd.read_parquet(Config.TEST_PATH, columns=Config.FEATURES)\n    submission_df = pd.read_csv(Config.SUBMISSION_PATH)\n    print(f\"Loaded data - Train: {train_df.shape}, Test: {test_df.shape}, Submission: {submission_df.shape}\")\n\n    # restore the test time order\n    test_df = sort_test_df_by_time(test_df).reset_index(drop=True)\n\n    train_df = add_features(train_df)\n    test_df = add_features(test_df)\n\n    return train_df.reset_index(drop=True), test_df.reset_index(drop=True), submission_df\n\n\n# =========================\n# Training and Evaluation\n# =========================\ndef train_and_evaluate(train_df, test_df):\n    FEATURES = [\n        \"X863\", \"X856\", \"X598\", \"X862\", \"X385\", \"X603\", \"X860\", \"X674\", \"X415\", \"X345\", \"X855\", \"X174\", \"X302\",\n        \"X178\", \"X168\", \"X612\", \"X333\", \"bid_qty\", \"ask_qty\", \"buy_qty\", \"sell_qty\", \"volume\", 'log_volume',\n        'bid_ask_interaction', 'bid_buy_interaction', 'bid_sell_interaction', 'ask_buy_interaction',\n        'ask_sell_interaction']\n    \n    lag_features = [f'{f}_lag_{l}' for f in FEATURES for l in Config.lags]\n    lead_features = [f'{f}_lead_{l}' for f in FEATURES for l in Config.lags]\n\n    FEATURES += lag_features\n    FEATURES += lead_features\n\n    n_samples = len(train_df)\n    test_preds = np.zeros(len(test_df))\n\n    full_weights = create_time_decay_weights(n_samples)\n    kf = KFold(n_splits=Config.N_FOLDS, shuffle=True)\n\n    for fold, (train_idx, valid_idx) in enumerate(kf.split(train_df), start=1):\n\n\n        X_train = train_df.iloc[train_idx][FEATURES]\n        y_train = train_df.iloc[train_idx][Config.LABEL_COLUMN]\n        sw = full_weights[train_idx]\n\n\n        model = Ridge(alpha = 0.105)\n        model.fit(\n            X_train, y_train,\n            sample_weight=sw\n        )\n\n        test_preds += model.predict(test_df[FEATURES])\n    return test_preds\n\n\n\ndef ensemble_simple(test_preds, submission_df):\n    submission_df[\"prediction\"] = test_preds\n    submission_df = submission_df.sort_values(by='idx', ascending=True)\n    submission_df = submission_df.drop('idx', axis=1)\n    submission_df['ID'] = range(1, len(submission_df) + 1)\n    submission_df = submission_df.reset_index(drop=True)\n    submission_df.to_csv(f\"submission.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T02:09:07.483478Z","iopub.execute_input":"2025-07-09T02:09:07.483829Z","iopub.status.idle":"2025-07-09T02:09:07.506916Z","shell.execute_reply.started":"2025-07-09T02:09:07.483788Z","shell.execute_reply":"2025-07-09T02:09:07.505564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if __name__ == \"__main__\":\n    train_df, test_df, submission_df = load_data()\n    test_preds = train_and_evaluate(train_df, test_df)\n    ensemble_simple(test_preds, submission_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T02:09:07.508891Z","iopub.execute_input":"2025-07-09T02:09:07.509285Z","iopub.status.idle":"2025-07-09T02:10:51.930915Z","shell.execute_reply.started":"2025-07-09T02:09:07.509255Z","shell.execute_reply":"2025-07-09T02:10:51.929827Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}