{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Multi-Asset Strategy Simulation\n",
"In this section, we will run the `Double Bollinger Band Strategy` from our earlier tutorial on multiple assets. But before we do that, we have to bring the quote value of all our forex currency pairs to the account currency (`USD`)."
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import vectorbtpro as vbt"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e8b999bcd06549b2b7556d617525943c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/8 [00:00, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/opt/miniconda3/envs/vbt/lib/python3.10/site-packages/vectorbtpro/data/base.py:688: \n",
"UserWarning: Symbols have mismatching index. Setting missing data points to NaN.\n",
" data = cls.align_index(data, missing=missing_index, silence_warnings=silence_warnings)\n"
]
}
],
"source": [
"## Forex Data\n",
"hdf_data = vbt.HDFData.fetch('/Users/dilip.rajkumar/Documents/vbtpro_tuts_private/data/MultiAsset_OHLCV_3Y_m1.h5',\n",
" # missing_index = 'drop',\n",
" silence_warnings=True) \n",
"\n",
"## Crypto Data\n",
"# m1_data = vbt.HDFData.fetch('../data/Binance_MultiAsset_OHLCV_3Y_m1.h5')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Convert FX pairs where `quote_currency != account currency` ( US$ )\n",
"\n",
"We will be converting `OHLC` price columns for the following currency pairs to the account currency (USD), as in these pairs either the `quote currency` or both the `base currency` & `quote currency` are not the same as the `account currency` which in our case is USD."
]
},
{
"cell_type": "code",
"execution_count": 96,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Multi-Asset DataFrame Symbols: ['AUDUSD', 'EURGBP', 'EURUSD', 'GBPAUD', 'GBPJPY', 'GBPUSD', 'USDCAD', 'USDJPY']\n"
]
}
],
"source": [
"symbols = hdf_data.symbols\n",
"print('Multi-Asset DataFrame Symbols:',symbols)"
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {},
"outputs": [],
"source": [
"## Convert FX pairs where quote_currency is != USD (account currency)\n",
"price_cols = [\"Open\", \"High\", \"Low\", \"Close\"]\n",
"symbols_to_convert = [\"USDJPY\", \"USDCAD\", \"GBPJPY\", \"EURGBP\", \"GBPAUD\"]"
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {},
"outputs": [],
"source": [
"def convert_to_account_currency(price_data : pd.Series, account_currency : str = \"USD\",\n",
" bridge_pair_price_data: pd.Series = None) -> pd.Series:\n",
" \"\"\"\n",
" Convert prices of different FX pairs to account currency.\n",
"\n",
" Parameters\n",
" ==========\n",
" price_data : pd.Series, Price data from (OHLC) columns of the pair to be converted\n",
" account_currency: str, default = 'USD'\n",
" bridge_pair_price_data: pd.Series, price data to be used when neither,\n",
" the base or quote currency is = account currency\n",
" \n",
" Returns\n",
" =======\n",
" new_instrument_price : pd.Series, converted price data\n",
"\n",
" \"\"\"\n",
" symbol = price_data.name\n",
" base_currency = symbol[0:3].upper()\n",
" quote_currency = symbol[3:6].upper() ## a.k.a Counter_currency\n",
"\n",
" if base_currency == account_currency: ## case 1 - Eg: USDJPY\n",
" # print(f\"BaseCurrency: {base_currency} is same as AccountCurrency: {account_currency} for Symbol:- {symbol}.\"+ \\\n",
" # \"Performing price inversion\")\n",
" new_instrument_price = (1/price_data)\n",
"\n",
" elif (quote_currency != account_currency) and (base_currency != account_currency): ## Case 2 - Eg: GBPJPY \n",
" bridge_pair_symbol = account_currency + quote_currency ## Bridge Pair symbol is : USDJPY\n",
" print(f\"Applying currency conversion for {symbol} with {bridge_pair_symbol} price data\")\n",
" if (bridge_pair_price_data is None):\n",
" raise Exception(f\"Price data for {bridge_pair_symbol} is missing. Please provide the same\")\n",
" elif (bridge_pair_symbol != bridge_pair_price_data.name.upper()):\n",
" message = f\"Mismatched data. Price data for {bridge_pair_symbol} is expected, but\" + \\\n",
" f\"{bridge_pair_price_data.name.upper()} price data is provided\"\n",
" print(message) ## Eg: When AUDUSD is provided instead of USDAUD\n",
" new_instrument_price = price_data * bridge_pair_price_data\n",
" else:\n",
" new_instrument_price = price_data/ bridge_pair_price_data ## Divide GBPJPY / USDJPY\n",
" \n",
" else:\n",
" # print(f\"No currency conversion needed for {symbol} as QuoteCurreny: {quote_currency} == Account Currency\")\n",
" new_instrument_price = price_data\n",
" return new_instrument_price"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We copy the data from the origina `hdf_data` file and store them in a dictionary of dataframes.
For symbols whose price columns are to be converted we create an empty `pd.DataFrame` which we will be filling with the converted price values"
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {},
"outputs": [],
"source": [
"new_data = {}\n",
"for symbol, df in hdf_data.data.items():\n",
" if symbol in symbols_to_convert: ## symbols whose price columns needs to be converted to account currency\n",
" new_data[symbol] = pd.DataFrame(columns=['Open','High','Low','Close','Volume'])\n",
" else: ## for other symbols store the data as it is\n",
" new_data[symbol] = df"
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Open | \n",
" High | \n",
" Low | \n",
" Close | \n",
" Volume | \n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Empty DataFrame\n",
"Columns: [Open, High, Low, Close, Volume]\n",
"Index: []"
]
},
"execution_count": 100,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Quick Sanity Check to see if empty dataframe was created\n",
"new_data['USDCAD']"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we call our `convert_to_account_currency()` function to convert the price data to account cuurency.
For pairs like `USDJPY` and `USDCAD` a simple price inversion (Eg: `1 / USDJPY` ) alone is sufficient, so for these cases we will be setting `bridge_pair == None`."
]
},
{
"cell_type": "code",
"execution_count": 101,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Source Symbol: USDJPY || Bridge Pair: None || Column: Open\n",
"Source Symbol: USDJPY || Bridge Pair: None || Column: High\n",
"Source Symbol: USDJPY || Bridge Pair: None || Column: Low\n",
"Source Symbol: USDJPY || Bridge Pair: None || Column: Close\n",
"Source Symbol: USDCAD || Bridge Pair: None || Column: Open\n",
"Source Symbol: USDCAD || Bridge Pair: None || Column: High\n",
"Source Symbol: USDCAD || Bridge Pair: None || Column: Low\n",
"Source Symbol: USDCAD || Bridge Pair: None || Column: Close\n",
"Source Symbol: GBPJPY || Bridge Pair: USDJPY || Column: Open\n",
"Applying currency conversion for GBPJPY with USDJPY price data\n",
"Source Symbol: GBPJPY || Bridge Pair: USDJPY || Column: High\n",
"Applying currency conversion for GBPJPY with USDJPY price data\n",
"Source Symbol: GBPJPY || Bridge Pair: USDJPY || Column: Low\n",
"Applying currency conversion for GBPJPY with USDJPY price data\n",
"Source Symbol: GBPJPY || Bridge Pair: USDJPY || Column: Close\n",
"Applying currency conversion for GBPJPY with USDJPY price data\n",
"Source Symbol: EURGBP || Bridge Pair: GBPUSD || Column: Open\n",
"Applying currency conversion for EURGBP with USDGBP price data\n",
"Mismatched data. Price data for USDGBP is expected, but GBPUSD price data is provided\n",
"Source Symbol: EURGBP || Bridge Pair: GBPUSD || Column: High\n",
"Applying currency conversion for EURGBP with USDGBP price data\n",
"Mismatched data. Price data for USDGBP is expected, but GBPUSD price data is provided\n",
"Source Symbol: EURGBP || Bridge Pair: GBPUSD || Column: Low\n",
"Applying currency conversion for EURGBP with USDGBP price data\n",
"Mismatched data. Price data for USDGBP is expected, but GBPUSD price data is provided\n",
"Source Symbol: EURGBP || Bridge Pair: GBPUSD || Column: Close\n",
"Applying currency conversion for EURGBP with USDGBP price data\n",
"Mismatched data. Price data for USDGBP is expected, but GBPUSD price data is provided\n",
"Source Symbol: GBPAUD || Bridge Pair: AUDUSD || Column: Open\n",
"Applying currency conversion for GBPAUD with USDAUD price data\n",
"Mismatched data. Price data for USDAUD is expected, but AUDUSD price data is provided\n",
"Source Symbol: GBPAUD || Bridge Pair: AUDUSD || Column: High\n",
"Applying currency conversion for GBPAUD with USDAUD price data\n",
"Mismatched data. Price data for USDAUD is expected, but AUDUSD price data is provided\n",
"Source Symbol: GBPAUD || Bridge Pair: AUDUSD || Column: Low\n",
"Applying currency conversion for GBPAUD with USDAUD price data\n",
"Mismatched data. Price data for USDAUD is expected, but AUDUSD price data is provided\n",
"Source Symbol: GBPAUD || Bridge Pair: AUDUSD || Column: Close\n",
"Applying currency conversion for GBPAUD with USDAUD price data\n",
"Mismatched data. Price data for USDAUD is expected, but AUDUSD price data is provided\n"
]
}
],
"source": [
"bridge_pairs = [None, None, \"USDJPY\", \"GBPUSD\", \"AUDUSD\"]\n",
"\n",
"for ticker_source, ticker_bridge in zip(symbols_to_convert, bridge_pairs):\n",
" new_data[ticker_source][\"Volume\"] = hdf_data.get(\"Volume\")[ticker_source]\n",
" for col in price_cols:\n",
" print(\"Source Symbol:\", ticker_source, \"|| Bridge Pair:\", ticker_bridge, \"|| Column:\", col)\n",
" new_data[ticker_source][col] = convert_to_account_currency( \n",
" price_data = hdf_data.get(col)[ticker_source],\n",
" bridge_pair_price_data = None if ticker_bridge is None else hdf_data.get(col)[ticker_bridge]\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {},
"outputs": [],
"source": [
"## Converts this `new_data` dict of dataframes into a vbt.Data object\n",
"m1_data = vbt.Data.from_data(new_data) "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ensuring Correct data for `High` and `Low` columns\n",
"Once we have the converted OHLC price columns for a particular symbol (`ticker_source`), we recalculate the `High` and `Low` by getting the `max` and `min` of each row in the OHLC columns respectively using `df.max(axis=1)` and `df.min(axis=1)`"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {},
"outputs": [],
"source": [
"for ticker_source in symbols:\n",
" m1_data.data[ticker_source]['High'] = m1_data.data[ticker_source][price_cols].max(axis=1)\n",
" m1_data.data[ticker_source]['Low'] = m1_data.data[ticker_source][price_cols].min(axis=1)\n",
" # m1_data.data[ticker_source].dropna(inplace = True) ## This creates out of Bounds error\n",
" "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"**What need is there for above step?**
\n",
"Lets assume for a symbol `X` if low is 10 and high is 20, then when we do a simple price inversion ( `1/X` ) new high would become `1/10 = 0.1` and new low would become `1/20 = 0.05` which will result in complications and thus arises the need for the above step"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Open | \n",
" High | \n",
" Low | \n",
" Close | \n",
" Volume | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:06:00+00:00 | \n",
" 0.733353 | \n",
" 0.733501 | \n",
" 0.733353 | \n",
" 0.733450 | \n",
" 21.220 | \n",
"
\n",
" \n",
" | 2019-01-01 22:07:00+00:00 | \n",
" 0.733415 | \n",
" 0.733452 | \n",
" 0.733396 | \n",
" 0.733396 | \n",
" 7.875 | \n",
"
\n",
" \n",
" | 2019-01-01 22:08:00+00:00 | \n",
" 0.733393 | \n",
" 0.733399 | \n",
" 0.733393 | \n",
" 0.733396 | \n",
" 3.000 | \n",
"
\n",
" \n",
" | 2019-01-01 22:09:00+00:00 | \n",
" 0.733399 | \n",
" 0.733469 | \n",
" 0.733350 | \n",
" 0.733350 | \n",
" 17.750 | \n",
"
\n",
" \n",
" | 2019-01-01 22:10:00+00:00 | \n",
" 0.733348 | \n",
" 0.733522 | \n",
" 0.733348 | \n",
" 0.733469 | \n",
" 12.625 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2022-04-27 15:02:30+00:00 | \n",
" 0.771129 | \n",
" 0.771197 | \n",
" 0.771129 | \n",
" 0.771159 | \n",
" 93.290 | \n",
"
\n",
" \n",
" | 2022-04-27 15:03:30+00:00 | \n",
" 0.771156 | \n",
" 0.771206 | \n",
" 0.771156 | \n",
" 0.771168 | \n",
" 70.050 | \n",
"
\n",
" \n",
" | 2022-04-27 15:04:30+00:00 | \n",
" 0.771165 | \n",
" 0.771239 | \n",
" 0.771165 | \n",
" 0.771224 | \n",
" 91.840 | \n",
"
\n",
" \n",
" | 2022-04-27 15:05:30+00:00 | \n",
" 0.771230 | \n",
" 0.771236 | \n",
" 0.771209 | \n",
" 0.771209 | \n",
" 30.620 | \n",
"
\n",
" \n",
" | 2022-04-27 15:06:30+00:00 | \n",
" 0.771209 | \n",
" 0.771340 | \n",
" 0.771209 | \n",
" 0.771304 | \n",
" 72.445 | \n",
"
\n",
" \n",
"
\n",
"
296614 rows × 5 columns
\n",
"
"
],
"text/plain": [
" Open High Low Close Volume\n",
"time \n",
"2019-01-01 22:06:00+00:00 0.733353 0.733501 0.733353 0.733450 21.220\n",
"2019-01-01 22:07:00+00:00 0.733415 0.733452 0.733396 0.733396 7.875\n",
"2019-01-01 22:08:00+00:00 0.733393 0.733399 0.733393 0.733396 3.000\n",
"2019-01-01 22:09:00+00:00 0.733399 0.733469 0.733350 0.733350 17.750\n",
"2019-01-01 22:10:00+00:00 0.733348 0.733522 0.733348 0.733469 12.625\n",
"... ... ... ... ... ...\n",
"2022-04-27 15:02:30+00:00 0.771129 0.771197 0.771129 0.771159 93.290\n",
"2022-04-27 15:03:30+00:00 0.771156 0.771206 0.771156 0.771168 70.050\n",
"2022-04-27 15:04:30+00:00 0.771165 0.771239 0.771165 0.771224 91.840\n",
"2022-04-27 15:05:30+00:00 0.771230 0.771236 0.771209 0.771209 30.620\n",
"2022-04-27 15:06:30+00:00 0.771209 0.771340 0.771209 0.771304 72.445\n",
"\n",
"[296614 rows x 5 columns]"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Sanity check to see if empty pd.DataFrame got filled now\n",
"m1_data.data['USDCAD'].dropna()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Double Bollinger Band Strategy over Multi-Asset portfolio\n",
"The following steps are very similar we already saw in the [Alignment and Resampling](https://qubitquants.pro/aligning-mtf-data/index.html) and [Strategy Development](https://qubitquants.pro/strategydev/index.html) tutorials, except now they are applied over multiple symbols (assets) in a portfolio. So I will just put the code here and won't be explaining anything here in detail, when in doubt refer back to the above two tutorials."
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {},
"outputs": [],
"source": [
"m15_data = m1_data.resample('15T') # Convert 1 minute to 15 mins\n",
"h1_data = m1_data.resample(\"1h\") # Convert 1 minute to 1 hour\n",
"h4_data = m1_data.resample('4h') # Convert 1 minute to 4 hour"
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"DatetimeIndex(['2019-01-01 22:00:00+00:00', '2019-01-01 22:15:00+00:00',\n",
" '2019-01-01 22:30:00+00:00', '2019-01-01 22:45:00+00:00',\n",
" '2019-01-01 23:00:00+00:00', '2019-01-01 23:15:00+00:00',\n",
" '2019-01-01 23:30:00+00:00', '2019-01-01 23:45:00+00:00',\n",
" '2019-01-02 00:00:00+00:00', '2019-01-02 00:15:00+00:00',\n",
" ...\n",
" '2023-01-16 04:30:00+00:00', '2023-01-16 04:45:00+00:00',\n",
" '2023-01-16 05:00:00+00:00', '2023-01-16 05:15:00+00:00',\n",
" '2023-01-16 05:30:00+00:00', '2023-01-16 05:45:00+00:00',\n",
" '2023-01-16 06:00:00+00:00', '2023-01-16 06:15:00+00:00',\n",
" '2023-01-16 06:30:00+00:00', '2023-01-16 06:45:00+00:00'],\n",
" dtype='datetime64[ns, UTC]', name='time', length=141636, freq='15T')"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"m15_data.wrapper.index"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {},
"outputs": [],
"source": [
"# Obtain all the required prices using the .get() method\n",
"m15_close = m15_data.get('Close')\n",
"\n",
"## h1 data\n",
"h1_open = h1_data.get('Open')\n",
"h1_close = h1_data.get('Close')\n",
"h1_high = h1_data.get('High')\n",
"h1_low = h1_data.get('Low')\n",
"\n",
"## h4 data\n",
"h4_open = h4_data.get('Open')\n",
"h4_close = h4_data.get('Close')\n",
"h4_high = h4_data.get('High')\n",
"h4_low = h4_data.get('Low')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create (manually) the indicators for Multi-Time Frames"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {},
"outputs": [],
"source": [
"rsi_period = 21\n",
"\n",
"## 15m indicators\n",
"m15_rsi = vbt.talib(\"RSI\", timeperiod = rsi_period).run(m15_close, skipna=True).real.ffill()\n",
"m15_bbands = vbt.talib(\"BBANDS\").run(m15_close, skipna=True)\n",
"m15_bbands_rsi = vbt.talib(\"BBANDS\").run(m15_rsi, skipna=True)\n",
"\n",
"## h1 indicators\n",
"h1_rsi = vbt.talib(\"RSI\", timeperiod = rsi_period).run(h1_close, skipna=True).real.ffill()\n",
"h1_bbands = vbt.talib(\"BBANDS\").run(h1_close, skipna=True)\n",
"h1_bbands_rsi = vbt.talib(\"BBANDS\").run(h1_rsi, skipna=True)\n",
"\n",
"## h4 indicators\n",
"h4_rsi = vbt.talib(\"RSI\", timeperiod = rsi_period).run(h4_close, skipna=True).real.ffill()\n",
"h4_bbands = vbt.talib(\"BBANDS\").run(h4_close, skipna=True)\n",
"h4_bbands_rsi = vbt.talib(\"BBANDS\").run(h4_rsi, skipna=True)"
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {},
"outputs": [],
"source": [
"def create_resamplers(result_dict_keys_list : list, source_indices : list, \n",
" source_frequencies :list, target_index : pd.Series, target_freq : str):\n",
" \"\"\"\n",
" Creates a dictionary of vbtpro resampler objects.\n",
"\n",
" Parameters\n",
" ==========\n",
" result_dict_keys_list : list, list of strings, which are keys of the output dictionary\n",
" source_indices : list, list of pd.time series objects of the higher timeframes\n",
" source_frequencies : list(str), which are short form representation of time series order. Eg:[\"1D\", \"4h\"]\n",
" target_index : pd.Series, target time series for the resampler objects\n",
" target_freq : str, target time frequency for the resampler objects\n",
"\n",
" Returns\n",
" ===========\n",
" resamplers_dict : dict, vbt pro resampler objects\n",
" \"\"\"\n",
" \n",
" \n",
" resamplers = []\n",
" for si, sf in zip(source_indices, source_frequencies):\n",
" resamplers.append(vbt.Resampler(source_index = si, target_index = target_index,\n",
" source_freq = sf, target_freq = target_freq))\n",
" return dict(zip(result_dict_keys_list, resamplers))"
]
},
{
"cell_type": "code",
"execution_count": 110,
"metadata": {},
"outputs": [],
"source": [
"## Initialize dictionary\n",
"mtf_data = {}\n",
"\n",
"col_values = [\n",
" m15_close, m15_rsi, m15_bbands.upperband, m15_bbands.middleband, m15_bbands.lowerband, \n",
" m15_bbands_rsi.upperband, m15_bbands_rsi.middleband, m15_bbands_rsi.lowerband\n",
" ]\n",
"\n",
"col_keys = [\n",
" \"m15_close\", \"m15_rsi\", \"m15_bband_price_upper\", \"m15_bband_price_middle\", \"m15_bband_price_lower\", \n",
" \"m15_bband_rsi_upper\", \"m15_bband_rsi_middle\", \"m15_bband_rsi_lower\"\n",
" ]\n",
"\n",
"# Assign key, value pairs for method of time series data to store in data dict\n",
"for key, time_series in zip(col_keys, col_values):\n",
" mtf_data[key] = time_series.ffill()"
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'h1_m15': ,\n",
" 'h4_m15': }"
]
},
"execution_count": 111,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Create Resampler Objects for upsampling\n",
"src_indices = [h1_close.index, h4_close.index]\n",
"src_frequencies = [\"1H\",\"4H\"] \n",
"resampler_dict_keys = [\"h1_m15\",\"h4_m15\"]\n",
"\n",
"list_resamplers = create_resamplers(resampler_dict_keys, src_indices, src_frequencies, m15_close.index, \"15T\")\n",
"\n",
"list_resamplers"
]
},
{
"cell_type": "code",
"execution_count": 112,
"metadata": {},
"outputs": [],
"source": [
"## Use along with Manual indicator creation method for MTF\n",
"series_to_resample = [\n",
" [h1_open, h1_high, h1_low, h1_close, h1_rsi, h1_bbands.upperband, h1_bbands.middleband, h1_bbands.lowerband,\n",
" h1_bbands_rsi.upperband, h1_bbands_rsi.middleband, h1_bbands_rsi.lowerband], \n",
" [h4_high, h4_low, h4_close, h4_rsi, h4_bbands.upperband, h4_bbands.middleband, h4_bbands.lowerband, \n",
" h4_bbands_rsi.upperband, h4_bbands_rsi.middleband, h4_bbands_rsi.lowerband]\n",
" ]\n",
"\n",
"\n",
"data_keys = [\n",
" [\"h1_open\",\"h1_high\", \"h1_low\", \"h1_close\", \"h1_rsi\", \"h1_bband_price_upper\", \"h1_bband_price_middle\", \"h1_bband_price_lower\", \n",
" \"h1_bband_rsi_upper\", \"h1_bband_rsi_middle\", \"h1_bband_rsi_lower\"],\n",
" [\"h4_open\",\"h4_high\", \"h4_low\", \"h4_close\", \"h4_rsi\", \"h4_bband_price_upper\", \"h4_bband_price_middle\", \"h4_bband_price_lower\", \n",
" \"h4_bband_rsi_upper\", \"h4_bband_rsi_middle\", \"h4_bband_rsi_lower\"]\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": 113,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Resampling h1_open differently using vbt.resample_opening using \"h1_m15\" resampler\n",
"Resampling h4_open differently using vbt.resample_opening using \"h4_m15\" resampler\n"
]
}
],
"source": [
"for lst_series, lst_keys, resampler in zip(series_to_resample, data_keys, resampler_dict_keys):\n",
" for key, time_series in zip(lst_keys, lst_series):\n",
" if key.lower().endswith('open'):\n",
" print(f'Resampling {key} differently using vbt.resample_opening using \"{resampler}\" resampler')\n",
" resampled_time_series = time_series.vbt.resample_opening(list_resamplers[resampler])\n",
" else:\n",
" resampled_time_series = time_series.vbt.resample_closing(list_resamplers[resampler])\n",
" mtf_data[key] = resampled_time_series"
]
},
{
"cell_type": "code",
"execution_count": 114,
"metadata": {},
"outputs": [],
"source": [
"cols_order = ['m15_close', 'm15_rsi', 'm15_bband_price_upper','m15_bband_price_middle', 'm15_bband_price_lower',\n",
" 'm15_bband_rsi_upper','m15_bband_rsi_middle', 'm15_bband_rsi_lower',\n",
" 'h1_open', 'h1_high', 'h1_low', 'h1_close', 'h1_rsi',\n",
" 'h1_bband_price_upper', 'h1_bband_price_middle', 'h1_bband_price_lower', \n",
" 'h1_bband_rsi_upper', 'h1_bband_rsi_middle', 'h1_bband_rsi_lower', \n",
" 'h4_open', 'h4_high', 'h4_low', 'h4_close', 'h4_rsi',\n",
" 'h4_bband_price_upper', 'h4_bband_price_middle', 'h4_bband_price_lower', \n",
" 'h4_bband_rsi_upper', 'h4_bband_rsi_middle', 'h4_bband_rsi_lower'\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": 115,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | symbol | \n",
" AUDUSD | \n",
" EURGBP | \n",
" EURUSD | \n",
" GBPAUD | \n",
" GBPJPY | \n",
" GBPUSD | \n",
" USDCAD | \n",
" USDJPY | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:15:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:30:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:45:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 23:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2023-01-16 05:45:00+00:00 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" 52.757665 | \n",
" 65.976674 | \n",
" 40.581654 | \n",
" 60.242668 | \n",
" 60.559401 | \n",
" 84.30117 | \n",
"
\n",
" \n",
" | 2023-01-16 06:00:00+00:00 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" 52.757665 | \n",
" 65.976674 | \n",
" 40.581654 | \n",
" 60.242668 | \n",
" 60.559401 | \n",
" 84.30117 | \n",
"
\n",
" \n",
" | 2023-01-16 06:15:00+00:00 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" 52.757665 | \n",
" 65.976674 | \n",
" 40.581654 | \n",
" 60.242668 | \n",
" 60.559401 | \n",
" 84.30117 | \n",
"
\n",
" \n",
" | 2023-01-16 06:30:00+00:00 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" 52.757665 | \n",
" 65.976674 | \n",
" 40.581654 | \n",
" 60.242668 | \n",
" 60.559401 | \n",
" 84.30117 | \n",
"
\n",
" \n",
" | 2023-01-16 06:45:00+00:00 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" 52.757665 | \n",
" 65.976674 | \n",
" 40.581654 | \n",
" 60.242668 | \n",
" 60.559401 | \n",
" 84.30117 | \n",
"
\n",
" \n",
"
\n",
"
141636 rows × 8 columns
\n",
"
"
],
"text/plain": [
"symbol AUDUSD EURGBP EURUSD GBPAUD \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN NaN NaN \n",
"... ... ... ... ... \n",
"2023-01-16 05:45:00+00:00 68.223309 35.73201 52.757665 65.976674 \n",
"2023-01-16 06:00:00+00:00 68.223309 35.73201 52.757665 65.976674 \n",
"2023-01-16 06:15:00+00:00 68.223309 35.73201 52.757665 65.976674 \n",
"2023-01-16 06:30:00+00:00 68.223309 35.73201 52.757665 65.976674 \n",
"2023-01-16 06:45:00+00:00 68.223309 35.73201 52.757665 65.976674 \n",
"\n",
"symbol GBPJPY GBPUSD USDCAD USDJPY \n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN NaN NaN \n",
"... ... ... ... ... \n",
"2023-01-16 05:45:00+00:00 40.581654 60.242668 60.559401 84.30117 \n",
"2023-01-16 06:00:00+00:00 40.581654 60.242668 60.559401 84.30117 \n",
"2023-01-16 06:15:00+00:00 40.581654 60.242668 60.559401 84.30117 \n",
"2023-01-16 06:30:00+00:00 40.581654 60.242668 60.559401 84.30117 \n",
"2023-01-16 06:45:00+00:00 40.581654 60.242668 60.559401 84.30117 \n",
"\n",
"[141636 rows x 8 columns]"
]
},
"execution_count": 115,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mtf_data.get('m15_rsi')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Double Bollinger Band - Strategy Conditions"
]
},
{
"cell_type": "code",
"execution_count": 116,
"metadata": {},
"outputs": [],
"source": [
"required_cols = ['m15_close','m15_rsi','m15_bband_rsi_lower', 'm15_bband_rsi_upper',\n",
" 'h4_low', \"h4_rsi\", \"h4_bband_price_lower\", \"h4_bband_price_upper\" ]"
]
},
{
"cell_type": "code",
"execution_count": 117,
"metadata": {},
"outputs": [],
"source": [
"## Higher values greater than 1.0 are like moving up the lower RSI b-band, \n",
"## signifying if the lowerband rsi is anywhere around 1% of the lower b-band validate that case as True\n",
"bb_upper_fract = 0.99\n",
"bb_lower_fract = 1.01\n",
"\n",
"## Long Entry Conditions\n",
"# c1_long_entry = (mtf_data['h1_low'] <= mtf_data['h1_bband_price_lower'])\n",
"c1_long_entry = (mtf_data['h4_low'] <= mtf_data['h4_bband_price_lower'])\n",
"c2_long_entry = (mtf_data['m15_rsi'] <= (bb_lower_fract * mtf_data['m15_bband_rsi_lower']) )\n",
"\n",
"\n",
"## Long Exit Conditions\n",
"# c1_long_exit = (mtf_data['h1_high'] >= mtf_data['h1_bband_price_upper'])\n",
"c1_long_exit = (mtf_data['h4_high'] >= mtf_data['h4_bband_price_upper'])\n",
"c2_long_exit = (mtf_data['m15_rsi'] >= (bb_upper_fract * mtf_data['m15_bband_rsi_upper'])) "
]
},
{
"cell_type": "code",
"execution_count": 118,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | symbol | \n",
" AUDUSD | \n",
" EURGBP | \n",
" EURUSD | \n",
" GBPAUD | \n",
" GBPJPY | \n",
" GBPUSD | \n",
" USDCAD | \n",
" USDJPY | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:00:00+00:00 | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" | 2019-01-01 22:15:00+00:00 | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" | 2019-01-01 22:30:00+00:00 | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" | 2019-01-01 22:45:00+00:00 | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" | 2019-01-01 23:00:00+00:00 | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2023-01-16 05:45:00+00:00 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" | 2023-01-16 06:00:00+00:00 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" | 2023-01-16 06:15:00+00:00 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" | 2023-01-16 06:30:00+00:00 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" | 2023-01-16 06:45:00+00:00 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
"
\n",
"
141636 rows × 8 columns
\n",
"
"
],
"text/plain": [
"symbol AUDUSD EURGBP EURUSD GBPAUD GBPJPY GBPUSD \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 False False False False False False \n",
"2019-01-01 22:15:00+00:00 False False False False False False \n",
"2019-01-01 22:30:00+00:00 False False False False False False \n",
"2019-01-01 22:45:00+00:00 False False False False False False \n",
"2019-01-01 23:00:00+00:00 False False False False False False \n",
"... ... ... ... ... ... ... \n",
"2023-01-16 05:45:00+00:00 True True True True True True \n",
"2023-01-16 06:00:00+00:00 True True True True True True \n",
"2023-01-16 06:15:00+00:00 True True True True True True \n",
"2023-01-16 06:30:00+00:00 True True True True True True \n",
"2023-01-16 06:45:00+00:00 True True True True True True \n",
"\n",
"symbol USDCAD USDJPY \n",
"time \n",
"2019-01-01 22:00:00+00:00 False False \n",
"2019-01-01 22:15:00+00:00 False False \n",
"2019-01-01 22:30:00+00:00 False False \n",
"2019-01-01 22:45:00+00:00 False False \n",
"2019-01-01 23:00:00+00:00 False False \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 True True \n",
"2023-01-16 06:00:00+00:00 True True \n",
"2023-01-16 06:15:00+00:00 True True \n",
"2023-01-16 06:30:00+00:00 True True \n",
"2023-01-16 06:45:00+00:00 True True \n",
"\n",
"[141636 rows x 8 columns]"
]
},
"execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c1_long_entry"
]
},
{
"cell_type": "code",
"execution_count": 119,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | symbol | \n",
" AUDUSD_m15_close | \n",
" EURGBP_m15_close | \n",
" EURUSD_m15_close | \n",
" GBPAUD_m15_close | \n",
" GBPJPY_m15_close | \n",
" GBPUSD_m15_close | \n",
" USDCAD_m15_close | \n",
" USDJPY_m15_close | \n",
" AUDUSD_m15_rsi | \n",
" EURGBP_m15_rsi | \n",
" ... | \n",
" USDCAD_h4_bband_price_lower | \n",
" USDJPY_h4_bband_price_lower | \n",
" AUDUSD_h4_bband_price_upper | \n",
" EURGBP_h4_bband_price_upper | \n",
" EURUSD_h4_bband_price_upper | \n",
" GBPAUD_h4_bband_price_upper | \n",
" GBPJPY_h4_bband_price_upper | \n",
" GBPUSD_h4_bband_price_upper | \n",
" USDCAD_h4_bband_price_upper | \n",
" USDJPY_h4_bband_price_upper | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:15:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:30:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:45:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 23:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2023-01-16 05:45:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:00:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:15:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:30:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:45:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
"
\n",
"
141636 rows × 64 columns
\n",
"
"
],
"text/plain": [
"symbol AUDUSD_m15_close EURGBP_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:00:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:15:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:30:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:45:00+00:00 0.695595 1.122143 \n",
"\n",
"symbol EURUSD_m15_close GBPAUD_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:00:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:15:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:30:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:45:00+00:00 1.054005 1.309694 \n",
"\n",
"symbol GBPJPY_m15_close GBPUSD_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:00:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:15:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:30:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:45:00+00:00 1.225058 1.198255 \n",
"\n",
"symbol USDCAD_m15_close USDJPY_m15_close AUDUSD_m15_rsi \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN NaN \n",
"... ... ... ... \n",
"2023-01-16 05:45:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:00:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:15:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:30:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:45:00+00:00 0.771304 0.008549 68.223309 \n",
"\n",
"symbol EURGBP_m15_rsi ... USDCAD_h4_bband_price_lower \\\n",
"time ... \n",
"2019-01-01 22:00:00+00:00 NaN ... NaN \n",
"2019-01-01 22:15:00+00:00 NaN ... NaN \n",
"2019-01-01 22:30:00+00:00 NaN ... NaN \n",
"2019-01-01 22:45:00+00:00 NaN ... NaN \n",
"2019-01-01 23:00:00+00:00 NaN ... NaN \n",
"... ... ... ... \n",
"2023-01-16 05:45:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:00:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:15:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:30:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:45:00+00:00 35.73201 ... 52.28795 \n",
"\n",
"symbol USDJPY_h4_bband_price_lower \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 69.81101 \n",
"2023-01-16 06:00:00+00:00 69.81101 \n",
"2023-01-16 06:15:00+00:00 69.81101 \n",
"2023-01-16 06:30:00+00:00 69.81101 \n",
"2023-01-16 06:45:00+00:00 69.81101 \n",
"\n",
"symbol AUDUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.692467 \n",
"2023-01-16 06:00:00+00:00 0.692467 \n",
"2023-01-16 06:15:00+00:00 0.692467 \n",
"2023-01-16 06:30:00+00:00 0.692467 \n",
"2023-01-16 06:45:00+00:00 0.692467 \n",
"\n",
"symbol EURGBP_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.15173 \n",
"2023-01-16 06:00:00+00:00 1.15173 \n",
"2023-01-16 06:15:00+00:00 1.15173 \n",
"2023-01-16 06:30:00+00:00 1.15173 \n",
"2023-01-16 06:45:00+00:00 1.15173 \n",
"\n",
"symbol EURUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.054172 \n",
"2023-01-16 06:00:00+00:00 1.054172 \n",
"2023-01-16 06:15:00+00:00 1.054172 \n",
"2023-01-16 06:30:00+00:00 1.054172 \n",
"2023-01-16 06:45:00+00:00 1.054172 \n",
"\n",
"symbol GBPAUD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.303757 \n",
"2023-01-16 06:00:00+00:00 1.303757 \n",
"2023-01-16 06:15:00+00:00 1.303757 \n",
"2023-01-16 06:30:00+00:00 1.303757 \n",
"2023-01-16 06:45:00+00:00 1.303757 \n",
"\n",
"symbol GBPJPY_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.228194 \n",
"2023-01-16 06:00:00+00:00 1.228194 \n",
"2023-01-16 06:15:00+00:00 1.228194 \n",
"2023-01-16 06:30:00+00:00 1.228194 \n",
"2023-01-16 06:45:00+00:00 1.228194 \n",
"\n",
"symbol GBPUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.196343 \n",
"2023-01-16 06:00:00+00:00 1.196343 \n",
"2023-01-16 06:15:00+00:00 1.196343 \n",
"2023-01-16 06:30:00+00:00 1.196343 \n",
"2023-01-16 06:45:00+00:00 1.196343 \n",
"\n",
"symbol USDCAD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.770143 \n",
"2023-01-16 06:00:00+00:00 0.770143 \n",
"2023-01-16 06:15:00+00:00 0.770143 \n",
"2023-01-16 06:30:00+00:00 0.770143 \n",
"2023-01-16 06:45:00+00:00 0.770143 \n",
"\n",
"symbol USDJPY_h4_bband_price_upper \n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.008446 \n",
"2023-01-16 06:00:00+00:00 0.008446 \n",
"2023-01-16 06:15:00+00:00 0.008446 \n",
"2023-01-16 06:30:00+00:00 0.008446 \n",
"2023-01-16 06:45:00+00:00 0.008446 \n",
"\n",
"[141636 rows x 64 columns]"
]
},
"execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.concat([mtf_data[col][c1_long_entry].add_suffix(f\"_{col}\") for col in required_cols], axis = 1)"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | symbol | \n",
" AUDUSD_m15_close | \n",
" EURGBP_m15_close | \n",
" EURUSD_m15_close | \n",
" GBPAUD_m15_close | \n",
" GBPJPY_m15_close | \n",
" GBPUSD_m15_close | \n",
" USDCAD_m15_close | \n",
" USDJPY_m15_close | \n",
" AUDUSD_m15_rsi | \n",
" EURGBP_m15_rsi | \n",
" ... | \n",
" USDCAD_h4_bband_price_lower | \n",
" USDJPY_h4_bband_price_lower | \n",
" AUDUSD_h4_bband_price_upper | \n",
" EURGBP_h4_bband_price_upper | \n",
" EURUSD_h4_bband_price_upper | \n",
" GBPAUD_h4_bband_price_upper | \n",
" GBPJPY_h4_bband_price_upper | \n",
" GBPUSD_h4_bband_price_upper | \n",
" USDCAD_h4_bband_price_upper | \n",
" USDJPY_h4_bband_price_upper | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:15:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:30:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 22:45:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | 2019-01-01 23:00:00+00:00 | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" ... | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2023-01-16 05:45:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:00:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:15:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:30:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
" | 2023-01-16 06:45:00+00:00 | \n",
" 0.695595 | \n",
" 1.122143 | \n",
" 1.054005 | \n",
" 1.309694 | \n",
" 1.225058 | \n",
" 1.198255 | \n",
" 0.771304 | \n",
" 0.008549 | \n",
" 68.223309 | \n",
" 35.73201 | \n",
" ... | \n",
" 52.28795 | \n",
" 69.81101 | \n",
" 0.692467 | \n",
" 1.15173 | \n",
" 1.054172 | \n",
" 1.303757 | \n",
" 1.228194 | \n",
" 1.196343 | \n",
" 0.770143 | \n",
" 0.008446 | \n",
"
\n",
" \n",
"
\n",
"
141636 rows × 64 columns
\n",
"
"
],
"text/plain": [
"symbol AUDUSD_m15_close EURGBP_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:00:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:15:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:30:00+00:00 0.695595 1.122143 \n",
"2023-01-16 06:45:00+00:00 0.695595 1.122143 \n",
"\n",
"symbol EURUSD_m15_close GBPAUD_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:00:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:15:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:30:00+00:00 1.054005 1.309694 \n",
"2023-01-16 06:45:00+00:00 1.054005 1.309694 \n",
"\n",
"symbol GBPJPY_m15_close GBPUSD_m15_close \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:00:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:15:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:30:00+00:00 1.225058 1.198255 \n",
"2023-01-16 06:45:00+00:00 1.225058 1.198255 \n",
"\n",
"symbol USDCAD_m15_close USDJPY_m15_close AUDUSD_m15_rsi \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:15:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:30:00+00:00 NaN NaN NaN \n",
"2019-01-01 22:45:00+00:00 NaN NaN NaN \n",
"2019-01-01 23:00:00+00:00 NaN NaN NaN \n",
"... ... ... ... \n",
"2023-01-16 05:45:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:00:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:15:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:30:00+00:00 0.771304 0.008549 68.223309 \n",
"2023-01-16 06:45:00+00:00 0.771304 0.008549 68.223309 \n",
"\n",
"symbol EURGBP_m15_rsi ... USDCAD_h4_bband_price_lower \\\n",
"time ... \n",
"2019-01-01 22:00:00+00:00 NaN ... NaN \n",
"2019-01-01 22:15:00+00:00 NaN ... NaN \n",
"2019-01-01 22:30:00+00:00 NaN ... NaN \n",
"2019-01-01 22:45:00+00:00 NaN ... NaN \n",
"2019-01-01 23:00:00+00:00 NaN ... NaN \n",
"... ... ... ... \n",
"2023-01-16 05:45:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:00:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:15:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:30:00+00:00 35.73201 ... 52.28795 \n",
"2023-01-16 06:45:00+00:00 35.73201 ... 52.28795 \n",
"\n",
"symbol USDJPY_h4_bband_price_lower \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 69.81101 \n",
"2023-01-16 06:00:00+00:00 69.81101 \n",
"2023-01-16 06:15:00+00:00 69.81101 \n",
"2023-01-16 06:30:00+00:00 69.81101 \n",
"2023-01-16 06:45:00+00:00 69.81101 \n",
"\n",
"symbol AUDUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.692467 \n",
"2023-01-16 06:00:00+00:00 0.692467 \n",
"2023-01-16 06:15:00+00:00 0.692467 \n",
"2023-01-16 06:30:00+00:00 0.692467 \n",
"2023-01-16 06:45:00+00:00 0.692467 \n",
"\n",
"symbol EURGBP_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.15173 \n",
"2023-01-16 06:00:00+00:00 1.15173 \n",
"2023-01-16 06:15:00+00:00 1.15173 \n",
"2023-01-16 06:30:00+00:00 1.15173 \n",
"2023-01-16 06:45:00+00:00 1.15173 \n",
"\n",
"symbol EURUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.054172 \n",
"2023-01-16 06:00:00+00:00 1.054172 \n",
"2023-01-16 06:15:00+00:00 1.054172 \n",
"2023-01-16 06:30:00+00:00 1.054172 \n",
"2023-01-16 06:45:00+00:00 1.054172 \n",
"\n",
"symbol GBPAUD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.303757 \n",
"2023-01-16 06:00:00+00:00 1.303757 \n",
"2023-01-16 06:15:00+00:00 1.303757 \n",
"2023-01-16 06:30:00+00:00 1.303757 \n",
"2023-01-16 06:45:00+00:00 1.303757 \n",
"\n",
"symbol GBPJPY_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.228194 \n",
"2023-01-16 06:00:00+00:00 1.228194 \n",
"2023-01-16 06:15:00+00:00 1.228194 \n",
"2023-01-16 06:30:00+00:00 1.228194 \n",
"2023-01-16 06:45:00+00:00 1.228194 \n",
"\n",
"symbol GBPUSD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 1.196343 \n",
"2023-01-16 06:00:00+00:00 1.196343 \n",
"2023-01-16 06:15:00+00:00 1.196343 \n",
"2023-01-16 06:30:00+00:00 1.196343 \n",
"2023-01-16 06:45:00+00:00 1.196343 \n",
"\n",
"symbol USDCAD_h4_bband_price_upper \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.770143 \n",
"2023-01-16 06:00:00+00:00 0.770143 \n",
"2023-01-16 06:15:00+00:00 0.770143 \n",
"2023-01-16 06:30:00+00:00 0.770143 \n",
"2023-01-16 06:45:00+00:00 0.770143 \n",
"\n",
"symbol USDJPY_h4_bband_price_upper \n",
"time \n",
"2019-01-01 22:00:00+00:00 NaN \n",
"2019-01-01 22:15:00+00:00 NaN \n",
"2019-01-01 22:30:00+00:00 NaN \n",
"2019-01-01 22:45:00+00:00 NaN \n",
"2019-01-01 23:00:00+00:00 NaN \n",
"... ... \n",
"2023-01-16 05:45:00+00:00 0.008446 \n",
"2023-01-16 06:00:00+00:00 0.008446 \n",
"2023-01-16 06:15:00+00:00 0.008446 \n",
"2023-01-16 06:30:00+00:00 0.008446 \n",
"2023-01-16 06:45:00+00:00 0.008446 \n",
"\n",
"[141636 rows x 64 columns]"
]
},
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.concat([mtf_data[col][c2_long_entry].add_suffix(f\"_{col}\") for col in required_cols], axis = 1)"
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {},
"outputs": [],
"source": [
"## Strategy conditions check - Using m15 and h4 data \n",
"mtf_data['entries'] = c1_long_entry & c2_long_entry\n",
"mtf_data['exits'] = c1_long_exit & c2_long_exit"
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {},
"outputs": [],
"source": [
"mtf_data['signal'] = 0 \n",
"mtf_data['signal'] = np.where( mtf_data['entries'], 1, 0)\n",
"mtf_data['signal'] = np.where( mtf_data['exits'] , -1, mtf_data['signal'])"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"After the above np.where, we can use this `pd.df.where` to return a pandas object"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {},
"outputs": [],
"source": [
"# After the above `np.where`, we can use this pd.df.where()\n",
"# (https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.where.html) to return a pandas object\n",
"mtf_data['signal'] = mtf_data['entries'].vbt.wrapper.wrap(mtf_data['signal'])\n",
"mtf_data['signal'] = mtf_data['exits'].vbt.wrapper.wrap(mtf_data['signal'])"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"AUDUSD Unique Signal col Values: [0, -1, 1]\n",
"EURGBP Unique Signal col Values: [0, 1, -1]\n",
"EURUSD Unique Signal col Values: [0, -1, 1]\n",
"GBPAUD Unique Signal col Values: [0, -1, 1]\n",
"GBPJPY Unique Signal col Values: [0, -1, 1]\n",
"GBPUSD Unique Signal col Values: [0, -1, 1]\n",
"USDCAD Unique Signal col Values: [0, -1, 1]\n",
"USDJPY Unique Signal col Values: [0, -1, 1]\n"
]
}
],
"source": [
"# list(mtf_data['signal']['GBPUSD'].unique())\n",
"symbols = m1_data.symbols\n",
"for symbol in symbols:\n",
" print(f\"{symbol} Unique Signal col Values: {list(mtf_data['signal'][symbol].unique())}\")"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" \n",
"Shape: (141636, 8)\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | symbol | \n",
" AUDUSD | \n",
" EURGBP | \n",
" EURUSD | \n",
" GBPAUD | \n",
" GBPJPY | \n",
" GBPUSD | \n",
" USDCAD | \n",
" USDJPY | \n",
"
\n",
" \n",
" | time | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | 2019-01-01 22:00:00+00:00 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2019-01-01 22:15:00+00:00 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2019-01-01 22:30:00+00:00 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2019-01-01 22:45:00+00:00 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2019-01-01 23:00:00+00:00 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 2023-01-16 05:45:00+00:00 | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
" -1 | \n",
" -1 | \n",
" -1 | \n",
"
\n",
" \n",
" | 2023-01-16 06:00:00+00:00 | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
" -1 | \n",
" -1 | \n",
" -1 | \n",
"
\n",
" \n",
" | 2023-01-16 06:15:00+00:00 | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
" -1 | \n",
" -1 | \n",
" -1 | \n",
"
\n",
" \n",
" | 2023-01-16 06:30:00+00:00 | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
" -1 | \n",
" -1 | \n",
" -1 | \n",
"
\n",
" \n",
" | 2023-01-16 06:45:00+00:00 | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
" -1 | \n",
" -1 | \n",
" -1 | \n",
"
\n",
" \n",
"
\n",
"
141636 rows × 8 columns
\n",
"
"
],
"text/plain": [
"symbol AUDUSD EURGBP EURUSD GBPAUD GBPJPY GBPUSD \\\n",
"time \n",
"2019-01-01 22:00:00+00:00 0 0 0 0 0 0 \n",
"2019-01-01 22:15:00+00:00 0 0 0 0 0 0 \n",
"2019-01-01 22:30:00+00:00 0 0 0 0 0 0 \n",
"2019-01-01 22:45:00+00:00 0 0 0 0 0 0 \n",
"2019-01-01 23:00:00+00:00 0 0 0 0 0 0 \n",
"... ... ... ... ... ... ... \n",
"2023-01-16 05:45:00+00:00 -1 1 1 -1 1 -1 \n",
"2023-01-16 06:00:00+00:00 -1 1 1 -1 1 -1 \n",
"2023-01-16 06:15:00+00:00 -1 1 1 -1 1 -1 \n",
"2023-01-16 06:30:00+00:00 -1 1 1 -1 1 -1 \n",
"2023-01-16 06:45:00+00:00 -1 1 1 -1 1 -1 \n",
"\n",
"symbol USDCAD USDJPY \n",
"time \n",
"2019-01-01 22:00:00+00:00 0 0 \n",
"2019-01-01 22:15:00+00:00 0 0 \n",
"2019-01-01 22:30:00+00:00 0 0 \n",
"2019-01-01 22:45:00+00:00 0 0 \n",
"2019-01-01 23:00:00+00:00 0 0 \n",
"... ... ... \n",
"2023-01-16 05:45:00+00:00 -1 -1 \n",
"2023-01-16 06:00:00+00:00 -1 -1 \n",
"2023-01-16 06:15:00+00:00 -1 -1 \n",
"2023-01-16 06:30:00+00:00 -1 -1 \n",
"2023-01-16 06:45:00+00:00 -1 -1 \n",
"\n",
"[141636 rows x 8 columns]"
]
},
"execution_count": 125,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(type(mtf_data['signal']), \"\\nShape:\", mtf_data['signal'].shape )\n",
"mtf_data['signal']"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dict_keys(['m15_close', 'm15_rsi', 'm15_bband_price_upper', 'm15_bband_price_middle', 'm15_bband_price_lower', 'm15_bband_rsi_upper', 'm15_bband_rsi_middle', 'm15_bband_rsi_lower', 'h1_open', 'h1_high', 'h1_low', 'h1_close', 'h1_rsi', 'h1_bband_price_upper', 'h1_bband_price_middle', 'h1_bband_price_lower', 'h1_bband_rsi_upper', 'h1_bband_rsi_middle', 'h1_bband_rsi_lower', 'h4_open', 'h4_high', 'h4_low', 'h4_close', 'h4_rsi', 'h4_bband_price_upper', 'h4_bband_price_middle', 'h4_bband_price_lower', 'h4_bband_rsi_upper', 'h4_bband_rsi_middle', 'entries', 'exits', 'signal'])"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mtf_data.keys()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"**`Cleaning` and Resample `entries` and `exits` to H4 timeframe**"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {},
"outputs": [],
"source": [
"entries = mtf_data['signal'] == 1.0\n",
"exits = mtf_data['signal'] == -1.0\n",
"\n",
"# print(f\"Total Nr. of Entry Signals:\\n {entries.vbt.signals.total()}\\n\")\n",
"# print(f\"Total Nr. of Exit Signals:\\n {exits.vbt.signals.total()}\")"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total nr. of Signals in Clean_Entries and Clean_Exits\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Entries | \n",
" Exits | \n",
"
\n",
" \n",
" | symbol | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | AUDUSD | \n",
" 343 | \n",
" 343 | \n",
"
\n",
" \n",
" | EURGBP | \n",
" 173 | \n",
" 172 | \n",
"
\n",
" \n",
" | EURUSD | \n",
" 396 | \n",
" 395 | \n",
"
\n",
" \n",
" | GBPAUD | \n",
" 214 | \n",
" 214 | \n",
"
\n",
" \n",
" | GBPJPY | \n",
" 131 | \n",
" 130 | \n",
"
\n",
" \n",
" | GBPUSD | \n",
" 432 | \n",
" 432 | \n",
"
\n",
" \n",
" | USDCAD | \n",
" 376 | \n",
" 376 | \n",
"
\n",
" \n",
" | USDJPY | \n",
" 290 | \n",
" 290 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Entries Exits\n",
"symbol \n",
"AUDUSD 343 343\n",
"EURGBP 173 172\n",
"EURUSD 396 395\n",
"GBPAUD 214 214\n",
"GBPJPY 131 130\n",
"GBPUSD 432 432\n",
"USDCAD 376 376\n",
"USDJPY 290 290"
]
},
"execution_count": 128,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Clean redundant and duplicate signals\n",
"clean_entries, clean_exits = entries.vbt.signals.clean(exits)\n",
"\n",
"print(f\"Total nr. of Signals in Clean_Entries and Clean_Exits\")\n",
"pd.DataFrame(data = {\"Entries\":clean_entries.vbt.signals.total(),\n",
" \"Exits\": clean_exits.vbt.signals.total()})"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We can resample the entries and exits for plotting purposes on H4 chart, but this always produces some loss in the nr. of signals as the entries / exits in our strategy is based on M15 timeframe. So just be aware of this."
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total nr. of signals in H4_Entries and H4_Exits Signals:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" H4_Entries | \n",
" h4_Exits | \n",
"
\n",
" \n",
" | symbol | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | AUDUSD | \n",
" 310 | \n",
" 307 | \n",
"
\n",
" \n",
" | EURGBP | \n",
" 136 | \n",
" 143 | \n",
"
\n",
" \n",
" | EURUSD | \n",
" 353 | \n",
" 357 | \n",
"
\n",
" \n",
" | GBPAUD | \n",
" 182 | \n",
" 194 | \n",
"
\n",
" \n",
" | GBPJPY | \n",
" 104 | \n",
" 119 | \n",
"
\n",
" \n",
" | GBPUSD | \n",
" 386 | \n",
" 382 | \n",
"
\n",
" \n",
" | USDCAD | \n",
" 333 | \n",
" 332 | \n",
"
\n",
" \n",
" | USDJPY | \n",
" 269 | \n",
" 272 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" H4_Entries h4_Exits\n",
"symbol \n",
"AUDUSD 310 307\n",
"EURGBP 136 143\n",
"EURUSD 353 357\n",
"GBPAUD 182 194\n",
"GBPJPY 104 119\n",
"GBPUSD 386 382\n",
"USDCAD 333 332\n",
"USDJPY 269 272"
]
},
"execution_count": 129,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## Resample clean entries to H$ timeframe\n",
"clean_h4_entries = clean_entries.vbt.resample_apply(\"4h\", \"any\", wrap_kwargs=dict(dtype=bool))\n",
"clean_h4_exits = clean_exits.vbt.resample_apply(\"4h\", \"any\", wrap_kwargs=dict(dtype=bool))\n",
"print(\"Total nr. of signals in H4_Entries and H4_Exits Signals:\")\n",
"pd.DataFrame(data = {\"H4_Entries\":clean_h4_entries.vbt.signals.total(),\n",
" \"h4_Exits\": clean_h4_exits.vbt.signals.total()})"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Saving Data to `.pickle` file\n",
"For the purposes of plotting, we will be saving various data like:\n",
"- price data across various timeframes\n",
"- indicator data across various timeframes\n",
"- entries & exits\n",
"- finally, the `vectorbt.portfolio` objects after running each type of portfolio simulation"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" || \n",
" || || \n",
" || || \n"
]
}
],
"source": [
"## Save Specific Data to pickle file for plotting purposes\n",
"price_data = {\"h4_data\": h4_data, \"m15_data\" : m15_data}\n",
"vbt_indicators = {'m15_rsi': m15_rsi,'m15_price_bbands': m15_bbands, 'm15_rsi_bbands' : m15_bbands_rsi,\n",
" 'h4_rsi': h4_rsi, 'h4_price_bbands':h4_bbands, 'h4_rsi_bbands' : h4_bbands_rsi}\n",
"\n",
"entries_exits_data = {'clean_entries' : clean_entries, 'clean_exits' : clean_exits}\n",
"\n",
"print(type(h4_data), '||' ,type(m15_data))\n",
"print(type(h4_bbands), '||', type(h4_bbands_rsi), '||', type(h1_rsi))\n",
"print(type(m15_bbands), '||', type(m15_bbands_rsi), '||', type(m15_rsi))\n",
"\n",
"file_path1 = '../vbt_dashboard/data/price_data'\n",
"file_path2 = '../vbt_dashboard/data/indicators_data'\n",
"file_path3 = '../vbt_dashboard/data/entries_exits_data'\n",
"\n",
"\n",
"vbt.save(price_data, file_path1)\n",
"vbt.save(vbt_indicators, file_path2)\n",
"vbt.save(entries_exits_data, file_path3)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Multi-asset Portfolio Backtesting simulation using `vbt.Portfolio.from_signals()`\n",
"In this section, we will see different ways to run this `portfolio.from_signals()` simulation and save the results as `.pickle` files to be used in a `plotly-dash` data visualization dashboard later (in another tutorial)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.) Asset-wise Discrete Portfolio Simulation\n",
"In this section we will see how to run the portfolio simulation for each asset in the portfolio independently. If we start with the default `from_signals()` function as we had from the [previous tutorial](https://qubitquants.pro/strategydev/index.html), the simulation is run for each symbol independently, which means the account balance is not connected between the various trades executed across symbols"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unique Symbols: ['AUDUSD', 'EURGBP', 'EURUSD', 'GBPAUD', 'GBPJPY', 'GBPUSD', 'USDCAD', 'USDJPY']\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Order Id | \n",
" Column | \n",
" Signal Index | \n",
" Creation Index | \n",
" Fill Index | \n",
" Side | \n",
" Type | \n",
" Stop Type | \n",
" Size | \n",
" Price | \n",
" Fees | \n",
" PnL | \n",
" Return | \n",
" Direction | \n",
" Status | \n",
" Entry Trade Id | \n",
" Exit Trade Id | \n",
" Position Id | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" AUDUSD | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 1.415919e+05 | \n",
" 0.706255 | \n",
" 0.0 | \n",
" -934.506658 | \n",
" -0.009345 | \n",
" Short | \n",
" Closed | \n",
" 0 | \n",
" -1 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 1 | \n",
" AUDUSD | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 1.415919e+05 | \n",
" 0.712855 | \n",
" 0.0 | \n",
" -934.506658 | \n",
" -0.009345 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" AUDUSD | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 1.389700e+05 | \n",
" 0.712855 | \n",
" 0.0 | \n",
" 1419.579037 | \n",
" 0.014330 | \n",
" Long | \n",
" Closed | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 4 | \n",
" 2 | \n",
" AUDUSD | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 1.389700e+05 | \n",
" 0.723070 | \n",
" 0.0 | \n",
" 1419.579037 | \n",
" 0.014330 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 3 | \n",
" 2 | \n",
" AUDUSD | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 1.389700e+05 | \n",
" 0.723070 | \n",
" 0.0 | \n",
" 25.014609 | \n",
" 0.000249 | \n",
" Short | \n",
" Closed | \n",
" 2 | \n",
" -1 | \n",
" 2 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 7652 | \n",
" 497 | \n",
" USDJPY | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 1.246473e+07 | \n",
" 0.008489 | \n",
" 0.0 | \n",
" -223.637166 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" 497 | \n",
" -1 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7655 | \n",
" 498 | \n",
" USDJPY | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 1.246473e+07 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" -223.637166 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 497 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7654 | \n",
" 498 | \n",
" USDJPY | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 1.246473e+07 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" 125.074237 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" 498 | \n",
" -1 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7657 | \n",
" 499 | \n",
" USDJPY | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 1.246473e+07 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 125.074237 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 498 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7656 | \n",
" 499 | \n",
" USDJPY | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 1.249429e+07 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 1103.518449 | \n",
" 0.010439 | \n",
" Long | \n",
" Open | \n",
" 499 | \n",
" -1 | \n",
" 499 | \n",
"
\n",
" \n",
"
\n",
"
7658 rows × 18 columns
\n",
"
"
],
"text/plain": [
" Order Id Column Signal Index Creation Index \\\n",
"0 0 AUDUSD 2019-01-08 16:00:00+00:00 2019-01-08 16:00:00+00:00 \n",
"2 1 AUDUSD 2019-01-16 23:45:00+00:00 2019-01-16 23:45:00+00:00 \n",
"1 1 AUDUSD 2019-01-16 23:45:00+00:00 2019-01-16 23:45:00+00:00 \n",
"4 2 AUDUSD 2019-01-20 23:00:00+00:00 2019-01-20 23:00:00+00:00 \n",
"3 2 AUDUSD 2019-01-20 23:00:00+00:00 2019-01-20 23:00:00+00:00 \n",
"... ... ... ... ... \n",
"7652 497 USDJPY 2022-01-09 08:15:00+00:00 2022-01-09 08:15:00+00:00 \n",
"7655 498 USDJPY 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 \n",
"7654 498 USDJPY 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 \n",
"7657 499 USDJPY 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 \n",
"7656 499 USDJPY 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 \n",
"\n",
" Fill Index Side Type Stop Type Size \\\n",
"0 2019-01-08 16:00:00+00:00 Sell Market None 1.415919e+05 \n",
"2 2019-01-16 23:45:00+00:00 Buy Market None 1.415919e+05 \n",
"1 2019-01-16 23:45:00+00:00 Buy Market None 1.389700e+05 \n",
"4 2019-01-20 23:00:00+00:00 Sell Market None 1.389700e+05 \n",
"3 2019-01-20 23:00:00+00:00 Sell Market None 1.389700e+05 \n",
"... ... ... ... ... ... \n",
"7652 2022-01-09 08:15:00+00:00 Buy Market None 1.246473e+07 \n",
"7655 2022-01-09 15:45:00+00:00 Sell Market None 1.246473e+07 \n",
"7654 2022-01-09 15:45:00+00:00 Sell Market None 1.246473e+07 \n",
"7657 2022-01-09 16:00:00+00:00 Buy Market None 1.246473e+07 \n",
"7656 2022-01-09 16:00:00+00:00 Buy Market None 1.249429e+07 \n",
"\n",
" Price Fees PnL Return Direction Status Entry Trade Id \\\n",
"0 0.706255 0.0 -934.506658 -0.009345 Short Closed 0 \n",
"2 0.712855 0.0 -934.506658 -0.009345 Short Closed -1 \n",
"1 0.712855 0.0 1419.579037 0.014330 Long Closed 1 \n",
"4 0.723070 0.0 1419.579037 0.014330 Long Closed -1 \n",
"3 0.723070 0.0 25.014609 0.000249 Short Closed 2 \n",
"... ... ... ... ... ... ... ... \n",
"7652 0.008489 0.0 -223.637166 -0.002114 Long Closed 497 \n",
"7655 0.008471 0.0 -223.637166 -0.002114 Long Closed -1 \n",
"7654 0.008471 0.0 125.074237 0.001185 Short Closed 498 \n",
"7657 0.008461 0.0 125.074237 0.001185 Short Closed -1 \n",
"7656 0.008461 0.0 1103.518449 0.010439 Long Open 499 \n",
"\n",
" Exit Trade Id Position Id \n",
"0 -1 0 \n",
"2 0 0 \n",
"1 -1 1 \n",
"4 1 1 \n",
"3 -1 2 \n",
"... ... ... \n",
"7652 -1 497 \n",
"7655 497 497 \n",
"7654 -1 498 \n",
"7657 498 498 \n",
"7656 -1 499 \n",
"\n",
"[7658 rows x 18 columns]"
]
},
"execution_count": 131,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pf_from_signals_v1 = vbt.Portfolio.from_signals(\n",
" close = mtf_data['m15_close'], \n",
" entries = mtf_data['entries'], \n",
" exits = mtf_data['exits'], \n",
" direction = \"both\", ## This setting trades both long and short signals\n",
" freq = pd.Timedelta(minutes=15), \n",
" init_cash = 100000\n",
")\n",
"\n",
"## Save portfolio simulation as a pickle file\n",
"pf_from_signals_v1.save(\"../vbt_dashboard/data/pf_sim_discrete\")\n",
"\n",
"## Load saved portfolio simulation from pickle file\n",
"pf = vbt.Portfolio.load('../vbt_dashboard/data/pf_sim_discrete')\n",
"\n",
"## View Trading History of pf.simulation \n",
"pf_trade_history = pf.trade_history\n",
"print(\"Unique Symbols:\", list(pf_trade_history['Column'].unique()) )\n",
"pf_trade_history"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/var/folders/v1/9vbsmmyj7ml0rx9r62b_03c80000gn/T/ipykernel_15728/903157885.py:2: UserWarning: Object has multiple columns. Aggregated some metrics using . Pass column to select a single column/group.\n",
" stats_df = pd.concat([pf.stats()] + [pf[symbol].stats() for symbol in symbols], axis = 1)\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Metrics | \n",
" Agg_Stats | \n",
" AUDUSD | \n",
" EURGBP | \n",
" EURUSD | \n",
" GBPAUD | \n",
" GBPJPY | \n",
" GBPUSD | \n",
" USDCAD | \n",
" USDJPY | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" Start | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
"
\n",
" \n",
" | 1 | \n",
" End | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
"
\n",
" \n",
" | 2 | \n",
" Period | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
"
\n",
" \n",
" | 3 | \n",
" Start Value | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
" 100000.0 | \n",
"
\n",
" \n",
" | 4 | \n",
" Min Value | \n",
" 91702.349208 | \n",
" 90045.131523 | \n",
" 95322.347798 | \n",
" 98627.645459 | \n",
" 91206.754921 | \n",
" 88023.335074 | \n",
" 85813.084412 | \n",
" 92669.521096 | \n",
" 91910.973382 | \n",
"
\n",
" \n",
" | 5 | \n",
" Max Value | \n",
" 107556.598818 | \n",
" 109189.793819 | \n",
" 106013.882745 | \n",
" 111388.137845 | \n",
" 112422.030122 | \n",
" 107282.960571 | \n",
" 101280.220766 | \n",
" 105983.225022 | \n",
" 106892.539653 | \n",
"
\n",
" \n",
" | 6 | \n",
" End Value | \n",
" 100367.541502 | \n",
" 99956.64516 | \n",
" 101133.781763 | \n",
" 104162.736879 | \n",
" 97718.99519 | \n",
" 97861.297648 | \n",
" 91182.110407 | \n",
" 104107.161632 | \n",
" 106817.603339 | \n",
"
\n",
" \n",
" | 7 | \n",
" Total Return [%] | \n",
" 0.367542 | \n",
" -0.043355 | \n",
" 1.133782 | \n",
" 4.162737 | \n",
" -2.281005 | \n",
" -2.138702 | \n",
" -8.81789 | \n",
" 4.107162 | \n",
" 6.817603 | \n",
"
\n",
" \n",
" | 8 | \n",
" Benchmark Return [%] | \n",
" -2.566604 | \n",
" -1.315145 | \n",
" -2.391998 | \n",
" -8.042332 | \n",
" 2.733491 | \n",
" -3.966899 | \n",
" -6.427266 | \n",
" 5.16234 | \n",
" -6.285025 | \n",
"
\n",
" \n",
" | 9 | \n",
" Total Time Exposure [%] | \n",
" 98.93371 | \n",
" 99.542489 | \n",
" 98.605581 | \n",
" 98.738315 | \n",
" 97.170917 | \n",
" 98.401536 | \n",
" 99.260075 | \n",
" 99.867265 | \n",
" 99.883504 | \n",
"
\n",
" \n",
" | 10 | \n",
" Max Gross Exposure [%] | \n",
" 104.022697 | \n",
" 102.613517 | \n",
" 106.638701 | \n",
" 101.206839 | \n",
" 106.234838 | \n",
" 106.373637 | \n",
" 102.547336 | \n",
" 105.004417 | \n",
" 101.56229 | \n",
"
\n",
" \n",
" | 11 | \n",
" Max Drawdown [%] | \n",
" 13.50183 | \n",
" 17.533381 | \n",
" 10.085033 | \n",
" 11.455881 | \n",
" 18.871101 | \n",
" 15.141241 | \n",
" 14.760923 | \n",
" 9.236595 | \n",
" 10.930482 | \n",
"
\n",
" \n",
" | 12 | \n",
" Max Drawdown Duration | \n",
" 801 days 01:26:15 | \n",
" 809 days 02:00:00 | \n",
" 1215 days 23:15:00 | \n",
" 479 days 16:45:00 | \n",
" 1027 days 17:30:00 | \n",
" 704 days 01:15:00 | \n",
" 836 days 23:45:00 | \n",
" 378 days 07:30:00 | \n",
" 956 days 15:30:00 | \n",
"
\n",
" \n",
" | 13 | \n",
" Total Orders | \n",
" 479.125 | \n",
" 573 | \n",
" 251 | \n",
" 674 | \n",
" 328 | \n",
" 176 | \n",
" 700 | \n",
" 631 | \n",
" 500 | \n",
"
\n",
" \n",
" | 14 | \n",
" Total Fees Paid | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 15 | \n",
" Total Trades | \n",
" 479.125 | \n",
" 573 | \n",
" 251 | \n",
" 674 | \n",
" 328 | \n",
" 176 | \n",
" 700 | \n",
" 631 | \n",
" 500 | \n",
"
\n",
" \n",
" | 16 | \n",
" Win Rate [%] | \n",
" 62.855149 | \n",
" 61.888112 | \n",
" 66.4 | \n",
" 64.041605 | \n",
" 62.996942 | \n",
" 58.857143 | \n",
" 62.088698 | \n",
" 64.444444 | \n",
" 62.124248 | \n",
"
\n",
" \n",
" | 17 | \n",
" Best Trade [%] | \n",
" 2.868856 | \n",
" 2.696122 | \n",
" 3.32835 | \n",
" 1.69205 | \n",
" 4.06637 | \n",
" 4.057935 | \n",
" 2.662538 | \n",
" 1.170649 | \n",
" 3.276834 | \n",
"
\n",
" \n",
" | 18 | \n",
" Worst Trade [%] | \n",
" -4.567903 | \n",
" -7.984396 | \n",
" -3.586285 | \n",
" -2.145795 | \n",
" -6.862178 | \n",
" -4.234196 | \n",
" -6.089636 | \n",
" -2.404781 | \n",
" -3.235954 | \n",
"
\n",
" \n",
" | 19 | \n",
" Avg Winning Trade [%] | \n",
" 0.23967 | \n",
" 0.212419 | \n",
" 0.277743 | \n",
" 0.144288 | \n",
" 0.361669 | \n",
" 0.450155 | \n",
" 0.169079 | \n",
" 0.121248 | \n",
" 0.180762 | \n",
"
\n",
" \n",
" | 20 | \n",
" Avg Losing Trade [%] | \n",
" -0.392531 | \n",
" -0.344853 | \n",
" -0.521055 | \n",
" -0.24255 | \n",
" -0.626788 | \n",
" -0.623333 | \n",
" -0.314004 | \n",
" -0.20067 | \n",
" -0.266994 | \n",
"
\n",
" \n",
" | 21 | \n",
" Avg Winning Trade Duration | \n",
" 1 days 19:21:39 | \n",
" 1 days 04:19:47 | \n",
" 3 days 02:11:06 | \n",
" 1 days 08:06:38 | \n",
" 1 days 19:07:08 | \n",
" 3 days 09:30:08 | \n",
" 1 days 06:56:38 | \n",
" 1 days 02:53:58 | \n",
" 1 days 05:47:51 | \n",
"
\n",
" \n",
" | 22 | \n",
" Avg Losing Trade Duration | \n",
" 4 days 15:07:36 | \n",
" 2 days 15:40:48 | \n",
" 7 days 06:38:53 | \n",
" 3 days 07:28:10 | \n",
" 4 days 20:41:07 | \n",
" 8 days 09:34:35 | \n",
" 3 days 08:03:57 | \n",
" 3 days 08:51:21 | \n",
" 3 days 20:01:55 | \n",
"
\n",
" \n",
" | 23 | \n",
" Profit Factor | \n",
" 1.027429 | \n",
" 0.999423 | \n",
" 1.076212 | \n",
" 1.067599 | \n",
" 0.973194 | \n",
" 1.015027 | \n",
" 0.884548 | \n",
" 1.089144 | \n",
" 1.114286 | \n",
"
\n",
" \n",
" | 24 | \n",
" Expectancy | \n",
" 2.699415 | \n",
" -0.075795 | \n",
" 13.126114 | \n",
" 6.124405 | \n",
" -6.315343 | \n",
" 3.805774 | \n",
" -12.908394 | \n",
" 6.387491 | \n",
" 11.451072 | \n",
"
\n",
" \n",
" | 25 | \n",
" Sharpe Ratio | \n",
" 0.07429 | \n",
" 0.031206 | \n",
" 0.074893 | \n",
" 0.224996 | \n",
" -0.020954 | \n",
" -0.029906 | \n",
" -0.29204 | \n",
" 0.253851 | \n",
" 0.352274 | \n",
"
\n",
" \n",
" | 26 | \n",
" Calmar Ratio | \n",
" 0.019512 | \n",
" -0.000612 | \n",
" 0.027695 | \n",
" 0.088521 | \n",
" -0.030163 | \n",
" -0.035229 | \n",
" -0.152962 | \n",
" 0.108346 | \n",
" 0.150498 | \n",
"
\n",
" \n",
" | 27 | \n",
" Omega Ratio | \n",
" 1.00543 | \n",
" 1.001928 | \n",
" 1.012664 | \n",
" 1.012787 | \n",
" 0.997674 | \n",
" 0.993371 | \n",
" 0.981075 | \n",
" 1.018555 | \n",
" 1.025383 | \n",
"
\n",
" \n",
" | 28 | \n",
" Sortino Ratio | \n",
" 0.108364 | \n",
" 0.042061 | \n",
" 0.103337 | \n",
" 0.328878 | \n",
" -0.028837 | \n",
" -0.043598 | \n",
" -0.432771 | \n",
" 0.336553 | \n",
" 0.56129 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Metrics Agg_Stats \\\n",
"0 Start 2019-01-01 22:00:00+00:00 \n",
"1 End 2023-01-16 06:45:00+00:00 \n",
"2 Period 1475 days 09:00:00 \n",
"3 Start Value 100000.0 \n",
"4 Min Value 91702.349208 \n",
"5 Max Value 107556.598818 \n",
"6 End Value 100367.541502 \n",
"7 Total Return [%] 0.367542 \n",
"8 Benchmark Return [%] -2.566604 \n",
"9 Total Time Exposure [%] 98.93371 \n",
"10 Max Gross Exposure [%] 104.022697 \n",
"11 Max Drawdown [%] 13.50183 \n",
"12 Max Drawdown Duration 801 days 01:26:15 \n",
"13 Total Orders 479.125 \n",
"14 Total Fees Paid 0.0 \n",
"15 Total Trades 479.125 \n",
"16 Win Rate [%] 62.855149 \n",
"17 Best Trade [%] 2.868856 \n",
"18 Worst Trade [%] -4.567903 \n",
"19 Avg Winning Trade [%] 0.23967 \n",
"20 Avg Losing Trade [%] -0.392531 \n",
"21 Avg Winning Trade Duration 1 days 19:21:39 \n",
"22 Avg Losing Trade Duration 4 days 15:07:36 \n",
"23 Profit Factor 1.027429 \n",
"24 Expectancy 2.699415 \n",
"25 Sharpe Ratio 0.07429 \n",
"26 Calmar Ratio 0.019512 \n",
"27 Omega Ratio 1.00543 \n",
"28 Sortino Ratio 0.108364 \n",
"\n",
" AUDUSD EURGBP \\\n",
"0 2019-01-01 22:00:00+00:00 2019-01-01 22:00:00+00:00 \n",
"1 2023-01-16 06:45:00+00:00 2023-01-16 06:45:00+00:00 \n",
"2 1475 days 09:00:00 1475 days 09:00:00 \n",
"3 100000.0 100000.0 \n",
"4 90045.131523 95322.347798 \n",
"5 109189.793819 106013.882745 \n",
"6 99956.64516 101133.781763 \n",
"7 -0.043355 1.133782 \n",
"8 -1.315145 -2.391998 \n",
"9 99.542489 98.605581 \n",
"10 102.613517 106.638701 \n",
"11 17.533381 10.085033 \n",
"12 809 days 02:00:00 1215 days 23:15:00 \n",
"13 573 251 \n",
"14 0.0 0.0 \n",
"15 573 251 \n",
"16 61.888112 66.4 \n",
"17 2.696122 3.32835 \n",
"18 -7.984396 -3.586285 \n",
"19 0.212419 0.277743 \n",
"20 -0.344853 -0.521055 \n",
"21 1 days 04:19:47 3 days 02:11:06 \n",
"22 2 days 15:40:48 7 days 06:38:53 \n",
"23 0.999423 1.076212 \n",
"24 -0.075795 13.126114 \n",
"25 0.031206 0.074893 \n",
"26 -0.000612 0.027695 \n",
"27 1.001928 1.012664 \n",
"28 0.042061 0.103337 \n",
"\n",
" EURUSD GBPAUD \\\n",
"0 2019-01-01 22:00:00+00:00 2019-01-01 22:00:00+00:00 \n",
"1 2023-01-16 06:45:00+00:00 2023-01-16 06:45:00+00:00 \n",
"2 1475 days 09:00:00 1475 days 09:00:00 \n",
"3 100000.0 100000.0 \n",
"4 98627.645459 91206.754921 \n",
"5 111388.137845 112422.030122 \n",
"6 104162.736879 97718.99519 \n",
"7 4.162737 -2.281005 \n",
"8 -8.042332 2.733491 \n",
"9 98.738315 97.170917 \n",
"10 101.206839 106.234838 \n",
"11 11.455881 18.871101 \n",
"12 479 days 16:45:00 1027 days 17:30:00 \n",
"13 674 328 \n",
"14 0.0 0.0 \n",
"15 674 328 \n",
"16 64.041605 62.996942 \n",
"17 1.69205 4.06637 \n",
"18 -2.145795 -6.862178 \n",
"19 0.144288 0.361669 \n",
"20 -0.24255 -0.626788 \n",
"21 1 days 08:06:38 1 days 19:07:08 \n",
"22 3 days 07:28:10 4 days 20:41:07 \n",
"23 1.067599 0.973194 \n",
"24 6.124405 -6.315343 \n",
"25 0.224996 -0.020954 \n",
"26 0.088521 -0.030163 \n",
"27 1.012787 0.997674 \n",
"28 0.328878 -0.028837 \n",
"\n",
" GBPJPY GBPUSD \\\n",
"0 2019-01-01 22:00:00+00:00 2019-01-01 22:00:00+00:00 \n",
"1 2023-01-16 06:45:00+00:00 2023-01-16 06:45:00+00:00 \n",
"2 1475 days 09:00:00 1475 days 09:00:00 \n",
"3 100000.0 100000.0 \n",
"4 88023.335074 85813.084412 \n",
"5 107282.960571 101280.220766 \n",
"6 97861.297648 91182.110407 \n",
"7 -2.138702 -8.81789 \n",
"8 -3.966899 -6.427266 \n",
"9 98.401536 99.260075 \n",
"10 106.373637 102.547336 \n",
"11 15.141241 14.760923 \n",
"12 704 days 01:15:00 836 days 23:45:00 \n",
"13 176 700 \n",
"14 0.0 0.0 \n",
"15 176 700 \n",
"16 58.857143 62.088698 \n",
"17 4.057935 2.662538 \n",
"18 -4.234196 -6.089636 \n",
"19 0.450155 0.169079 \n",
"20 -0.623333 -0.314004 \n",
"21 3 days 09:30:08 1 days 06:56:38 \n",
"22 8 days 09:34:35 3 days 08:03:57 \n",
"23 1.015027 0.884548 \n",
"24 3.805774 -12.908394 \n",
"25 -0.029906 -0.29204 \n",
"26 -0.035229 -0.152962 \n",
"27 0.993371 0.981075 \n",
"28 -0.043598 -0.432771 \n",
"\n",
" USDCAD USDJPY \n",
"0 2019-01-01 22:00:00+00:00 2019-01-01 22:00:00+00:00 \n",
"1 2023-01-16 06:45:00+00:00 2023-01-16 06:45:00+00:00 \n",
"2 1475 days 09:00:00 1475 days 09:00:00 \n",
"3 100000.0 100000.0 \n",
"4 92669.521096 91910.973382 \n",
"5 105983.225022 106892.539653 \n",
"6 104107.161632 106817.603339 \n",
"7 4.107162 6.817603 \n",
"8 5.16234 -6.285025 \n",
"9 99.867265 99.883504 \n",
"10 105.004417 101.56229 \n",
"11 9.236595 10.930482 \n",
"12 378 days 07:30:00 956 days 15:30:00 \n",
"13 631 500 \n",
"14 0.0 0.0 \n",
"15 631 500 \n",
"16 64.444444 62.124248 \n",
"17 1.170649 3.276834 \n",
"18 -2.404781 -3.235954 \n",
"19 0.121248 0.180762 \n",
"20 -0.20067 -0.266994 \n",
"21 1 days 02:53:58 1 days 05:47:51 \n",
"22 3 days 08:51:21 3 days 20:01:55 \n",
"23 1.089144 1.114286 \n",
"24 6.387491 11.451072 \n",
"25 0.253851 0.352274 \n",
"26 0.108346 0.150498 \n",
"27 1.018555 1.025383 \n",
"28 0.336553 0.56129 "
]
},
"execution_count": 132,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## View Portfolio Stats as a dataframe for pf_from_signals_v1 case\n",
"stats_df = pd.concat([pf.stats()] + [pf[symbol].stats() for symbol in symbols], axis = 1)\n",
"stats_df.loc['Avg Winning Trade Duration'] = [x.floor('s') for x in stats_df.iloc[21]]\n",
"stats_df.loc['Avg Losing Trade Duration'] = [x.floor('s') for x in stats_df.iloc[22]]\n",
"stats_df = stats_df.reset_index() \n",
"stats_df.rename(inplace = True, columns = {'agg_stats':'Agg_Stats', 'index' : 'Metrics' }) \n",
"stats_df"
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mean Total Return [%] (across cols): 0.3675\n",
"Mean Total Orders (across cols): 479.125\n",
"Mean Sortino Ratio (across cols): 0.1084\n"
]
}
],
"source": [
"print(\"Mean Total Return [%] (across cols):\", np.round(np.mean(stats_df.iloc[[7]].values.tolist()[0][1:]), 4) )\n",
"print(\"Mean Total Orders (across cols):\", np.round(np.mean(stats_df.iloc[[13]].values.tolist()[0][1:]), 4) )\n",
"print(\"Mean Sortino Ratio (across cols):\", np.round(np.mean(stats_df.iloc[[28]].values.tolist()[0][1:]), 4) )"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"2.) Run potfolio simulation treating the entire portfolio as a singular asset by enabling the following parameters in the `pf.from_signals()`:
\n",
"* `cash_sharing = True`\n",
"* `group_by = True`\n",
"* `size = 100`\n",
"* `call_seq = \"auto\"`"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unique Symbols: ['AUDUSD', 'EURGBP', 'EURUSD', 'GBPAUD', 'GBPJPY', 'GBPUSD', 'USDCAD', 'USDJPY']\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Order Id | \n",
" Column | \n",
" Signal Index | \n",
" Creation Index | \n",
" Fill Index | \n",
" Side | \n",
" Type | \n",
" Stop Type | \n",
" Size | \n",
" Price | \n",
" Fees | \n",
" PnL | \n",
" Return | \n",
" Direction | \n",
" Status | \n",
" Entry Trade Id | \n",
" Exit Trade Id | \n",
" Position Id | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" AUDUSD | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" 2019-01-08 16:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.706255 | \n",
" 0.0 | \n",
" -660.000000 | \n",
" -0.009345 | \n",
" Short | \n",
" Closed | \n",
" 0 | \n",
" -1 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 1 | \n",
" AUDUSD | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.712855 | \n",
" 0.0 | \n",
" -660.000000 | \n",
" -0.009345 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" AUDUSD | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" 2019-01-16 23:45:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.712855 | \n",
" 0.0 | \n",
" 1021.500000 | \n",
" 0.014330 | \n",
" Long | \n",
" Closed | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 4 | \n",
" 2 | \n",
" AUDUSD | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.723070 | \n",
" 0.0 | \n",
" 1021.500000 | \n",
" 0.014330 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 3 | \n",
" 2 | \n",
" AUDUSD | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" 2019-01-20 23:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.723070 | \n",
" 0.0 | \n",
" 18.000000 | \n",
" 0.000249 | \n",
" Short | \n",
" Closed | \n",
" 2 | \n",
" -1 | \n",
" 2 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 7652 | \n",
" 497 | \n",
" USDJPY | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008489 | \n",
" 0.0 | \n",
" -1.794160 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" 497 | \n",
" -1 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7655 | \n",
" 498 | \n",
" USDJPY | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" -1.794160 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 497 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7654 | \n",
" 498 | \n",
" USDJPY | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" 1.003425 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" 498 | \n",
" -1 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7657 | \n",
" 499 | \n",
" USDJPY | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 1.003425 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 498 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7656 | \n",
" 499 | \n",
" USDJPY | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 8.832179 | \n",
" 0.010439 | \n",
" Long | \n",
" Open | \n",
" 499 | \n",
" -1 | \n",
" 499 | \n",
"
\n",
" \n",
"
\n",
"
7658 rows × 18 columns
\n",
"
"
],
"text/plain": [
" Order Id Column Signal Index Creation Index \\\n",
"0 0 AUDUSD 2019-01-08 16:00:00+00:00 2019-01-08 16:00:00+00:00 \n",
"2 1 AUDUSD 2019-01-16 23:45:00+00:00 2019-01-16 23:45:00+00:00 \n",
"1 1 AUDUSD 2019-01-16 23:45:00+00:00 2019-01-16 23:45:00+00:00 \n",
"4 2 AUDUSD 2019-01-20 23:00:00+00:00 2019-01-20 23:00:00+00:00 \n",
"3 2 AUDUSD 2019-01-20 23:00:00+00:00 2019-01-20 23:00:00+00:00 \n",
"... ... ... ... ... \n",
"7652 497 USDJPY 2022-01-09 08:15:00+00:00 2022-01-09 08:15:00+00:00 \n",
"7655 498 USDJPY 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 \n",
"7654 498 USDJPY 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 \n",
"7657 499 USDJPY 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 \n",
"7656 499 USDJPY 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 \n",
"\n",
" Fill Index Side Type Stop Type Size Price \\\n",
"0 2019-01-08 16:00:00+00:00 Sell Market None 100000.0 0.706255 \n",
"2 2019-01-16 23:45:00+00:00 Buy Market None 100000.0 0.712855 \n",
"1 2019-01-16 23:45:00+00:00 Buy Market None 100000.0 0.712855 \n",
"4 2019-01-20 23:00:00+00:00 Sell Market None 100000.0 0.723070 \n",
"3 2019-01-20 23:00:00+00:00 Sell Market None 100000.0 0.723070 \n",
"... ... ... ... ... ... ... \n",
"7652 2022-01-09 08:15:00+00:00 Buy Market None 100000.0 0.008489 \n",
"7655 2022-01-09 15:45:00+00:00 Sell Market None 100000.0 0.008471 \n",
"7654 2022-01-09 15:45:00+00:00 Sell Market None 100000.0 0.008471 \n",
"7657 2022-01-09 16:00:00+00:00 Buy Market None 100000.0 0.008461 \n",
"7656 2022-01-09 16:00:00+00:00 Buy Market None 100000.0 0.008461 \n",
"\n",
" Fees PnL Return Direction Status Entry Trade Id \\\n",
"0 0.0 -660.000000 -0.009345 Short Closed 0 \n",
"2 0.0 -660.000000 -0.009345 Short Closed -1 \n",
"1 0.0 1021.500000 0.014330 Long Closed 1 \n",
"4 0.0 1021.500000 0.014330 Long Closed -1 \n",
"3 0.0 18.000000 0.000249 Short Closed 2 \n",
"... ... ... ... ... ... ... \n",
"7652 0.0 -1.794160 -0.002114 Long Closed 497 \n",
"7655 0.0 -1.794160 -0.002114 Long Closed -1 \n",
"7654 0.0 1.003425 0.001185 Short Closed 498 \n",
"7657 0.0 1.003425 0.001185 Short Closed -1 \n",
"7656 0.0 8.832179 0.010439 Long Open 499 \n",
"\n",
" Exit Trade Id Position Id \n",
"0 -1 0 \n",
"2 0 0 \n",
"1 -1 1 \n",
"4 1 1 \n",
"3 -1 2 \n",
"... ... ... \n",
"7652 -1 497 \n",
"7655 497 497 \n",
"7654 -1 498 \n",
"7657 498 498 \n",
"7656 -1 499 \n",
"\n",
"[7658 rows x 18 columns]"
]
},
"execution_count": 134,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pf_from_signals_v2 = vbt.Portfolio.from_signals(\n",
" close = mtf_data['m15_close'], \n",
" entries = mtf_data['entries'], \n",
" exits = mtf_data['exits'], \n",
" direction = \"both\", ## This setting trades both long and short signals\n",
" freq = pd.Timedelta(minutes=15), \n",
" init_cash = \"auto\",\n",
" size = 100000,\n",
" group_by = True,\n",
" cash_sharing = True,\n",
" call_seq = \"auto\"\n",
")\n",
"\n",
"## Save portfolio simulation as a pickle file\n",
"pf_from_signals_v2.save(\"../vbt_dashboard/data/pf_sim_single\")\n",
"\n",
"## Load portfolio simulation from pickle file\n",
"pf = vbt.Portfolio.load('../vbt_dashboard/data/pf_sim_single')\n",
"\n",
"## View Trading History of pf.simulation \n",
"pf_trade_history = pf.trade_history\n",
"print(\"Unique Symbols:\", list(pf_trade_history['Column'].unique()) )\n",
"pf_trade_history"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Start 2019-01-01 22:00:00+00:00\n",
"End 2023-01-16 06:45:00+00:00\n",
"Period 1475 days 09:00:00\n",
"Start Value 781099.026861\n",
"Min Value 751459.25085\n",
"Max Value 808290.908182\n",
"End Value 778580.017067\n",
"Total Return [%] -0.322496\n",
"Benchmark Return [%] 0.055682\n",
"Total Time Exposure [%] 99.883504\n",
"Max Gross Exposure [%] 99.851773\n",
"Max Drawdown [%] 4.745308\n",
"Max Drawdown Duration 740 days 04:15:00\n",
"Total Orders 3833\n",
"Total Fees Paid 0.0\n",
"Total Trades 3833\n",
"Win Rate [%] 63.006536\n",
"Best Trade [%] 4.06637\n",
"Worst Trade [%] -7.984396\n",
"Avg Winning Trade [%] 0.200416\n",
"Avg Losing Trade [%] -0.336912\n",
"Avg Winning Trade Duration 1 days 12:07:11.327800829\n",
"Avg Losing Trade Duration 3 days 22:03:11.201716738\n",
"Profit Factor 1.007163\n",
"Expectancy 0.858292\n",
"Sharpe Ratio -0.015093\n",
"Calmar Ratio -0.016834\n",
"Omega Ratio 0.999318\n",
"Sortino Ratio -0.021298\n",
"Name: group, dtype: object"
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## View Portfolio Stats as a dataframe for pf_from_signals_v2 case\n",
"pf.stats() "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"3.) Run portfolio simulation by grouping individual instruments in the portfolio basket into two groups and enabling the following parameters in the `pf.from_signals()`:
\n",
"* `cash_sharing = True`\n",
"* `group_by = 0`\n",
"* `call_seq = \"auto\"`\n",
"* `size = 100000`\n"
]
},
{
"cell_type": "code",
"execution_count": 136,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Symbols: ['AUDUSD', 'EURGBP', 'EURUSD', 'GBPAUD', 'GBPJPY', 'GBPUSD', 'USDCAD', 'USDJPY']\n",
"Group Types: ['USDPairs', 'NonUSDPairs', 'USDPairs', 'NonUSDPairs', 'NonUSDPairs', 'USDPairs', 'USDPairs', 'USDPairs']\n",
"Nr. of Unique Groups: ['USDPairs', 'NonUSDPairs']\n"
]
}
],
"source": [
"print(\"Symbols:\",list(pf_from_signals_v2.wrapper.columns))\n",
"grp_type = ['USDPairs', 'NonUSDPairs', 'USDPairs', 'NonUSDPairs', 'NonUSDPairs', 'USDPairs', 'USDPairs', 'USDPairs']\n",
"unique_grp_types = list(set(grp_type))\n",
"print(\"Group Types:\", grp_type)\n",
"print(\"Nr. of Unique Groups:\", unique_grp_types)"
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {},
"outputs": [],
"source": [
"def reorder_columns(df, group_by):\n",
" return df.vbt.stack_index(group_by).sort_index(axis=1, level=0)\n",
" \n",
"pf_from_signals_v3 = vbt.Portfolio.from_signals(\n",
" close = reorder_columns(mtf_data[\"m15_close\"], group_by = grp_type),\n",
" entries = reorder_columns(mtf_data['entries'], group_by = grp_type),\n",
" exits = reorder_columns(mtf_data['exits'], group_by = grp_type),\n",
" direction = \"both\", ## This setting trades both long and short signals\n",
" freq = pd.Timedelta(minutes=15), \n",
" init_cash = \"auto\",\n",
" size = 100000,\n",
" group_by = 0,\n",
" cash_sharing=True,\n",
" call_seq=\"auto\"\n",
")\n",
"\n",
"\n",
"## Save portfolio simulation as a pickle file\n",
"pf_from_signals_v3.save(\"../vbt_dashboard/data/pf_sim_grouped\")\n",
"\n",
"## Load portfolio simulation from a pickle file\n",
"pf = vbt.Portfolio.load('../vbt_dashboard/data/pf_sim_grouped')"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we basically appended `grp_type` list as the top-most level to the columns of each dataframe, which makes it the first in the hierarchy.
Group-by can accept both level position and level name (which we don't have in this case, since we passed the `grp_type` list).
Refer the following `pandas` documentation to understand more hierarchical indexing: https://pandas.pydata.org/docs/user_guide/advanced.html"
]
},
{
"cell_type": "code",
"execution_count": 138,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unique Symbols: [('NonUSDPairs', 'EURGBP'), ('NonUSDPairs', 'GBPAUD'), ('NonUSDPairs', 'GBPJPY'), ('USDPairs', 'AUDUSD'), ('USDPairs', 'EURUSD'), ('USDPairs', 'GBPUSD'), ('USDPairs', 'USDCAD'), ('USDPairs', 'USDJPY')]\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Order Id | \n",
" Column | \n",
" Signal Index | \n",
" Creation Index | \n",
" Fill Index | \n",
" Side | \n",
" Type | \n",
" Stop Type | \n",
" Size | \n",
" Price | \n",
" Fees | \n",
" PnL | \n",
" Return | \n",
" Direction | \n",
" Status | \n",
" Entry Trade Id | \n",
" Exit Trade Id | \n",
" Position Id | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" (NonUSDPairs, EURGBP) | \n",
" 2019-01-22 11:45:00+00:00 | \n",
" 2019-01-22 11:45:00+00:00 | \n",
" 2019-01-22 11:45:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 1.139290 | \n",
" 0.0 | \n",
" -1946.875030 | \n",
" -0.017088 | \n",
" Long | \n",
" Closed | \n",
" 0 | \n",
" -1 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 1 | \n",
" (NonUSDPairs, EURGBP) | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 1.119821 | \n",
" 0.0 | \n",
" -1946.875030 | \n",
" -0.017088 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" (NonUSDPairs, EURGBP) | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" 2019-01-28 21:00:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 1.119821 | \n",
" 0.0 | \n",
" 71.304000 | \n",
" 0.000637 | \n",
" Short | \n",
" Closed | \n",
" 1 | \n",
" -1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 4 | \n",
" 2 | \n",
" (NonUSDPairs, EURGBP) | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 1.119108 | \n",
" 0.0 | \n",
" 71.304000 | \n",
" 0.000637 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
" | 3 | \n",
" 2 | \n",
" (NonUSDPairs, EURGBP) | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" 2019-01-28 21:15:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 1.119108 | \n",
" 0.0 | \n",
" 102.818190 | \n",
" 0.000919 | \n",
" Long | \n",
" Closed | \n",
" 2 | \n",
" -1 | \n",
" 2 | \n",
"
\n",
" \n",
" | ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" | 7652 | \n",
" 497 | \n",
" (USDPairs, USDJPY) | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" 2022-01-09 08:15:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008489 | \n",
" 0.0 | \n",
" -1.794160 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" 497 | \n",
" -1 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7655 | \n",
" 498 | \n",
" (USDPairs, USDJPY) | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" -1.794160 | \n",
" -0.002114 | \n",
" Long | \n",
" Closed | \n",
" -1 | \n",
" 497 | \n",
" 497 | \n",
"
\n",
" \n",
" | 7654 | \n",
" 498 | \n",
" (USDPairs, USDJPY) | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" 2022-01-09 15:45:00+00:00 | \n",
" Sell | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008471 | \n",
" 0.0 | \n",
" 1.003425 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" 498 | \n",
" -1 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7657 | \n",
" 499 | \n",
" (USDPairs, USDJPY) | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 1.003425 | \n",
" 0.001185 | \n",
" Short | \n",
" Closed | \n",
" -1 | \n",
" 498 | \n",
" 498 | \n",
"
\n",
" \n",
" | 7656 | \n",
" 499 | \n",
" (USDPairs, USDJPY) | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" 2022-01-09 16:00:00+00:00 | \n",
" Buy | \n",
" Market | \n",
" None | \n",
" 100000.0 | \n",
" 0.008461 | \n",
" 0.0 | \n",
" 8.832179 | \n",
" 0.010439 | \n",
" Long | \n",
" Open | \n",
" 499 | \n",
" -1 | \n",
" 499 | \n",
"
\n",
" \n",
"
\n",
"
7658 rows × 18 columns
\n",
"
"
],
"text/plain": [
" Order Id Column Signal Index \\\n",
"0 0 (NonUSDPairs, EURGBP) 2019-01-22 11:45:00+00:00 \n",
"2 1 (NonUSDPairs, EURGBP) 2019-01-28 21:00:00+00:00 \n",
"1 1 (NonUSDPairs, EURGBP) 2019-01-28 21:00:00+00:00 \n",
"4 2 (NonUSDPairs, EURGBP) 2019-01-28 21:15:00+00:00 \n",
"3 2 (NonUSDPairs, EURGBP) 2019-01-28 21:15:00+00:00 \n",
"... ... ... ... \n",
"7652 497 (USDPairs, USDJPY) 2022-01-09 08:15:00+00:00 \n",
"7655 498 (USDPairs, USDJPY) 2022-01-09 15:45:00+00:00 \n",
"7654 498 (USDPairs, USDJPY) 2022-01-09 15:45:00+00:00 \n",
"7657 499 (USDPairs, USDJPY) 2022-01-09 16:00:00+00:00 \n",
"7656 499 (USDPairs, USDJPY) 2022-01-09 16:00:00+00:00 \n",
"\n",
" Creation Index Fill Index Side Type \\\n",
"0 2019-01-22 11:45:00+00:00 2019-01-22 11:45:00+00:00 Buy Market \n",
"2 2019-01-28 21:00:00+00:00 2019-01-28 21:00:00+00:00 Sell Market \n",
"1 2019-01-28 21:00:00+00:00 2019-01-28 21:00:00+00:00 Sell Market \n",
"4 2019-01-28 21:15:00+00:00 2019-01-28 21:15:00+00:00 Buy Market \n",
"3 2019-01-28 21:15:00+00:00 2019-01-28 21:15:00+00:00 Buy Market \n",
"... ... ... ... ... \n",
"7652 2022-01-09 08:15:00+00:00 2022-01-09 08:15:00+00:00 Buy Market \n",
"7655 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 Sell Market \n",
"7654 2022-01-09 15:45:00+00:00 2022-01-09 15:45:00+00:00 Sell Market \n",
"7657 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 Buy Market \n",
"7656 2022-01-09 16:00:00+00:00 2022-01-09 16:00:00+00:00 Buy Market \n",
"\n",
" Stop Type Size Price Fees PnL Return Direction \\\n",
"0 None 100000.0 1.139290 0.0 -1946.875030 -0.017088 Long \n",
"2 None 100000.0 1.119821 0.0 -1946.875030 -0.017088 Long \n",
"1 None 100000.0 1.119821 0.0 71.304000 0.000637 Short \n",
"4 None 100000.0 1.119108 0.0 71.304000 0.000637 Short \n",
"3 None 100000.0 1.119108 0.0 102.818190 0.000919 Long \n",
"... ... ... ... ... ... ... ... \n",
"7652 None 100000.0 0.008489 0.0 -1.794160 -0.002114 Long \n",
"7655 None 100000.0 0.008471 0.0 -1.794160 -0.002114 Long \n",
"7654 None 100000.0 0.008471 0.0 1.003425 0.001185 Short \n",
"7657 None 100000.0 0.008461 0.0 1.003425 0.001185 Short \n",
"7656 None 100000.0 0.008461 0.0 8.832179 0.010439 Long \n",
"\n",
" Status Entry Trade Id Exit Trade Id Position Id \n",
"0 Closed 0 -1 0 \n",
"2 Closed -1 0 0 \n",
"1 Closed 1 -1 1 \n",
"4 Closed -1 1 1 \n",
"3 Closed 2 -1 2 \n",
"... ... ... ... ... \n",
"7652 Closed 497 -1 497 \n",
"7655 Closed -1 497 497 \n",
"7654 Closed 498 -1 498 \n",
"7657 Closed -1 498 498 \n",
"7656 Open 499 -1 499 \n",
"\n",
"[7658 rows x 18 columns]"
]
},
"execution_count": 138,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"## View Trading History of pf.simulation \n",
"pf_trade_history = pf.trade_history\n",
"print(\"Unique Symbols:\", list(pf_trade_history['Column'].unique()) )\n",
"pf_trade_history"
]
},
{
"cell_type": "code",
"execution_count": 139,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Metrics | \n",
" USDPairs | \n",
" NonUSDPairs | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" Start | \n",
" 2019-01-01 22:00:00+00:00 | \n",
" 2019-01-01 22:00:00+00:00 | \n",
"
\n",
" \n",
" | 1 | \n",
" End | \n",
" 2023-01-16 06:45:00+00:00 | \n",
" 2023-01-16 06:45:00+00:00 | \n",
"
\n",
" \n",
" | 2 | \n",
" Period | \n",
" 1475 days 09:00:00 | \n",
" 1475 days 09:00:00 | \n",
"
\n",
" \n",
" | 3 | \n",
" Start Value | \n",
" 401135.388932 | \n",
" 382831.001776 | \n",
"
\n",
" \n",
" | 4 | \n",
" Min Value | \n",
" 385507.804066 | \n",
" 366381.544007 | \n",
"
\n",
" \n",
" | 5 | \n",
" Max Value | \n",
" 416965.770321 | \n",
" 401539.384864 | \n",
"
\n",
" \n",
" | 6 | \n",
" End Value | \n",
" 398793.379763 | \n",
" 382654.001151 | \n",
"
\n",
" \n",
" | 7 | \n",
" Total Return [%] | \n",
" -0.583845 | \n",
" -0.046235 | \n",
"
\n",
" \n",
" | 8 | \n",
" Benchmark Return [%] | \n",
" -2.182048 | \n",
" 1.650999 | \n",
"
\n",
" \n",
" | 9 | \n",
" Total Time Exposure [%] | \n",
" 99.883504 | \n",
" 98.605581 | \n",
"
\n",
" \n",
" | 10 | \n",
" Max Gross Exposure [%] | \n",
" 100.0 | \n",
" 100.0 | \n",
"
\n",
" \n",
" | 11 | \n",
" Max Drawdown [%] | \n",
" 6.431557 | \n",
" 7.693616 | \n",
"
\n",
" \n",
" | 12 | \n",
" Max Drawdown Duration | \n",
" 604 days 16:15:00 | \n",
" 740 days 10:15:00 | \n",
"
\n",
" \n",
" | 13 | \n",
" Total Orders | \n",
" 3078 | \n",
" 755 | \n",
"
\n",
" \n",
" | 14 | \n",
" Total Fees Paid | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 15 | \n",
" Total Trades | \n",
" 3078 | \n",
" 755 | \n",
"
\n",
" \n",
" | 16 | \n",
" Win Rate [%] | \n",
" 62.967784 | \n",
" 63.164894 | \n",
"
\n",
" \n",
" | 17 | \n",
" Best Trade [%] | \n",
" 3.276834 | \n",
" 4.06637 | \n",
"
\n",
" \n",
" | 18 | \n",
" Worst Trade [%] | \n",
" -7.984396 | \n",
" -6.862178 | \n",
"
\n",
" \n",
" | 19 | \n",
" Avg Winning Trade [%] | \n",
" 0.163322 | \n",
" 0.351527 | \n",
"
\n",
" \n",
" | 20 | \n",
" Avg Losing Trade [%] | \n",
" -0.274403 | \n",
" -0.594505 | \n",
"
\n",
" \n",
" | 21 | \n",
" Avg Winning Trade Duration | \n",
" 1 days 05:41:36 | \n",
" 2 days 14:17:56 | \n",
"
\n",
" \n",
" | 22 | \n",
" Avg Losing Trade Duration | \n",
" 3 days 06:57:16 | \n",
" 6 days 12:16:19 | \n",
"
\n",
" \n",
" | 23 | \n",
" Profit Factor | \n",
" 0.989343 | \n",
" 1.029618 | \n",
"
\n",
" \n",
" | 24 | \n",
" Expectancy | \n",
" -0.886256 | \n",
" 7.987277 | \n",
"
\n",
" \n",
" | 25 | \n",
" Sharpe Ratio | \n",
" -0.034462 | \n",
" 0.020401 | \n",
"
\n",
" \n",
" | 26 | \n",
" Calmar Ratio | \n",
" -0.022508 | \n",
" -0.001487 | \n",
"
\n",
" \n",
" | 27 | \n",
" Omega Ratio | \n",
" 0.998725 | \n",
" 1.001834 | \n",
"
\n",
" \n",
" | 28 | \n",
" Sortino Ratio | \n",
" -0.049602 | \n",
" 0.028554 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Metrics USDPairs \\\n",
"0 Start 2019-01-01 22:00:00+00:00 \n",
"1 End 2023-01-16 06:45:00+00:00 \n",
"2 Period 1475 days 09:00:00 \n",
"3 Start Value 401135.388932 \n",
"4 Min Value 385507.804066 \n",
"5 Max Value 416965.770321 \n",
"6 End Value 398793.379763 \n",
"7 Total Return [%] -0.583845 \n",
"8 Benchmark Return [%] -2.182048 \n",
"9 Total Time Exposure [%] 99.883504 \n",
"10 Max Gross Exposure [%] 100.0 \n",
"11 Max Drawdown [%] 6.431557 \n",
"12 Max Drawdown Duration 604 days 16:15:00 \n",
"13 Total Orders 3078 \n",
"14 Total Fees Paid 0.0 \n",
"15 Total Trades 3078 \n",
"16 Win Rate [%] 62.967784 \n",
"17 Best Trade [%] 3.276834 \n",
"18 Worst Trade [%] -7.984396 \n",
"19 Avg Winning Trade [%] 0.163322 \n",
"20 Avg Losing Trade [%] -0.274403 \n",
"21 Avg Winning Trade Duration 1 days 05:41:36 \n",
"22 Avg Losing Trade Duration 3 days 06:57:16 \n",
"23 Profit Factor 0.989343 \n",
"24 Expectancy -0.886256 \n",
"25 Sharpe Ratio -0.034462 \n",
"26 Calmar Ratio -0.022508 \n",
"27 Omega Ratio 0.998725 \n",
"28 Sortino Ratio -0.049602 \n",
"\n",
" NonUSDPairs \n",
"0 2019-01-01 22:00:00+00:00 \n",
"1 2023-01-16 06:45:00+00:00 \n",
"2 1475 days 09:00:00 \n",
"3 382831.001776 \n",
"4 366381.544007 \n",
"5 401539.384864 \n",
"6 382654.001151 \n",
"7 -0.046235 \n",
"8 1.650999 \n",
"9 98.605581 \n",
"10 100.0 \n",
"11 7.693616 \n",
"12 740 days 10:15:00 \n",
"13 755 \n",
"14 0.0 \n",
"15 755 \n",
"16 63.164894 \n",
"17 4.06637 \n",
"18 -6.862178 \n",
"19 0.351527 \n",
"20 -0.594505 \n",
"21 2 days 14:17:56 \n",
"22 6 days 12:16:19 \n",
"23 1.029618 \n",
"24 7.987277 \n",
"25 0.020401 \n",
"26 -0.001487 \n",
"27 1.001834 \n",
"28 0.028554 "
]
},
"execution_count": 139,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# For pf_from_signals_v3 case\n",
"# stats_df = pd.concat([pf.stats()] + [pf[grp].stats() for grp in unique_grp_types], axis = 1) \n",
"stats_df = pd.concat([pf[grp].stats() for grp in unique_grp_types], axis = 1) \n",
"stats_df.loc['Avg Winning Trade Duration'] = [x.floor('s') for x in stats_df.iloc[21]]\n",
"stats_df.loc['Avg Losing Trade Duration'] = [x.floor('s') for x in stats_df.iloc[22]]\n",
"stats_df = stats_df.reset_index() \n",
"stats_df.rename(inplace = True, columns = {'agg_stats':'Agg_Stats', 'index' : 'Metrics' }) \n",
"stats_df"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "vbt",
"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.10.6 (main, Oct 24 2022, 11:04:07) [Clang 12.0.0 ]"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "553d3b352623cb609a2efe4df91242fdc89d5ebcee56d9279e2aa2c11b529c13"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}