{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport datatable as dt\nimport datetime\nimport gc\n\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nDEVICE = \"CPU\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-04-10T13:46:23.561899Z","iopub.execute_input":"2022-04-10T13:46:23.562734Z","iopub.status.idle":"2022-04-10T13:46:24.663361Z","shell.execute_reply.started":"2022-04-10T13:46:23.562634Z","shell.execute_reply":"2022-04-10T13:46:24.66225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:46:24.665012Z","iopub.execute_input":"2022-04-10T13:46:24.665286Z","iopub.status.idle":"2022-04-10T13:46:24.671342Z","shell.execute_reply.started":"2022-04-10T13:46:24.665255Z","shell.execute_reply":"2022-04-10T13:46:24.670255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. Data import and preprocessing","metadata":{}},{"cell_type":"code","source":"data_path = \"/kaggle/input/g-research-crypto-forecasting/\"\n\ntrain = dt.fread(data_path + \"train.csv\").to_pandas()\nasset_details = pd.read_csv(data_path + \"asset_details.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:46:24.672882Z","iopub.execute_input":"2022-04-10T13:46:24.673156Z","iopub.status.idle":"2022-04-10T13:47:04.876586Z","shell.execute_reply.started":"2022-04-10T13:46:24.673122Z","shell.execute_reply":"2022-04-10T13:47:04.875423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Downgrade data types to save memory\nfloat_cols = list(train.dtypes[train.dtypes == \"float64\"].index)\ntrain[float_cols] = train[float_cols].astype(np.float32)\n    \ntrain[\"Asset_ID\"] = train[\"Asset_ID\"].astype(np.int8)\ntrain[\"Count\"] = train[\"Count\"].astype(np.int32)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:04.877965Z","iopub.execute_input":"2022-04-10T13:47:04.878281Z","iopub.status.idle":"2022-04-10T13:47:08.574523Z","shell.execute_reply.started":"2022-04-10T13:47:04.878248Z","shell.execute_reply":"2022-04-10T13:47:08.573598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Forward fill data\ntrain_df = pd.DataFrame()\ntrain = train.set_index(\"timestamp\").sort_index()\nfor asset in asset_details[\"Asset_ID\"].sort_values().values:\n    temp_df = train[train[\"Asset_ID\"]==asset]\n    temp_df = temp_df.reindex(range(temp_df.index[0],temp_df.index[-1]+60,60),method='pad')\n    temp_df = temp_df.reset_index()\n    train_df = pd.concat([train_df, temp_df])\n\ntrain_df[\"datetime\"] = train_df[\"timestamp\"].astype(\"datetime64[s]\")\ntrain_df.set_index(\"timestamp\", inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:08.576468Z","iopub.execute_input":"2022-04-10T13:47:08.576714Z","iopub.status.idle":"2022-04-10T13:47:22.468332Z","shell.execute_reply.started":"2022-04-10T13:47:08.576687Z","shell.execute_reply":"2022-04-10T13:47:22.467341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Drop irrelavant columns\ntrain_df.drop([\"VWAP\", \"Target\"], axis=1, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:22.469503Z","iopub.execute_input":"2022-04-10T13:47:22.469839Z","iopub.status.idle":"2022-04-10T13:47:22.976357Z","shell.execute_reply.started":"2022-04-10T13:47:22.469808Z","shell.execute_reply":"2022-04-10T13:47:22.975378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Calculate log returns\ndef append_log_returns(df, periods=[1]):\n    returns_df = pd.DataFrame()\n    for asset_id in asset_details.index:\n        train_single = df[df.Asset_ID == asset_id].copy().reset_index()\n        \n        for item in periods:\n            train_single[f\"{int(item/60)}h_log_returns\"] = np.log(train_single[\"Close\"]).diff(periods=item)\n            \n            if item < 0:\n                train_single[f\"{int(item/60)}h_log_returns\"] = train_single[f\"{int(item/60)}h_log_returns\"] * (-1)\n            \n        returns_df = returns_df.append(train_single.reset_index(drop=False))\n        \n    #Replace infinite numbers with 0\n    returns_df.replace([np.inf, -np.inf], 0, inplace=True)\n    returns_df.set_index(\"timestamp\", inplace=True)\n    return returns_df","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:22.977762Z","iopub.execute_input":"2022-04-10T13:47:22.978109Z","iopub.status.idle":"2022-04-10T13:47:22.985404Z","shell.execute_reply.started":"2022-04-10T13:47:22.978042Z","shell.execute_reply":"2022-04-10T13:47:22.984313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lrs = [60, 720, 1440, 2880, 4320, 5760, 7200, 8640, 10080, -60, -720, -1440, -2880, -4320, -5760, -7200, -8640, -10080]\ntrain_df = append_log_returns(train_df, lrs)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:22.986884Z","iopub.execute_input":"2022-04-10T13:47:22.98722Z","iopub.status.idle":"2022-04-10T13:47:47.092342Z","shell.execute_reply.started":"2022-04-10T13:47:22.987175Z","shell.execute_reply":"2022-04-10T13:47:47.091228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Drop rows with missing values\ntrain_df.dropna(inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:47.093626Z","iopub.execute_input":"2022-04-10T13:47:47.093858Z","iopub.status.idle":"2022-04-10T13:47:53.562538Z","shell.execute_reply.started":"2022-04-10T13:47:47.093829Z","shell.execute_reply":"2022-04-10T13:47:53.561715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Coin dataframe generation","metadata":{}},{"cell_type":"code","source":"asset_details","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:53.563617Z","iopub.execute_input":"2022-04-10T13:47:53.563877Z","iopub.status.idle":"2022-04-10T13:47:53.579626Z","shell.execute_reply.started":"2022-04-10T13:47:53.563803Z","shell.execute_reply":"2022-04-10T13:47:53.579096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Coinwise df generation\ncoin_df = train_df[(train_df[\"Asset_ID\" ] == 6) | (train_df[\"Asset_ID\" ] == 1)]","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:53.580733Z","iopub.execute_input":"2022-04-10T13:47:53.58095Z","iopub.status.idle":"2022-04-10T13:47:53.998077Z","shell.execute_reply.started":"2022-04-10T13:47:53.580923Z","shell.execute_reply":"2022-04-10T13:47:53.997136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import MinMaxScaler\n\ndef resample(df, new_timeframe):\n    train_daily = pd.DataFrame()\n    for asset_id, asset in zip(asset_details.Asset_ID, asset_details.Asset_Name):\n        train_single = df[df.Asset_ID == asset_id].copy().reset_index()\n        if train_single.shape[0] > 0:\n            train_single_new = train_single[['datetime','Count']].resample(new_timeframe, on='datetime').sum()\n            train_single_new['timestamp'] = train_single[['datetime', \"timestamp\"]].resample(new_timeframe, on='datetime').max()[\"timestamp\"]\n            train_single_new['open'] = train_single[['datetime','Open']].resample(new_timeframe, on='datetime').first()['Open']\n            train_single_new['high'] = train_single[['datetime','High']].resample(new_timeframe, on='datetime').max()['High']\n            train_single_new['low'] = train_single[['datetime','Low']].resample(new_timeframe, on='datetime').min()['Low']\n            train_single_new['close'] = train_single[['datetime','Close']].resample(new_timeframe, on='datetime').last()['Close']\n            train_single_new['volume'] = train_single[['datetime','Volume']].resample(new_timeframe, on='datetime').sum()['Volume']\n            \n            for lr in lrs:\n                train_single_new[f'{int(lr/60)}h_lr'] = train_single[['datetime',f'{int(lr/60)}h_log_returns']].resample(new_timeframe, on='datetime').last()[f'{int(lr/60)}h_log_returns']\n                train_single_new[f'{int(lr/60)}h_pr'] = train_single_new[f'{int(lr/60)}h_lr'] > 0\n                train_single_new[f'{int(lr/60)}h_pr'] = train_single_new[f'{int(lr/60)}h_pr'].astype(int)\n            \n            mean = train_single_new[[\"open\", \"high\", \"low\", \"close\"]].mean(axis=1)\n            std = train_single_new[[\"open\", \"high\", \"low\", \"close\"]].std(axis=1)\n\n            train_single_new['asset_ID'] = asset_id\n            train_single_new['asset'] = asset\n            train_single_new[\"upper_shadow\"] = upper_shadow(train_single_new)\n            train_single_new[\"lower_shadow\"] = lower_shadow(train_single_new)\n            train_single_new[\"real_body\"] = real_body(train_single_new)\n            train_single_new[\"candle\"] = candle_volatility(train_single_new)\n\n            train_single_new['body_mean'] = (train_single_new[\"open\"] + train_single_new[\"close\"]) / 2\n            \n            train_single_new[\"upper_shadow_v_real_body\"] = (train_single_new[\"upper_shadow\"] / train_single_new[\"real_body\"]) #/ train_single_new[\"body_mean\"]\n            train_single_new[\"lower_shadow_v_real_body\"] = (train_single_new[\"lower_shadow\"] / train_single_new[\"real_body\"]) #/ train_single_new[\"body_mean\"]\n            train_single_new[\"real_body_v_candle\"] = (train_single_new[\"real_body\"] / train_single_new[\"candle\"]) #/ train_single_new[\"body_mean\"]\n\n            \n            train_single_new = shift(train_single_new.copy(), [\"upper_shadow\", \"lower_shadow\", \"real_body\", \"candle\", \"body_mean\", \"open\", \"close\", \"high\", \"low\",\n                                \"upper_shadow_v_real_body\", \"lower_shadow_v_real_body\", \"real_body_v_candle\"], [-3, -2, -1, 1, 2, 3])\n            \n            train_daily = train_daily.append(train_single_new.reset_index(drop=False))\n        \n    #Replace infinite numbers with 0\n    train_daily.replace([np.inf, -np.inf], 0, inplace=True)\n    train_daily.set_index([\"timestamp\", \"asset_ID\"], inplace=True)\n    train_daily.sort_index()\n    return train_daily\n\ndef upper_shadow(df):\n    return df['high'] - np.maximum(df['close'], df['open'])\n\ndef lower_shadow(df):\n    return np.minimum(df['close'], df['open']) - df['low']\n\ndef real_body(df):\n    return np.abs(df['close'] - df['open'])\n\ndef candle_volatility(df):\n    return df['high'] - df['low']\n\n# Creating lagged features\ndef shift(df, columns, lags=[]):    \n    for lag in lags:\n        df = df.merge(df[columns].shift(lag), left_index=True, right_index=True, suffixes=('', f'_lag{lag}'), how=\"inner\")\n    df = df.dropna(axis=0)\n    return df","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-04-20T13:30:27.159947Z","iopub.execute_input":"2022-04-20T13:30:27.160278Z","iopub.status.idle":"2022-04-20T13:30:28.120961Z","shell.execute_reply.started":"2022-04-20T13:30:27.160193Z","shell.execute_reply":"2022-04-20T13:30:28.120134Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"coin_df = resample(coin_df.copy(), \"H\") #15T","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:54.135621Z","iopub.execute_input":"2022-04-10T13:47:54.135998Z","iopub.status.idle":"2022-04-10T13:47:59.163084Z","shell.execute_reply.started":"2022-04-10T13:47:54.135947Z","shell.execute_reply":"2022-04-10T13:47:59.16213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Single Candlestick Patterns Analysis","metadata":{}},{"cell_type":"code","source":"import plotly.graph_objects as go\nfrom sklearn.preprocessing import MinMaxScaler\n\ndef slice_datetime_window(df, start, end):\n    start = df.datetime.searchsorted(start)\n    end = df.datetime.searchsorted(end)\n    return df.iloc[start:end]\n\ndef group_standardize(df, N):\n    df = df.reset_index()\n    moments = pd.DataFrame()\n    moments[\"mean\"] = df[[\"open\", \"high\", \"low\", \"close\"]].groupby(df.index // N).agg(func=np.mean, axis=0).mean(axis=1)\n    moments[\"std\"] = df[[\"open\", \"high\", \"low\", \"close\"]].groupby(df.index // N).agg(func=np.std, axis=0).std(axis=1)\n    moments.index = moments.index * N\n    df = df.join(moments).fillna(method=\"ffill\")\n    return df\n\ndef plot_candlestick(df, slider=True, suffix=\"\"):\n    fig = go.Figure(data=[go.Candlestick(x=df.index, open=df[f'open{suffix}'], high=df[f'high{suffix}'], low=df[f'low{suffix}'], close=df[f'close{suffix}'])])\n    fig.update_layout(xaxis_rangeslider_visible=slider)\n    fig.show()\n    \ndef plot_patterns(df, normalize=False, standardize=False, group_standardization=False, N=1):\n    suffix = \"\"\n    df[\"body_mean\"] = 1\n    \n    if normalize == True:\n        suffix = \"_sc\"\n        df[\"open_sc\"] = (df[\"open\"] - df[\"low\"])/(df[\"high\"] - df[\"low\"])\n        df[\"high_sc\"] = 1\n        df[\"low_sc\"] = 0\n        df[\"close_sc\"] = (df[\"close\"] - df[\"low\"])/(df[\"high\"] - df[\"low\"])\n    \n    elif standardize==True:\n        suffix = \"_sc\"\n        mean = df[[\"open\", \"high\", \"low\", \"close\"]].mean(axis=1)\n        std = df[[\"open\", \"high\", \"low\", \"close\"]].std(axis=1)\n        \n        df[\"open_sc\"] = (df[\"open\"] - mean) / std\n        df[\"high_sc\"] = (df[\"high\"] - mean) / std\n        df[\"low_sc\"] = (df[\"low\"] - mean) / std\n        df[\"close_sc\"] = (df[\"close\"] - mean) / std\n    \n    elif group_standardization == True:\n        suffix = \"_sc\"\n        df = group_standardize(df.copy(), N)\n        df[\"open_sc\"] = (df[\"open\"] - df[\"mean\"]) / df[\"std\"]\n        df[\"high_sc\"] = (df[\"high\"] - df[\"mean\"]) / df[\"std\"]\n        df[\"low_sc\"] = (df[\"low\"] - df[\"mean\"]) / df[\"std\"]\n        df[\"close_sc\"] = (df[\"close\"] - df[\"mean\"]) / df[\"std\"]\n    else:\n        df[\"open\"] = df[\"open\"] / df[\"body_mean\"]\n        df[\"high\"] = df[\"high\"] / df[\"body_mean\"]\n        df[\"low\"] = df[\"low\"] / df[\"body_mean\"]\n        df[\"close\"] = df[\"close\"] / df[\"body_mean\"]\n        \n    plot_candlestick(df.reset_index(), False, suffix)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:59.16604Z","iopub.execute_input":"2022-04-10T13:47:59.166414Z","iopub.status.idle":"2022-04-10T13:47:59.304953Z","shell.execute_reply.started":"2022-04-10T13:47:59.166378Z","shell.execute_reply":"2022-04-10T13:47:59.303938Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from scipy import stats\nfrom statsmodels.stats.weightstats import ztest as ztest\n\ndef calc_metrics(df, pattern, plot_label=[], col_label=[], thr=None):\n    direction_df = pd.DataFrame()\n    \n#     returns_list = [\"168h_lr\",\"144h_lr\",\"120h_lr\",\"96h_lr\",\"72h_lr\",\"48h_lr\", \"24h_lr\", \"-24h_lr\", \"-48h_lr\", \"-72h_lr\", \"-96h_lr\", \"-120h_lr\", \"-144h_lr\", \"-168h_lr\"]\n#     positive_returns_list = [\"168h_pr\",\"144h_pr\",\"120h_pr\",\"96h_pr\",\"72h_pr\",\"48h_pr\", \"24h_pr\", \"-24h_pr\", \"-48h_pr\", \"-72h_pr\", \"-96h_pr\", \"-120h_pr\", \"-144h_pr\", \"-168h_pr\"]\n    \n    returns_list = [\"-24h_lr\", \"-48h_lr\", \"-72h_lr\", \"-96h_lr\", \"-120h_lr\", \"-144h_lr\", \"-168h_lr\"]\n    positive_returns_list = [\"-24h_pr\", \"-48h_pr\", \"-72h_pr\", \"-96h_pr\", \"-120h_pr\", \"-144h_pr\", \"-168h_pr\"]\n    \n    replace_dict = {\"-24h_pr\": \"day 1\", \"-48h_pr\": \"day 2\", \"-72h_pr\": \"day 3\", \"-96h_pr\": \"day 4\", \"-120h_pr\": \"day 5\", \"-144h_pr\": \"day 6\", \"-168h_pr\": \"day 7\"}\n    \n    #General direction\n    gen = df[(df[pattern] > 0)]\n    gen_lr_df = pd.melt(gen, id_vars=[\"asset\"], value_vars=returns_list)\n    gen_pr_df = pd.melt(gen, id_vars=[\"asset\"], value_vars=positive_returns_list)\n\n    down = df[(df[\"48h_lr\"] < 0.02) & (df[\"24h_lr\"] < 0.02) & (df[pattern] > 0)]\n    down_lr_df = pd.melt(down, id_vars=[\"asset\"], value_vars=returns_list)\n    down_pr_df = pd.melt(down, id_vars=[\"asset\"], value_vars=positive_returns_list)\n    \n    up = df[(df[\"48h_lr\"] > 0.02) & (df[\"24h_lr\"] > 0.02) & (df[pattern] > 0)]\n    up_lr_df = pd.melt(up, id_vars=[\"asset\"], value_vars=returns_list)\n    up_pr_df = pd.melt(up, id_vars=[\"asset\"], value_vars=positive_returns_list)\n    \n    # z scores\n    ztest_lr_gen_values = ztest(df[returns_list], gen[returns_list], value=0)[1]\n    ztest_lr_down_values = ztest(df[returns_list], down[returns_list], value=0)[1]\n    ztest_lr_up_values = ztest(df[returns_list], up[returns_list], value=0)[1]\n    \n    ztest_pr_gen_values = ztest(df[positive_returns_list], gen[positive_returns_list], value=0)[1]\n    ztest_pr_down_values = ztest(df[positive_returns_list], down[positive_returns_list], value=0)[1]\n    ztest_pr_up_values = ztest(df[positive_returns_list], up[positive_returns_list], value=0)[1]\n                                \n    gen_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    down_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    up_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    \n    fig, ax = plt.subplots(2,3, figsize=(20, 7), gridspec_kw={'height_ratios': [3, 1]}, sharex='col')\n    \n    primary_color = \"#1781b3\"\n    secondary_color = \"#00957e\"\n    \n    clrs_pr_gen = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_gen_values]\n    clrs_pr_down = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_down_values]\n    clrs_pr_up = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_up_values]\n    \n    clrs_lr_gen = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_gen_values]\n    clrs_lr_down = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_down_values]\n    clrs_lr_up = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_up_values]\n        \n    \n    significance = [*clrs_pr_gen, *clrs_pr_down, *clrs_pr_up, *clrs_lr_gen, *clrs_lr_down, *clrs_lr_up].count(\"grey\") / 42\n    \n#     print(f\"Significance: {significance}, thr: {thr}\")\n    \n    \n    sns.barplot(x=\"variable\", y=\"value\", data=gen_lr_df, ax=ax[0,0], ci=None, color=primary_color, palette=clrs_pr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=down_lr_df, ax=ax[0,1], ci=None, color=primary_color, palette=clrs_pr_down)\n    sns.barplot(x=\"variable\", y=\"value\", data=up_lr_df, ax=ax[0,2], ci=None, color=primary_color, palette=clrs_pr_up)\n\n    sns.barplot(x=\"variable\", y=\"value\", data=gen_pr_df, ax=ax[1,0], ci=None, color=secondary_color, palette=clrs_lr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=down_pr_df, ax=ax[1,1], ci=None, color=secondary_color, palette=clrs_lr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=up_pr_df, ax=ax[1,2], ci=None, color=secondary_color, palette=clrs_lr_gen)\n\n    \n    ax[0,0].set_title(f'Total returns, sample size {gen.shape[0]}', fontsize = 15)\n    ax[0,1].set_title(f'After downtrend returns, sample size {down.shape[0]}', fontsize = 15)\n    ax[0,2].set_title(f'After uptrend returns, sample size {up.shape[0]}', fontsize = 15)\n    \n    \n    ax[0,0].set_ylim(-0.10, 0.10)\n    ax[0,1].set_ylim(-0.10, 0.10)\n    ax[0,2].set_ylim(-0.10, 0.10)\n    ax[1,0].set_ylim(0, 1)\n    ax[1,1].set_ylim(0, 1)\n    ax[1,2].set_ylim(0, 1)\n    \n    ax[0,0].set_xlabel(None)\n    ax[0,1].set_xlabel(None)\n    ax[0,2].set_xlabel(None)\n    \n    ax[1,0].set_xlabel(\"Timeframe\")\n    ax[1,1].set_xlabel(\"Timeframe\")\n    ax[1,2].set_xlabel(\"Timeframe\")\n    \n    ax[0,0].set_ylabel(\"Mean log returns\", labelpad=10)\n    ax[0,1].set_ylabel(None)\n    ax[0,2].set_ylabel(None)\n    \n    ax[1,0].set_ylabel(\"Positive returns probability\", labelpad=25)\n    ax[1,1].set_ylabel(None)\n    ax[1,2].set_ylabel(None)\n    \n    ax[0,0].tick_params(axis='x', rotation=90, labelbottom=False)\n    ax[0,1].tick_params(axis='x', rotation=90, labelbottom=False)\n    ax[0,2].tick_params(axis='x', rotation=90, labelbottom=False)\n    \n    ax[1,0].tick_params(axis='x', rotation=45)\n    ax[1,1].tick_params(axis='x', rotation=45)\n    ax[1,2].tick_params(axis='x', rotation=45)\n    \n    \n    for index_1, subplot in enumerate(plot_label):\n        for index_2, p in enumerate(ax[tuple(subplot)].patches):\n            if index_2 in col_label[index_1]:\n                label_color = primary_color\n                if subplot[0] == 1:\n                    label_color = secondary_color\n                    \n                if ((subplot[0] == 1) and (p.get_height() < 0.5)):\n                    ax[tuple(subplot)].text(p.get_x() + p.get_width()/2., p.get_height() - 0.2, '{0:.2f}'.format(p.get_height()), fontsize=12, color=\"white\", ha='center', va='bottom')\n                elif p.get_height() < 0:\n                    ax[tuple(subplot)].text(p.get_x() + p.get_width()/2., p.get_height() - 0.014, '{0:.2f}'.format(p.get_height()), fontsize=12, color=label_color, ha='center', va='bottom')\n                else:\n                    ax[tuple(subplot)].text(p.get_x() + p.get_width()/2., p.get_height(), '{0:.2f}'.format(p.get_height()), fontsize=12, color=label_color, ha='center', va='bottom')\n                    \n    ax[1,0].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    ax[1,1].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    ax[1,2].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    \n    \n    sns.despine()\n    \n    plt.savefig(f\"barplot_{pattern}.png\")\n    \n#     return direction_df","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:59.306916Z","iopub.execute_input":"2022-04-10T13:47:59.307213Z","iopub.status.idle":"2022-04-10T13:47:59.365294Z","shell.execute_reply.started":"2022-04-10T13:47:59.307181Z","shell.execute_reply":"2022-04-10T13:47:59.364532Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from scipy import stats\nfrom statsmodels.stats.weightstats import ztest as ztest\n\ndef calc_metrics_2(df, pattern, plot_label=[], col_label=[], thr=None):\n    direction_df = pd.DataFrame()\n    \n#     returns_list = [\"168h_lr\",\"144h_lr\",\"120h_lr\",\"96h_lr\",\"72h_lr\",\"48h_lr\", \"24h_lr\", \"-24h_lr\", \"-48h_lr\", \"-72h_lr\", \"-96h_lr\", \"-120h_lr\", \"-144h_lr\", \"-168h_lr\"]\n#     positive_returns_list = [\"168h_pr\",\"144h_pr\",\"120h_pr\",\"96h_pr\",\"72h_pr\",\"48h_pr\", \"24h_pr\", \"-24h_pr\", \"-48h_pr\", \"-72h_pr\", \"-96h_pr\", \"-120h_pr\", \"-144h_pr\", \"-168h_pr\"]\n    \n    returns_list = [\"-24h_lr\", \"-48h_lr\", \"-72h_lr\", \"-96h_lr\", \"-120h_lr\", \"-144h_lr\", \"-168h_lr\"]\n    positive_returns_list = [\"-24h_pr\", \"-48h_pr\", \"-72h_pr\", \"-96h_pr\", \"-120h_pr\", \"-144h_pr\", \"-168h_pr\"]\n    \n    replace_dict = {\"-24h_pr\": \"day 1\", \"-48h_pr\": \"day 2\", \"-72h_pr\": \"day 3\", \"-96h_pr\": \"day 4\", \"-120h_pr\": \"day 5\", \"-144h_pr\": \"day 6\", \"-168h_pr\": \"day 7\"}\n    \n    #General direction\n    gen = df[(df[pattern] > 0)]\n    gen_lr_df = pd.melt(gen, id_vars=[\"asset\"], value_vars=returns_list)\n    gen_pr_df = pd.melt(gen, id_vars=[\"asset\"], value_vars=positive_returns_list)\n\n    down = df[(df[\"48h_lr\"] < 0.02) & (df[\"24h_lr\"] < 0.02) & (df[pattern] > 0)]\n    down_lr_df = pd.melt(down, id_vars=[\"asset\"], value_vars=returns_list)\n    down_pr_df = pd.melt(down, id_vars=[\"asset\"], value_vars=positive_returns_list)\n    \n    up = df[(df[\"48h_lr\"] > 0.02) & (df[\"24h_lr\"] > 0.02) & (df[pattern] > 0)]\n    up_lr_df = pd.melt(up, id_vars=[\"asset\"], value_vars=returns_list)\n    up_pr_df = pd.melt(up, id_vars=[\"asset\"], value_vars=positive_returns_list)\n    \n    # z scores\n    ztest_lr_gen_values = ztest(df[returns_list], gen[returns_list], value=0)[1]\n    ztest_lr_down_values = ztest(df[returns_list], down[returns_list], value=0)[1]\n    ztest_lr_up_values = ztest(df[returns_list], up[returns_list], value=0)[1]\n    \n    ztest_pr_gen_values = ztest(df[positive_returns_list], gen[positive_returns_list], value=0)[1]\n    ztest_pr_down_values = ztest(df[positive_returns_list], down[positive_returns_list], value=0)[1]\n    ztest_pr_up_values = ztest(df[positive_returns_list], up[positive_returns_list], value=0)[1]\n                                \n    gen_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    down_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    up_pr_df.replace({\"variable\": replace_dict}, inplace=True)\n    \n\n    primary_color = \"#1781b3\"\n    secondary_color = \"#00957e\"\n    \n    clrs_pr_gen = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_gen_values]\n    clrs_pr_down = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_down_values]\n    clrs_pr_up = ['grey' if (x > 0.05) else primary_color for x in ztest_pr_up_values]\n    \n    clrs_lr_gen = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_gen_values]\n    clrs_lr_down = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_down_values]\n    clrs_lr_up = ['grey' if (x > 0.05) else secondary_color for x in ztest_lr_up_values]\n        \n    \n    significance = [*clrs_pr_gen, *clrs_pr_down, *clrs_pr_up, *clrs_lr_gen, *clrs_lr_down, *clrs_lr_up].count(\"grey\") / 42\n    \n    print(f\"Significance: {significance}, thr: {thr}\")\n\n    fig = plt.figure(figsize=(13, 10))\n\n    fig, ax = plt.subplot_mosaic([['upper', 'upper', 'upper', 'upper'],\n                                  ['lower', 'lower', 'lower', 'lower'],\n                                  ['upper left', 'upper left', 'upper right', 'upper right'],\n                                  ['lower left', 'lower left', 'lower right', 'lower right']],\n                                gridspec_kw={'height_ratios': [6, 2, 3, 1]},\n                                figsize=(13, 10),\n                                constrained_layout=True)\n    \n    sns.barplot(x=\"variable\", y=\"value\", data=gen_lr_df, ax=ax[\"upper\"], ci=None, color=primary_color, palette=clrs_pr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=down_lr_df, ax=ax[\"upper left\"], ci=None, color=primary_color, palette=clrs_pr_down)\n    sns.barplot(x=\"variable\", y=\"value\", data=up_lr_df, ax=ax[\"upper right\"], ci=None, color=primary_color, palette=clrs_pr_up)\n\n    sns.barplot(x=\"variable\", y=\"value\", data=gen_pr_df, ax=ax[\"lower\"], ci=None, color=secondary_color, palette=clrs_lr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=down_pr_df, ax=ax[\"lower left\"], ci=None, color=secondary_color, palette=clrs_lr_gen)\n    sns.barplot(x=\"variable\", y=\"value\", data=up_pr_df, ax=ax[\"lower right\"], ci=None, color=secondary_color, palette=clrs_lr_gen)\n\n    \n    ax[\"upper\"].set_title(f'Total returns, sample size {gen.shape[0]}', fontsize = 15)\n    ax[\"upper left\"].set_title(f'After downtrend returns, sample size {down.shape[0]}')\n    ax[\"upper right\"].set_title(f'After uptrend returns, sample size {up.shape[0]}')\n    \n    ax[\"upper\"].get_shared_x_axes().join(ax[\"upper\"], ax[\"lower\"])\n    ax[\"upper left\"].get_shared_x_axes().join(ax[\"upper left\"], ax[\"lower left\"])\n    ax[\"upper right\"].get_shared_x_axes().join(ax[\"upper right\"], ax[\"lower right\"])\n    \n    ax[\"upper\"].set_ylim(-0.10, 0.10)\n    ax[\"upper left\"].set_ylim(-0.10, 0.10)\n    ax[\"upper right\"].set_ylim(-0.10, 0.10)\n    \n    ax[\"lower\"].set_ylim(0, 1)\n    ax[\"lower left\"].set_ylim(0, 1)\n    ax[\"lower right\"].set_ylim(0, 1)\n    \n    ax[\"upper\"].set_xlabel(None)\n    ax[\"upper left\"].set_xlabel(None)\n    ax[\"upper right\"].set_xlabel(None)\n    ax[\"lower\"].set_xlabel(None)\n    ax[\"lower left\"].set_xlabel(None)\n    ax[\"lower right\"].set_xlabel(None)\n    \n    ax[\"upper\"].set_ylabel(\"Mean log returns\", labelpad=10)\n    ax[\"upper left\"].set_ylabel(\"Mean lr\", labelpad=10)\n    ax[\"upper right\"].set_ylabel(None)\n    \n    ax[\"lower\"].set_ylabel(\"Positive returns probability\", labelpad=25)\n    ax[\"lower left\"].set_ylabel(\"Pr probability\", labelpad=25)\n    ax[\"lower right\"].set_ylabel(None)\n    \n    ax[\"upper\"].tick_params(axis='x', labelbottom=False)\n    ax[\"upper left\"].tick_params(axis='x', labelbottom=False)\n    ax[\"upper right\"].tick_params(axis='x', labelbottom=False)\n    \n    ax[\"lower\"].tick_params(axis='x')\n    ax[\"lower left\"].tick_params(axis='x', rotation=45)\n    ax[\"lower right\"].tick_params(axis='x', rotation=45)\n    \n    \n    for index_1, subplot in enumerate(plot_label):\n        for index_2, p in enumerate(ax[subplot].patches):\n            if index_2 in col_label[index_1]:\n                label_color = primary_color\n                if \"lower\" in subplot:\n                    label_color = secondary_color\n                ax[subplot].text(p.get_x() + p.get_width()/2., p.get_height(), '{0:.2f}'.format(p.get_height()), fontsize=12, color=label_color, ha='center', va='bottom')\n    \n    ax[\"lower\"].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    ax[\"lower left\"].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    ax[\"lower right\"].hlines(y = 0.5, xmin = 0, xmax = 6, color = 'black', linewidth=2)\n    \n    \n    sns.despine()\n        \n    plt.savefig(f\"barplot_{pattern}.png\")","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:59.366833Z","iopub.execute_input":"2022-04-10T13:47:59.367321Z","iopub.status.idle":"2022-04-10T13:47:59.397683Z","shell.execute_reply.started":"2022-04-10T13:47:59.367281Z","shell.execute_reply":"2022-04-10T13:47:59.396774Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.0 Long and short candles","metadata":{}},{"cell_type":"code","source":"upper_th = 0.10\nlower_th = 0.01\n\nsmall_candle = coin_df[\n    (coin_df[\"candle\"] < coin_df[\"body_mean\"] * lower_th) \n]\n\nmedium_candle = coin_df[\n    (coin_df[\"candle\"] > coin_df[\"body_mean\"] * lower_th) \n    & (coin_df[\"candle\"] < coin_df[\"body_mean\"] * upper_th)\n]\n\nlarge_candle = coin_df[\n    (coin_df[\"candle\"] > coin_df[\"body_mean\"] * upper_th)\n]\n\nsmall_candle[\"small_candle\"] = 1\nmedium_candle[\"medium_candle\"] = 1\nlarge_candle[\"large_candle\"] = 1\n\ncoin_df = coin_df.join(small_candle[\"small_candle\"]).fillna(0)\ncoin_df = coin_df.join(medium_candle[\"medium_candle\"]).fillna(0)\ncoin_df = coin_df.join(large_candle[\"large_candle\"]).fillna(0)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:47:59.399345Z","iopub.execute_input":"2022-04-10T13:47:59.399611Z","iopub.status.idle":"2022-04-10T13:48:01.20908Z","shell.execute_reply.started":"2022-04-10T13:47:59.399579Z","shell.execute_reply":"2022-04-10T13:48:01.208124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.1 Baseline market movement metrics","metadata":{}},{"cell_type":"code","source":"# calc_metrics_2(coin_df.reset_index(), \"asset_ID\", [\"upper\", \"lower\"], [[6], [6]])\ncalc_metrics(coin_df.reset_index(), \"asset_ID\", [[0, 0], [1, 0], [0, 2]], [[6], [6], [4]])","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:01.210374Z","iopub.execute_input":"2022-04-10T13:48:01.21137Z","iopub.status.idle":"2022-04-10T13:48:03.31519Z","shell.execute_reply.started":"2022-04-10T13:48:01.211324Z","shell.execute_reply":"2022-04-10T13:48:03.31433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"How to read the chart:\n* The upper chart shows mean log-returns comparing today and day x in the future.\n* The lower chart shows the probability of positive market returns comparing today and day x in the future.\n* Grey bars indicate statistically insignificant results (z-test).\n* Left charts shows general market direction after certain canldestick pattern\n* Middle charts shows market direction after certain canldestick pattern when market is in the downtrend\n* Right charts shows market direction after certain canldestick pattern when market is in the uptrend","metadata":{}},{"cell_type":"markdown","source":"## 3.2 Bullish Marubozu","metadata":{}},{"cell_type":"code","source":"bull_marubozu = coin_df[\n    ((coin_df[\"high\"] - coin_df[\"close\"]) / coin_df[\"close\"] < 0.003)\n    & ((coin_df[\"low\"] - coin_df[\"open\"]) / coin_df[\"open\"] < 0.003)\n    & (coin_df[\"upper_shadow_v_real_body\"] < 0.09)\n    & (coin_df[\"lower_shadow_v_real_body\"] < 0.09)\n    & (coin_df[\"close\"] > coin_df[\"open\"])\n#     & (coin_df[\"medium_candle\"] == 1)\n]\n\nbull_marubozu[\"bull_marubozu\"] = 1\ncoin_df2 = coin_df.join(bull_marubozu[\"bull_marubozu\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"bull_marubozu\", [\"upper\",\"lower\", \"lower left\", \"upper right\", \"lower right\"], [[6], [6], [6], [6], [6]])\ncalc_metrics(coin_df2, \"bull_marubozu\", [[0, 0], [1, 0], [1, 1], [0, 2], [1, 2]], [[6], [6], [6], [6], [6]])\n\nplot_patterns(coin_df2[coin_df2[\"bull_marubozu\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:03.316453Z","iopub.execute_input":"2022-04-10T13:48:03.317108Z","iopub.status.idle":"2022-04-10T13:48:05.19857Z","shell.execute_reply.started":"2022-04-10T13:48:03.317046Z","shell.execute_reply":"2022-04-10T13:48:05.197902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.3 Bearish Marubozu","metadata":{}},{"cell_type":"code","source":"bear_marubozu = coin_df[\n    ((coin_df[\"low\"] - coin_df[\"close\"]) / coin_df[\"close\"] < 0.003)\n    & ((coin_df[\"high\"] - coin_df[\"open\"]) / coin_df[\"open\"] < 0.003) \n    & (coin_df[\"upper_shadow_v_real_body\"] < 0.09)\n    & (coin_df[\"lower_shadow_v_real_body\"] < 0.09)\n    & (coin_df[\"close\"] < coin_df[\"open\"])\n#     & (coin_df[\"medium_candle\"] == 1)\n]\n\nbear_marubozu[\"bear_marubozu\"] = 1\ncoin_df2 = coin_df.join(bear_marubozu[\"bear_marubozu\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"bear_marubozu\", [\"upper\", \"lower\", \"upper left\", \"lower left\"], [[4], [4], [4], [4]])\ncalc_metrics(coin_df2, \"bear_marubozu\", [[0, 0], [1, 0], [0, 1], [1, 1]], [[4], [4], [4], [4]])\n\nplot_patterns(coin_df2[coin_df2[\"bear_marubozu\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:05.199572Z","iopub.execute_input":"2022-04-10T13:48:05.200318Z","iopub.status.idle":"2022-04-10T13:48:06.837778Z","shell.execute_reply.started":"2022-04-10T13:48:05.200281Z","shell.execute_reply":"2022-04-10T13:48:06.83687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.4 Hammer","metadata":{}},{"cell_type":"code","source":"thr = 1.7\n\nhammer = coin_df[\n    ((coin_df[\"high\"] - coin_df[\"close\"]) * thr < (coin_df[\"close\"] - coin_df[\"open\"]))\n    & ((coin_df[\"close\"] - coin_df[\"open\"]) * thr < (coin_df[\"open\"] - coin_df[\"low\"]))\n    & (coin_df[\"close\"] > coin_df[\"open\"])\n#     & (coin_df[\"medium_candle\"] == 1)\n]\n\nhammer[\"hammer\"] = 1\ncoin_df2 = coin_df.join(hammer[\"hammer\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"hammer\", [\"upper\", \"lower\", \"upper right\", \"lower right\"], [[6], [6], [6], [6]])\ncalc_metrics(coin_df2, \"hammer\", [[0, 0], [1, 0], [0, 2], [1, 2]], [[6], [6], [6], [6]])\n\nplot_patterns(coin_df2[coin_df2[\"hammer\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:06.839122Z","iopub.execute_input":"2022-04-10T13:48:06.839375Z","iopub.status.idle":"2022-04-10T13:48:08.605984Z","shell.execute_reply.started":"2022-04-10T13:48:06.839343Z","shell.execute_reply":"2022-04-10T13:48:08.605005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.5 Hanging man","metadata":{}},{"cell_type":"code","source":"thr = 2.2\n\nhang_man = coin_df[\n    ((coin_df[\"high\"] - coin_df[\"open\"]) * thr < (coin_df[\"open\"] - coin_df[\"close\"]))\n    & ((coin_df[\"open\"] - coin_df[\"close\"]) * thr < (coin_df[\"close\"] - coin_df[\"low\"]))\n    & (coin_df[\"close\"] < coin_df[\"open\"])\n#     & (coin_df[\"medium_candle\"] == 1)\n]\n\nhang_man[\"hang_man\"] = 1\ncoin_df2 = coin_df.join(hang_man[\"hang_man\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"hang_man\", [\"upper\", \"lower\"], [[0], [6]])\ncalc_metrics(coin_df2, \"hang_man\", [[0, 0], [1, 0], [1, 1]], [[0], [6], [6]])\n\nplot_patterns(coin_df2[coin_df2[\"hang_man\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:08.607379Z","iopub.execute_input":"2022-04-10T13:48:08.607703Z","iopub.status.idle":"2022-04-10T13:48:10.3577Z","shell.execute_reply.started":"2022-04-10T13:48:08.607666Z","shell.execute_reply":"2022-04-10T13:48:10.356744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.6 Inverted hammer","metadata":{}},{"cell_type":"code","source":"thr = 2\n\ninv_hammer = coin_df[\n    ((coin_df[\"open\"] - coin_df[\"low\"]) * thr < (coin_df[\"close\"] - coin_df[\"open\"]))\n    & ((coin_df[\"close\"] - coin_df[\"open\"]) * thr < (coin_df[\"high\"] - coin_df[\"close\"]))\n    & (coin_df[\"close\"] > coin_df[\"open\"])\n    #& (coin_df[\"medium_candle\"] == 1)\n]\n\ninv_hammer[\"inv_hammer\"] = 1\ncoin_df2 = coin_df.join(inv_hammer[\"inv_hammer\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"inv_hammer\", [\"upper\", \"lower\", \"upper left\", \"lower left\"], [[4], [4], [4], [5]])\ncalc_metrics(coin_df2, \"inv_hammer\", [[0, 0], [1, 0], [0, 1], [1, 1]], [[4], [4], [4], [5]])\n\nplot_patterns(coin_df2[coin_df2[\"inv_hammer\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:10.359433Z","iopub.execute_input":"2022-04-10T13:48:10.359699Z","iopub.status.idle":"2022-04-10T13:48:11.961915Z","shell.execute_reply.started":"2022-04-10T13:48:10.359666Z","shell.execute_reply":"2022-04-10T13:48:11.960989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.7 Shooting star","metadata":{}},{"cell_type":"code","source":"thr = 2\n\nshot_star = coin_df[    \n    ((coin_df[\"close\"] - coin_df[\"low\"]) * thr < (coin_df[\"open\"] - coin_df[\"close\"]))\n    & ((coin_df[\"open\"] - coin_df[\"close\"]) * thr < (coin_df[\"high\"] - coin_df[\"open\"]))\n    & (coin_df[\"close\"] < coin_df[\"open\"])\n#     & (coin_df[\"medium_candle\"] == 1)\n]\n\nshot_star[\"shot_star\"] = 1\ncoin_df2 = coin_df.join(shot_star[\"shot_star\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"shot_star\", [\"upper\",\"lower\", \"upper left\", \"lower left\", \"upper right\", \"lower right\"], [[5], [5], [6], [5], [4], [5]])\ncalc_metrics(coin_df2, \"shot_star\", [[0, 0], [1, 0], [0, 1], [1, 1], [0, 2], [1, 2]], [[5], [5], [6], [5], [4], [5]])\nplot_patterns(coin_df2[coin_df2[\"shot_star\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:11.963351Z","iopub.execute_input":"2022-04-10T13:48:11.963891Z","iopub.status.idle":"2022-04-10T13:48:13.685334Z","shell.execute_reply.started":"2022-04-10T13:48:11.963774Z","shell.execute_reply":"2022-04-10T13:48:13.684399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.8 Spinning top","metadata":{}},{"cell_type":"code","source":"spin_top = coin_df[\n    (coin_df[\"real_body\"] / coin_df[\"upper_shadow\"] < 0.20)\n    & (coin_df[\"real_body\"] / coin_df[\"lower_shadow\"] < 0.20)\n    & (coin_df[\"real_body\"] / coin_df[\"upper_shadow\"] > 0.10)\n    & (coin_df[\"real_body\"] / coin_df[\"lower_shadow\"] > 0.10)\n    & (coin_df[\"upper_shadow\"] / coin_df[\"lower_shadow\"] > 0.95)\n    & (coin_df[\"upper_shadow\"] / coin_df[\"lower_shadow\"] < 1.05)\n]\n\nspin_top[\"spin_top\"] = 1\ncoin_df2 = coin_df.join(spin_top[\"spin_top\"]).fillna(0)\n\n# calc_metrics_2(coin_df2, \"spin_top\", [\"upper\",\"lower\", \"upper left\", \"lower left\", \"upper right\", \"lower right\"], [[5], [5], [6], [5], [4], [5]])\ncalc_metrics(coin_df2, \"spin_top\", [[0, 0], [1, 0], [0, 1], [1, 1], [1, 2]], [[6], [6], [6], [6], [4]])\nplot_patterns(coin_df2[coin_df2[\"spin_top\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:13.686665Z","iopub.execute_input":"2022-04-10T13:48:13.686904Z","iopub.status.idle":"2022-04-10T13:48:15.391807Z","shell.execute_reply.started":"2022-04-10T13:48:13.686874Z","shell.execute_reply":"2022-04-10T13:48:15.390989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.9 Doji","metadata":{}},{"cell_type":"code","source":"doji = coin_df[\n    (coin_df[\"real_body\"] / coin_df[\"lower_shadow\"] < 0.10)\n    & (coin_df[\"real_body\"] / coin_df[\"upper_shadow\"] < 0.10)\n    & (coin_df[\"upper_shadow\"] / coin_df[\"lower_shadow\"] > 0.95)\n    & (coin_df[\"upper_shadow\"] / coin_df[\"lower_shadow\"] < 1.05)\n]\n\n\ndoji[\"doji\"] = 1\ncoin_df2 = coin_df.join(doji[\"doji\"]).fillna(0)\n\n# calc_metrics(coin_df2, \"doji\", \"\")\ncalc_metrics(coin_df2, \"doji\", [[0, 0], [1, 0], [0, 1], [1, 1], [1, 2]], [[6], [4], [6], [4], [4]])\n\nplot_patterns(coin_df2[coin_df2[\"doji\"] > 0][:20], False, True)","metadata":{"execution":{"iopub.status.busy":"2022-04-10T13:48:15.393109Z","iopub.execute_input":"2022-04-10T13:48:15.393331Z","iopub.status.idle":"2022-04-10T13:48:17.232859Z","shell.execute_reply.started":"2022-04-10T13:48:15.393303Z","shell.execute_reply":"2022-04-10T13:48:17.232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}