{ "cells": [ { "cell_type": "markdown", "id": "257110ac-fb97-4051-adfe-81c1130b8cd2", "metadata": {}, "source": [ "# MTF analysis" ] }, { "cell_type": "code", "execution_count": null, "id": "957fc6b1-f3b9-4778-ab72-28921aed1449", "metadata": {}, "outputs": [], "source": [ "from vectorbtpro import *\n", "# whats_imported()\n", "\n", "vbt.settings.set_theme(\"dark\")" ] }, { "cell_type": "markdown", "id": "c705f5df-b3ab-4a8f-8ea8-952d0cc6cd81", "metadata": {}, "source": [ "## Data" ] }, { "cell_type": "code", "execution_count": null, "id": "8356ce73-60e4-469e-b3b3-2e414b82eb5e", "metadata": {}, "outputs": [], "source": [ "# h1_data = vbt.BinanceData.pull(\n", "# \"BTCUSDT\", \n", "# start=\"2020-01-01 UTC\", \n", "# end=\"2021-01-01 UTC\",\n", "# timeframe=\"1h\"\n", "# )\n", "\n", "# h1_data.to_hdf()" ] }, { "cell_type": "code", "execution_count": null, "id": "06507a95-fc57-49db-9b97-62ccc4184055", "metadata": {}, "outputs": [], "source": [ "h1_data = vbt.HDFData.pull('BinanceData.h5')" ] }, { "cell_type": "code", "execution_count": null, "id": "2fab718a-09f2-4640-b477-dd681753ac53", "metadata": {}, "outputs": [], "source": [ "h1_data.wrapper.index" ] }, { "cell_type": "code", "execution_count": null, "id": "2a930576-729d-4c06-a9a3-6a8ad3de34e6", "metadata": {}, "outputs": [], "source": [ "h1_resampler = h1_data.wrapper.get_resampler(\"1h\")\n", "h1_resampler.index_difference(reverse=True)" ] }, { "cell_type": "code", "execution_count": null, "id": "d4124583-e303-4eda-bfb0-f97e3908ef91", "metadata": {}, "outputs": [], "source": [ "h1_data.wrapper.columns" ] }, { "cell_type": "code", "execution_count": null, "id": "f39bc0ee-6e5c-4c87-93a3-1b5a31fe86f4", "metadata": {}, "outputs": [], "source": [ "h1_ohlcv_data = h1_data[[\"Open\", \"High\", \"Low\", \"Close\", \"Volume\"]]" ] }, { "cell_type": "code", "execution_count": null, "id": "461c8632-4e29-4b0d-8e85-72ea3b1754ae", "metadata": {}, "outputs": [], "source": [ "h4_ohlcv = h1_ohlcv_data.get().resample(\"4h\").agg({\n", " \"Open\": \"first\",\n", " \"High\": \"max\",\n", " \"Low\": \"min\",\n", " \"Close\": \"last\",\n", " \"Volume\": \"sum\"\n", "})\n", "h4_ohlcv" ] }, { "cell_type": "code", "execution_count": null, "id": "b84728de-a16b-417f-9ee8-ddafce9b24c3", "metadata": {}, "outputs": [], "source": [ "print(h1_ohlcv_data.get().iloc[:4])" ] }, { "cell_type": "code", "execution_count": null, "id": "def713aa-9e46-488a-b100-83a563c5c30f", "metadata": {}, "outputs": [], "source": [ "print(h4_ohlcv.iloc[[0]])" ] }, { "cell_type": "code", "execution_count": null, "id": "8e0d8b54-f1b6-4ff0-851e-c0cb8b8c415a", "metadata": {}, "outputs": [], "source": [ "print(vbt.prettify(vbt.BinanceData.feature_config))" ] }, { "cell_type": "code", "execution_count": null, "id": "5fcdcdbd-4274-4078-9e8f-5b64c4cd1e46", "metadata": {}, "outputs": [], "source": [ "h1_data.use_feature_config_of(vbt.BinanceData)\n", "\n", "h4_data = h1_data.resample(\"4h\")\n", "d1_data = h1_data.resample(\"1d\")" ] }, { "cell_type": "code", "execution_count": null, "id": "5980b577-d6ee-484d-8faf-9db6647dd29b", "metadata": {}, "outputs": [], "source": [ "print(d1_data.get().iloc[[0, -1]])" ] }, { "cell_type": "code", "execution_count": null, "id": "000ebb64-4228-4967-aaac-2dc88975da61", "metadata": {}, "outputs": [], "source": [ "print(vbt.BinanceData.pull(\n", " \"BTCUSDT\", \n", " start=\"2020-01-01 UTC\", \n", " end=\"2021-01-01 UTC\",\n", " timeframe=\"1d\"\n", ").get().iloc[[0, -1]])" ] }, { "cell_type": "markdown", "id": "f47840ab-b31d-49b3-bf24-d6406a2b542c", "metadata": {}, "source": [ "## Alignment" ] }, { "cell_type": "markdown", "id": "0c0ebc21-981a-4c09-8b38-2339e204cf5d", "metadata": {}, "source": [ "### Pandas" ] }, { "cell_type": "code", "execution_count": null, "id": "73b897e3-4f35-41b2-a5c1-8f1c4010c0c2", "metadata": {}, "outputs": [], "source": [ "h1_close = h1_data.get(\"Close\")\n", "h4_close = h4_data.get(\"Close\")" ] }, { "cell_type": "code", "execution_count": null, "id": "9dccb01e-8056-4dc0-b5f6-0be44e3f5099", "metadata": {}, "outputs": [], "source": [ "h1_close.iloc[:4]" ] }, { "cell_type": "code", "execution_count": null, "id": "0a3a3c1c-0747-4a18-9462-863162dcdddb", "metadata": {}, "outputs": [], "source": [ "h4_close.iloc[:1]" ] }, { "cell_type": "code", "execution_count": null, "id": "b1c22394-c1fc-4abc-8036-788848acbe92", "metadata": {}, "outputs": [], "source": [ "h1_h4_ratio = h1_close / h4_close\n", "h1_h4_ratio.iloc[:4]" ] }, { "cell_type": "code", "execution_count": null, "id": "acc7216c-0457-46a0-819d-a4675780f242", "metadata": {}, "outputs": [], "source": [ "h4_close_shifted = h4_close.shift()\n", "h1_h4_ratio = h1_close / h4_close_shifted\n", "h1_h4_ratio.iloc[:8]" ] }, { "cell_type": "code", "execution_count": null, "id": "e8dbbb29-8b79-4c8c-8ce8-5c2582434c95", "metadata": {}, "outputs": [], "source": [ "h1_h4_ratio.shift(-1).iloc[:8]" ] }, { "cell_type": "code", "execution_count": null, "id": "fd546cfa-559d-45a3-8e35-b2af75bd9df6", "metadata": {}, "outputs": [], "source": [ "h4_h1_close = h4_close.shift(1).resample(\"1h\").last().shift(-1).ffill()\n", "h4_h1_close.iloc[:8]" ] }, { "cell_type": "code", "execution_count": null, "id": "ba830c23-074b-4ab9-ab4d-3b738a14be56", "metadata": {}, "outputs": [], "source": [ "fig = h1_close.rename(\"H1\").iloc[:16].vbt.plot()\n", "h4_h1_close.rename(\"H4_H1\").iloc[:16].vbt.plot(fig=fig).show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "6e8c73ee-5c05-4e95-89d0-ad195e138a96", "metadata": {}, "outputs": [], "source": [ "h1_h4_ratio = h1_close / h4_h1_close\n", "h1_h4_ratio" ] }, { "cell_type": "code", "execution_count": null, "id": "023c506a-8e48-43e6-9244-9093c876edb0", "metadata": {}, "outputs": [], "source": [ "h1_open = h1_data.get(\"Open\")\n", "h4_open = h4_data.get(\"Open\")\n", "\n", "h1_open.iloc[:8]" ] }, { "cell_type": "code", "execution_count": null, "id": "ca1bd16a-4157-43ba-be2f-61749ba83a3a", "metadata": {}, "outputs": [], "source": [ "h4_h1_open = h4_open.resample(\"1h\").first().ffill()\n", "h4_h1_open.iloc[:8]" ] }, { "cell_type": "markdown", "id": "ffcce240-8595-470d-b743-9b9f743f4543", "metadata": {}, "source": [ "### VBT" ] }, { "cell_type": "code", "execution_count": null, "id": "8e90d2b3-d4b0-4b4f-ae19-fc6e0260ac16", "metadata": {}, "outputs": [], "source": [ "h4_close.vbt.realign_closing(\"1h\")" ] }, { "cell_type": "code", "execution_count": null, "id": "328daf52-40c4-40a8-9614-ea83c702f429", "metadata": {}, "outputs": [], "source": [ "h4_open.vbt.realign_opening(\"1h\")" ] }, { "cell_type": "markdown", "id": "fceafe15-dd02-495f-bbcb-7978981dbfc8", "metadata": {}, "source": [ "#### Resampler" ] }, { "cell_type": "code", "execution_count": null, "id": "d9a79ae2-812a-4693-b68f-4b20246f86d4", "metadata": {}, "outputs": [], "source": [ "h4_h1_resampler = h4_close.vbt.wrapper.get_resampler(\"1h\")\n", "h4_h1_resampler.source_index" ] }, { "cell_type": "code", "execution_count": null, "id": "75260aef-922a-46d9-b2c2-268247e57c20", "metadata": {}, "outputs": [], "source": [ "h4_h1_resampler.target_index" ] }, { "cell_type": "code", "execution_count": null, "id": "1bcb75a6-1808-4738-b746-80805817bd97", "metadata": {}, "outputs": [], "source": [ "h4_h1_resampler.source_freq" ] }, { "cell_type": "code", "execution_count": null, "id": "eb51ba6c-2d10-4f4e-9d5e-432d515d72c4", "metadata": {}, "outputs": [], "source": [ "h4_h1_resampler.target_freq" ] }, { "cell_type": "code", "execution_count": null, "id": "ef759223-074b-4961-87f4-47d9ab48e31a", "metadata": {}, "outputs": [], "source": [ "pd_resampler = h4_close.resample(\"1h\")\n", "vbt.Resampler.from_pd_resampler(pd_resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "402d9361-3657-46de-bf30-5a57d3006c50", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler.from_date_range(\n", " source_index=h4_close.index,\n", " source_freq=\"4h\",\n", " start=\"2020-01-01 10:00:00\",\n", " end=\"2020-01-01 22:00:00\",\n", " freq=\"1h\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "52df63ec-3951-4ed7-a1ea-18628dc9a0c0", "metadata": {}, "outputs": [], "source": [ "h4_close.vbt.realign_closing(resampler)" ] }, { "cell_type": "markdown", "id": "beef78cd-9046-456f-8484-14e1e04b3c2f", "metadata": {}, "source": [ "#### Custom index" ] }, { "cell_type": "code", "execution_count": null, "id": "63ff2b4e-46b9-4ad3-8ef6-2f751ad7a9d8", "metadata": {}, "outputs": [], "source": [ "target_index = pd.Index([\n", " \"2020-01-01\",\n", " \"2020-02-01\",\n", " \"2020-03-01\",\n", " \"2020-04-01\",\n", " \"2020-05-01\",\n", " \"2020-06-01\",\n", " \"2020-07-01\",\n", " \"2020-08-01\",\n", " \"2020-09-01\",\n", " \"2020-10-01\",\n", " \"2020-11-01\",\n", " \"2020-12-01\",\n", " \"2021-01-01\"\n", "])\n", "resampler = vbt.Resampler(h4_close.index, target_index, target_freq=False)\n", "h4_close.vbt.realign_closing(resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "e5b6de84-d1a8-4d16-9677-fd8e7d8e5b1f", "metadata": {}, "outputs": [], "source": [ "h4_close[h4_close.index < \"2020-09-01\"].iloc[-1]" ] }, { "cell_type": "code", "execution_count": null, "id": "3612f6b6-c960-4a10-b581-ccfbaf583cf8", "metadata": {}, "outputs": [], "source": [ "h4_open.vbt.realign_opening(resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "4fed1a9d-0867-49a1-bd20-4acf2d974e91", "metadata": {}, "outputs": [], "source": [ "h4_open[h4_open.index <= \"2020-08-01\"].iloc[-1]" ] }, { "cell_type": "code", "execution_count": null, "id": "063cfaaf-045c-40f4-be79-c177196c884b", "metadata": {}, "outputs": [], "source": [ "target_index = pd.Index([\n", " \"2020-01-01\",\n", " \"2020-02-01\",\n", "])\n", "resampler = vbt.Resampler(h4_close.index, target_index, target_freq=False)\n", "h4_close.vbt.realign_closing(resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "5f3fb1cf-8646-4c71-b38a-b7631d94907e", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler(h4_close.index, target_index, target_freq=\"30d\")\n", "h4_close.vbt.realign_closing(resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "07f61c2b-ea6a-4b6f-9633-760ce35901c1", "metadata": {}, "outputs": [], "source": [ "h4_open.vbt.realign(\"2020-06-07 12:15:00\")" ] }, { "cell_type": "code", "execution_count": null, "id": "42601b68-e4ea-4b70-b302-4f6bb2025969", "metadata": {}, "outputs": [], "source": [ "h4_close.vbt.realign(\n", " \"2020-06-07 12:15:00\", \n", " source_rbound=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "8a5685b5-4847-4e59-8463-e7690bcf84f7", "metadata": {}, "outputs": [], "source": [ "h4_high = h4_data.get(\"High\")\n", "h4_high.vbt.realign(\n", " target_index, \n", " source_rbound=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "65eb1d9f-a7a6-4c03-89ec-68db9685c1d1", "metadata": {}, "outputs": [], "source": [ "h4_high.index[h4_high.index < \"2020-02-01\"][-1]" ] }, { "cell_type": "code", "execution_count": null, "id": "a9873388-768a-4ff5-a034-081779b3f879", "metadata": {}, "outputs": [], "source": [ "h4_high.vbt.realign(\n", " target_index, \n", " source_rbound=True,\n", " target_rbound=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "3be78c1c-1424-406c-b959-64bdc8cbd826", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler(h4_high.index, target_index)\n", "resampler.target_rbound_index" ] }, { "cell_type": "code", "execution_count": null, "id": "0631eb39-d180-461f-93c6-3b9c4b5efce2", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler(\n", " h4_high.index, \n", " target_index, \n", " target_freq=pd.offsets.MonthBegin(1))\n", "resampler.target_rbound_index" ] }, { "cell_type": "code", "execution_count": null, "id": "b96efd81-4a14-4f65-8663-5d049b01a42b", "metadata": {}, "outputs": [], "source": [ "h4_high.vbt.realign(\n", " resampler.replace(\n", " target_index=resampler.target_rbound_index, \n", " target_freq=False\n", " ), \n", " wrap_kwargs=dict(index=target_index)\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "1e3f96e1-8161-4417-8201-5084aaec43ee", "metadata": {}, "outputs": [], "source": [ "h4_high.vbt.realign(\n", " target_index, \n", " freq=pd.offsets.MonthBegin(1),\n", " target_rbound=\"pandas\"\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "bac8e960-94ac-420a-81db-58db70a623d3", "metadata": {}, "outputs": [], "source": [ "h4_high[h4_high.index < \"2020-03-01\"].resample(vbt.offset(\"M\")).last()" ] }, { "cell_type": "markdown", "id": "fa904b11-4aa9-4a3c-9990-4dfb17e5092f", "metadata": {}, "source": [ "#### Numeric index" ] }, { "cell_type": "code", "execution_count": null, "id": "acfcad7a-b094-4378-a380-8dd5dc8bc4ea", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler(\n", " source_index=np.arange(len(h4_high)),\n", " target_index=np.arange(len(h4_high))[::6],\n", " source_freq=1,\n", " target_freq=6\n", ")\n", "h4_high.vbt.realign(\n", " resampler, \n", " source_rbound=True,\n", " target_rbound=True\n", ")" ] }, { "cell_type": "markdown", "id": "d3ec6678-66b8-4a9d-92cf-a41ca96a9adb", "metadata": {}, "source": [ "#### Forward filling" ] }, { "cell_type": "code", "execution_count": null, "id": "3f27ab10-cba8-4c5f-97e6-e0533943795a", "metadata": {}, "outputs": [], "source": [ "min5_index = vbt.date_range(start=\"2020\", freq=\"5min\", periods=3)\n", "min1_index = vbt.date_range(start=\"2020\", freq=\"1min\", periods=15)\n", "min5_mask = pd.Series(False, index=min5_index)\n", "min5_mask.iloc[0] = True\n", "min5_mask.iloc[2] = True\n", "\n", "resampler = vbt.Resampler(min5_index, min1_index)\n", "min1_mask = min5_mask.vbt.realign_closing(resampler)\n", "min1_mask" ] }, { "cell_type": "code", "execution_count": null, "id": "ab594857-24ea-4316-83e9-aa65c0be621c", "metadata": {}, "outputs": [], "source": [ "min1_mask = min5_mask.vbt.realign_closing(resampler, ffill=False)\n", "min1_mask" ] }, { "cell_type": "code", "execution_count": null, "id": "053aeb5f-b8c1-46d5-849a-ec431e64ce8c", "metadata": {}, "outputs": [], "source": [ "min1_mask = min1_mask.fillna(False).astype(bool)\n", "min1_mask" ] }, { "cell_type": "markdown", "id": "0a220a77-0bd8-43f3-92ea-d532b883a793", "metadata": {}, "source": [ "### Indicators" ] }, { "cell_type": "code", "execution_count": null, "id": "5f1b6073-9e03-49cf-a212-83953d9910e3", "metadata": {}, "outputs": [], "source": [ "h4_sma = vbt.talib(\"SMA\").run(h4_data.get(\"Close\"), skipna=True).real\n", "d1_sma = vbt.talib(\"SMA\").run(d1_data.get(\"Close\"), skipna=True).real\n", "\n", "h4_sma = h4_sma.ffill()\n", "d1_sma = d1_sma.ffill()" ] }, { "cell_type": "code", "execution_count": null, "id": "13ace4e8-4647-4f29-a516-142a94460a76", "metadata": {}, "outputs": [], "source": [ "resampler = vbt.Resampler(\n", " d1_sma.index,\n", " h4_sma.index,\n", " source_freq=\"1d\",\n", " target_freq=\"4h\"\n", ")\n", "d1_h4_sma = d1_sma.vbt.realign_closing(resampler)" ] }, { "cell_type": "code", "execution_count": null, "id": "837efa98-5a41-411f-91e4-7e07db205703", "metadata": {}, "outputs": [], "source": [ "d1_sma[\"2020-12-30\":]" ] }, { "cell_type": "code", "execution_count": null, "id": "6f4fab4d-05ec-4c96-be22-7d383ad493bb", "metadata": {}, "outputs": [], "source": [ "d1_h4_sma[\"2020-12-30\":]" ] }, { "cell_type": "code", "execution_count": null, "id": "1e4de9a1-e7e4-49f4-b2d4-f5afe1895cae", "metadata": {}, "outputs": [], "source": [ "entries = h4_sma.vbt.crossed_above(d1_h4_sma)\n", "exits = h4_sma.vbt.crossed_below(d1_h4_sma)\n", "\n", "def plot_date_range(date_range):\n", " fig = h4_sma[date_range].rename(\"H4\").vbt.plot()\n", " d1_h4_sma[date_range].rename(\"D1_H4\").vbt.plot(fig=fig)\n", " entries[date_range].rename(\"Entry\").vbt.signals.plot_as_entries(\n", " y=h4_sma[date_range], fig=fig)\n", " exits[date_range].rename(\"Exit\").vbt.signals.plot_as_exits(\n", " y=h4_sma[date_range], fig=fig)\n", " return fig\n", "\n", "plot_date_range(slice(\"2020-02-01\", \"2020-03-01\")).show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "dfa7eae9-caff-49c9-b6cd-49216374cda5", "metadata": {}, "outputs": [], "source": [ "d1_open_sma = vbt.talib(\"SMA\").run(\n", " d1_data.get(\"Open\"), \n", " skipna=True\n", ").real\n", "d1_open_sma = d1_open_sma.ffill()\n", "\n", "d1_h4_open_sma = d1_open_sma.vbt.realign(\n", " resampler, \n", " source_rbound=False,\n", " target_rbound=True,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "ab960235-1f29-4558-9e3b-c8f1d4ade177", "metadata": {}, "outputs": [], "source": [ "d1_open_sma[\"2020-12-30\":]" ] }, { "cell_type": "code", "execution_count": null, "id": "5cd93da8-2e9e-46a3-b2cc-576561baca66", "metadata": {}, "outputs": [], "source": [ "d1_h4_open_sma[\"2020-12-30\":]" ] }, { "cell_type": "code", "execution_count": null, "id": "9b7e7a74-9d26-486d-b1e9-47844c4c0d26", "metadata": {}, "outputs": [], "source": [ "def generate_bandwidths(freqs):\n", " bandwidths = []\n", " for freq in freqs:\n", " close = h1_data.resample(freq).get(\"Close\")\n", " bbands = vbt.talib(\"BBANDS\").run(close, skipna=True)\n", " upperband = bbands.upperband.ffill()\n", " middleband = bbands.middleband.ffill()\n", " lowerband = bbands.lowerband.ffill()\n", " bandwidth = (upperband - lowerband) / middleband\n", " bandwidths.append(bandwidth.vbt.realign_closing(\"1h\"))\n", " df = pd.concat(bandwidths, axis=1, keys=pd.Index(freqs, name=\"timeframe\"))\n", " return df.ffill()\n", "\n", "bandwidths = generate_bandwidths([\"1h\", \"4h\", \"1d\", \"7d\"])\n", "print(bandwidths)" ] }, { "cell_type": "code", "execution_count": null, "id": "b5349999-74d9-4106-924d-b8bfa44557b3", "metadata": {}, "outputs": [], "source": [ "bandwidths.loc[:, ::-1].vbt.ts_heatmap().show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "5474bcdd-1096-46a4-97da-cb16ea310c26", "metadata": {}, "outputs": [], "source": [ ">>> bbands = vbt.talib(\"BBANDS\").run(\n", "... h1_data.get(\"Close\"), \n", "... skipna=True, \n", "... timeframe=[\"1h\", \"4h\", \"1d\", \"7d\"],\n", "... broadcast_kwargs=dict(wrapper_kwargs=dict(freq=\"1h\"))\n", "... )\n", ">>> bandwidth = (bbands.upperband - bbands.lowerband) / bbands.middleband\n", ">>> print(bandwidths)" ] }, { "cell_type": "markdown", "id": "d0ab34e7-6b65-420a-b7ad-41626267a852", "metadata": {}, "source": [ "### Testing" ] }, { "cell_type": "code", "execution_count": null, "id": "3d012722-e263-4361-a2be-f77fd57ee53c", "metadata": {}, "outputs": [], "source": [ "def generate_signals(data, freq, fast_window, slow_window):\n", " open_price = data.get(\"Open\").resample(freq).first()\n", " fast_sma = vbt.talib(\"SMA\")\\\n", " .run(\n", " open_price, \n", " fast_window, \n", " skipna=True, \n", " short_name=\"fast_sma\"\n", " )\\\n", " .real.ffill()\\\n", " .vbt.realign(data.wrapper.index)\n", " slow_sma = vbt.talib(\"SMA\")\\\n", " .run(\n", " open_price, \n", " slow_window, \n", " skipna=True, \n", " short_name=\"slow_sma\"\n", " )\\\n", " .real.ffill()\\\n", " .vbt.realign(data.wrapper.index)\n", " entries = fast_sma.vbt.crossed_above(slow_sma)\n", " exits = fast_sma.vbt.crossed_below(slow_sma)\n", " return entries, exits\n", "\n", "fast_window = [10, 20]\n", "slow_window = [20, 30]\n", "h1_entries, h1_exits = generate_signals(h1_data, \"1h\", fast_window, slow_window)\n", "h4_entries, h4_exits = generate_signals(h1_data, \"4h\", fast_window, slow_window)\n", "d1_entries, d1_exits = generate_signals(h1_data, \"1d\", fast_window, slow_window)\n", "\n", "entries = pd.concat(\n", " (h1_entries, h4_entries, d1_entries), \n", " axis=1, \n", " keys=pd.Index([\"1h\", \"4h\", \"1d\"], name=\"timeframe\")\n", ")\n", "exits = pd.concat(\n", " (h1_exits, h4_exits, d1_exits), \n", " axis=1, \n", " keys=pd.Index([\"1h\", \"4h\", \"1d\"], name=\"timeframe\")\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "be4a1fb7-231e-42a3-b113-a1e71173c96d", "metadata": {}, "outputs": [], "source": [ "(entries.astype(int) - exits.astype(int))\\\n", " .resample(\"1d\").sum()\\\n", " .vbt.ts_heatmap(\n", " trace_kwargs=dict(\n", " colorscale=[\"#ef553b\", \"rgba(0, 0, 0, 0)\", \"#17becf\"],\n", " colorbar=dict(\n", " tickvals=[-1, 0, 1], \n", " ticktext=[\"Exit\", \"\", \"Entry\"]\n", " )\n", " )\n", " ).show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "8cbd506a-8911-400e-bbe3-fc439ae5e31d", "metadata": {}, "outputs": [], "source": [ "pf = vbt.Portfolio.from_signals(\n", " h1_data,\n", " entries,\n", " exits,\n", " sl_stop=0.1,\n", " freq=\"1h\"\n", ")\n", "\n", "pf.orders.count()" ] }, { "cell_type": "code", "execution_count": null, "id": "79f8734e-cfd3-4bb3-836f-5e4c96af1078", "metadata": {}, "outputs": [], "source": [ "pf.sharpe_ratio" ] }, { "cell_type": "markdown", "id": "594dd6b4-814a-459a-9a68-a004471cbf55", "metadata": {}, "source": [ "## Aggregation" ] }, { "cell_type": "code", "execution_count": null, "id": "e1a727a9-be21-4859-81c7-f660932dbfef", "metadata": {}, "outputs": [], "source": [ "ms_data = h1_data.resample(\"M\")\n", "ms_data.get(\"Low\") / ms_data.get(\"High\") - 1" ] }, { "cell_type": "code", "execution_count": null, "id": "ba41908f-77bb-41fd-92dc-3ddfb66660c7", "metadata": {}, "outputs": [], "source": [ "h1_high = h1_data.get(\"High\")\n", "h1_low = h1_data.get(\"Low\")\n", "ms_high = h1_high.resample(vbt.offset(\"M\")).max()\n", "ms_low = h1_low.resample(vbt.offset(\"M\")).min()\n", "ms_low / ms_high - 1" ] }, { "cell_type": "code", "execution_count": null, "id": "4054b7a6-002d-40f7-8d81-906491355f2c", "metadata": {}, "outputs": [], "source": [ "ms_high = h1_high.vbt.resample_apply(\"M\", vbt.nb.max_reduce_nb)\n", "ms_low = h1_low.vbt.resample_apply(\"M\", vbt.nb.min_reduce_nb)\n", "ms_low / ms_high - 1" ] }, { "cell_type": "markdown", "id": "5b8bc23f-95a4-4dd9-92cd-87e997979eb9", "metadata": {}, "source": [ "### Custom index" ] }, { "cell_type": "markdown", "id": "49646098-0314-4c0d-8ed2-361dc5316346", "metadata": {}, "source": [ "#### Using target index" ] }, { "cell_type": "code", "execution_count": null, "id": "286732d7-1ae7-4bd9-9a8e-8a7c21e7caab", "metadata": {}, "outputs": [], "source": [ "target_index = pd.Index([\n", " \"2020-01-01\",\n", " \"2020-02-01\",\n", "])\n", "h1_high.vbt.resample_to_index(\n", " target_index, \n", " vbt.nb.max_reduce_nb\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "6c8f7530-3669-4b50-9cd8-933c638b47f9", "metadata": {}, "outputs": [], "source": [ "target_rbound_index = vbt.Resampler.get_rbound_index(\n", " target_index, \n", " pd.offsets.MonthBegin(1)\n", ")\n", "h1_high.vbt.resample_to_index(\n", " target_index.append(target_rbound_index[[-1]]), \n", " vbt.nb.max_reduce_nb\n", ").iloc[:-1]" ] }, { "cell_type": "code", "execution_count": null, "id": "41025b95-36f3-40cb-ac84-8fd0168ef481", "metadata": {}, "outputs": [], "source": [ "h1_high[:\"2020-03-01\"].resample(vbt.offset(\"M\")).max().iloc[:-1]" ] }, { "cell_type": "markdown", "id": "a2f6f226-2cdd-48b6-9a5c-9379dd2c6ec9", "metadata": {}, "source": [ "#### Using group-by" ] }, { "cell_type": "code", "execution_count": null, "id": "6ae265d2-195c-4045-9dcd-4180bb7ddb7b", "metadata": {}, "outputs": [], "source": [ "pd_resampler = h1_high.resample(vbt.offset(\"M\"))\n", "ms_high = h1_high.vbt.groupby_apply(pd_resampler, vbt.nb.max_reduce_nb)\n", "ms_low = h1_low.vbt.groupby_apply(pd_resampler, vbt.nb.min_reduce_nb)\n", "ms_low / ms_high - 1" ] }, { "cell_type": "code", "execution_count": null, "id": "b9a38ab9-18a0-4716-84cf-d276c945f2fd", "metadata": {}, "outputs": [], "source": [ "target_lbound_index = pd.Index([\n", " \"2020-01-01\",\n", " \"2020-02-01\",\n", "])\n", "target_rbound_index = pd.Index([\n", " \"2020-02-01\",\n", " \"2020-03-01\",\n", "])\n", "h1_high.vbt.resample_between_bounds(\n", " target_lbound_index, \n", " target_rbound_index,\n", " vbt.nb.max_reduce_nb\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "1b315822-a70c-4385-b0c4-2bc5c2b488eb", "metadata": {}, "outputs": [], "source": [ "h1_high.vbt.resample_between_bounds(\n", " \"2020-01-01\", \n", " vbt.date_range(\"2020-01-02\", \"2021-01-01\", freq=\"M\", inclusive=\"both\"),\n", " vbt.nb.max_reduce_nb\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "170017dd-fb6d-47ca-b819-6498d018e9e8", "metadata": {}, "outputs": [], "source": [ "h1_high.expanding().max().resample(vbt.offset(\"M\")).max()" ] }, { "cell_type": "markdown", "id": "24e72852-be2b-4b5b-bc60-d921491d1ab3", "metadata": {}, "source": [ "### Meta methods" ] }, { "cell_type": "code", "execution_count": null, "id": "986fe4e4-f9f6-47d2-b415-a22e49723af4", "metadata": {}, "outputs": [], "source": [ "@njit\n", "def mdd_nb(from_i, to_i, col, high, low):\n", " highest = np.nanmax(high[from_i:to_i, col])\n", " lowest = np.nanmin(low[from_i:to_i, col])\n", " return lowest / highest - 1\n", "\n", "vbt.pd_acc.resample_apply(\n", " \"M\",\n", " mdd_nb,\n", " vbt.Rep(\"high\"),\n", " vbt.Rep(\"low\"),\n", " broadcast_named_args=dict(\n", " high=h1_high,\n", " low=h1_low\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "a83cb89f-90b9-4563-8124-79ea7938da70", "metadata": {}, "outputs": [], "source": [ "h1_high.iloc[0:744]" ] }, { "cell_type": "code", "execution_count": null, "id": "41414c25-d863-4f83-a140-c1dfef1e4226", "metadata": {}, "outputs": [], "source": [ "h1_low.iloc[0:744].min() / h1_high.iloc[0:744].max() - 1" ] }, { "cell_type": "code", "execution_count": null, "id": "98949b71-5900-407f-b117-de2b7b50cd2e", "metadata": {}, "outputs": [], "source": [ ">>> target_lbound_index = vbt.date_range(\"2020-01-01\", \"2020-12-01\", freq=\"M\", tz=\"UTC\", inclusive=\"both\")\n", ">>> target_rbound_index = vbt.date_range(\"2020-02-01\", \"2021-01-01\", freq=\"M\", tz=\"UTC\", inclusive=\"both\")\n", ">>> vbt.pd_acc.resample_between_bounds(\n", "... target_lbound_index,\n", "... target_rbound_index,\n", "... mdd_nb,\n", "... vbt.Rep(\"high\"),\n", "... vbt.Rep(\"low\"),\n", "... broadcast_named_args=dict(\n", "... high=h1_high,\n", "... low=h1_low\n", "... )\n", "... )" ] }, { "cell_type": "markdown", "id": "d039d5e0-2562-44e1-b572-0345064bacfe", "metadata": {}, "source": [ "### Numba" ] }, { "cell_type": "code", "execution_count": null, "id": "cf993314-d0dc-42ae-a97c-3f38c237d67a", "metadata": {}, "outputs": [], "source": [ ">>> from vectorbtpro.base.resampling.nb import map_bounds_to_source_ranges_nb\n", "\n", ">>> range_starts, range_ends = map_bounds_to_source_ranges_nb(\n", "... source_index=h1_high.index.values,\n", "... target_lbound_index=target_lbound_index.values,\n", "... target_rbound_index=target_rbound_index.values,\n", "... closed_lbound=True,\n", "... closed_rbound=False,\n", "... )\n", ">>> np.column_stack((range_starts, range_ends))" ] }, { "cell_type": "code", "execution_count": null, "id": "ad3643dd-c3a4-4bc4-92b8-0c976fea9636", "metadata": {}, "outputs": [], "source": [ ">>> ms_mdd_arr = vbt.nb.reduce_index_ranges_meta_nb(\n", "... 1,\n", "... range_starts,\n", "... range_ends,\n", "... mdd_nb,\n", "... vbt.to_2d_array(h1_high),\n", "... vbt.to_2d_array(h1_low)\n", "... )\n", ">>> ms_mdd_arr" ] }, { "cell_type": "code", "execution_count": null, "id": "00aeb4d1-6f86-4470-9fe0-695823118b31", "metadata": {}, "outputs": [], "source": [ ">>> pd.Series(ms_mdd_arr[:, 0], index=target_lbound_index)" ] }, { "cell_type": "markdown", "id": "e8df7bde-fef1-421d-b09e-b454eb2286d9", "metadata": {}, "source": [ "### Caveats" ] }, { "cell_type": "code", "execution_count": null, "id": "911d934a-5e38-4a62-a7f1-9a538f7b09a2", "metadata": {}, "outputs": [], "source": [ "h4_close_2d = h4_close.iloc[:12]\n", "h4_close_2d" ] }, { "cell_type": "code", "execution_count": null, "id": "57f8392d-8fa2-4927-923f-ceb3bf1e9349", "metadata": {}, "outputs": [], "source": [ "h4_close_2d.resample(\"1d\").last()" ] }, { "cell_type": "code", "execution_count": null, "id": "1e7e3b5d-e6e7-463c-ae65-3b0b8915afa0", "metadata": {}, "outputs": [], "source": [ "h5_close = h1_close.resample(\"5h\").last()\n", "h5_close_2d = h5_close.iloc[:10]\n", "h5_close_2d" ] }, { "cell_type": "code", "execution_count": null, "id": "f5fafb16-c6c3-4a6a-ab92-6f1d0122b603", "metadata": {}, "outputs": [], "source": [ "h5_close_2d.resample(\"1d\").last()" ] }, { "cell_type": "code", "execution_count": null, "id": "1a45bfe1-fdcf-4e0b-b208-78aa32cc88b9", "metadata": {}, "outputs": [], "source": [ "vbt.timedelta(\"1d\") % vbt.timedelta(\"1h\")" ] }, { "cell_type": "code", "execution_count": null, "id": "ab874a51-5c3f-442d-9b2f-238d3fc810ab", "metadata": {}, "outputs": [], "source": [ "vbt.timedelta(\"1d\") % vbt.timedelta(\"4h\")" ] }, { "cell_type": "code", "execution_count": null, "id": "7f8129ea-1f41-412c-a86b-bde7bc42af2b", "metadata": {}, "outputs": [], "source": [ "vbt.timedelta(\"1d\") % vbt.timedelta(\"5h\")" ] }, { "cell_type": "code", "execution_count": null, "id": "fcd15b36-44f9-4642-a976-9a341d12f2f5", "metadata": {}, "outputs": [], "source": [ "h5_close_time = h5_close_2d.index.shift() - pd.Timedelta(nanoseconds=1)\n", "h5_close_time.name = \"Close time\"\n", "h5_close_2d.index = h5_close_time\n", "h5_close_2d" ] }, { "cell_type": "code", "execution_count": null, "id": "62befe68-5743-4901-b6eb-b654be33148b", "metadata": {}, "outputs": [], "source": [ "h5_close_2d.resample(\"1d\").last()" ] }, { "cell_type": "markdown", "id": "6f5ad0b0-fe77-44c1-bcc2-4364c7ca15a3", "metadata": {}, "source": [ "### Portfolio" ] }, { "cell_type": "code", "execution_count": null, "id": "1c8b2cf1-a1e2-4acf-8eee-5568d93005eb", "metadata": {}, "outputs": [], "source": [ "fast_sma = vbt.talib(\"SMA\").run(h1_close, timeperiod=vbt.Default(10))\n", "slow_sma = vbt.talib(\"SMA\").run(h1_close, timeperiod=vbt.Default(20))\n", "entries = fast_sma.real_crossed_above(slow_sma.real)\n", "exits = fast_sma.real_crossed_below(slow_sma.real)\n", "\n", "pf = vbt.Portfolio.from_signals(h1_close, entries, exits)\n", "pf.plot().show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "8e50332b-8357-4b8d-9236-b2099eb13b62", "metadata": {}, "outputs": [], "source": [ "ms_pf = pf.resample(\"M\")\n", "ms_pf.plot().show_svg()" ] }, { "cell_type": "code", "execution_count": null, "id": "695b0602-710b-49ac-bf01-8eb981481dc7", "metadata": {}, "outputs": [], "source": [ "pf.total_return" ] }, { "cell_type": "code", "execution_count": null, "id": "3c10ebcb-64ab-439d-b71e-0ab9e2645c6e", "metadata": {}, "outputs": [], "source": [ "ms_pf.total_return" ] }, { "cell_type": "code", "execution_count": null, "id": "9821141f-89ad-465d-980c-632f0e8a4c17", "metadata": {}, "outputs": [], "source": [ "(1 + pf.returns).resample(vbt.offset(\"M\")).apply(lambda x: x.prod() - 1)" ] }, { "cell_type": "code", "execution_count": null, "id": "ac16b57c-2148-4e85-a2a9-21909209c463", "metadata": {}, "outputs": [], "source": [ "ms_pf.returns" ] }, { "cell_type": "code", "execution_count": null, "id": "d5725b28-494d-4748-8959-27906374a239", "metadata": {}, "outputs": [], "source": [ "ms_pf.trades.pnl.to_pd(reduce_func_nb=\"sum\")" ] }, { "cell_type": "code", "execution_count": null, "id": "a175390c-359d-49d9-8892-cfcce10e464b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } }, "nbformat": 4, "nbformat_minor": 5 }