{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from v2realbot.tools.loadbatch import load_batch\n", "from v2realbot.utils.utils import zoneNY\n", "import pandas as pd\n", "import numpy as np\n", "import vectorbtpro as vbt\n", "from itables import init_notebook_mode, show\n", "import datetime\n", "from itertools import product\n", "\n", "init_notebook_mode(all_interactive=True)\n", "\n", "vbt.settings.set_theme(\"dark\")\n", "vbt.settings['plotting']['layout']['width'] = 1280\n", "vbt.settings.plotting.auto_rangebreaks = True\n", "# Set the option to display with pagination\n", "pd.set_option('display.notebook_repr_html', True)\n", "pd.set_option('display.max_rows', 10) # Number of rows per page\n", "\n", "# Define the market open and close times\n", "market_open = datetime.time(9, 30)\n", "market_close = datetime.time(16, 0)\n", "entry_window_opens = 1\n", "entry_window_closes = 370\n", "\n", "forced_exit_start = 380\n", "forced_exit_end = 390\n", "\n", "res, df = load_batch(batch_id=\"0fb5043a\", #0fb5043a bde6d0be\n", " space_resolution_evenly=False,\n", " indicators_columns=[\"Rsi14\"],\n", " main_session_only=True,\n", " verbose = False)\n", "if res < 0:\n", " print(\"Error\" + str(res) + str(df))\n", "df = df[\"bars\"]\n", "\n", "#df\n", "\n", "basic_data = vbt.Data.from_data(vbt.symbol_dict({\"BAC\": df}), tz_convert=zoneNY)\n", "#m1_data = basic_data[['Open', 'High', 'Low', 'Close', 'Volume']]\n", "basic_data = basic_data.transform(lambda df: df.between_time('09:30', '16:00'))\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#parameters (primary y line, secondary y line, close)\n", "def plot_2y_close(priminds, secinds, close):\n", " fig = vbt.make_subplots(rows=1, cols=1, shared_xaxes=True, specs=[[{\"secondary_y\": True}]], vertical_spacing=0.02, subplot_titles=(\"MOM\", \"Price\" ))\n", " close.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False), trace_kwargs=dict(line=dict(color=\"blue\")))\n", " for ind in priminds:\n", " ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False))\n", " for ind in secinds:\n", " ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True))\n", " return fig\n", "\n", "# close = basic_data.xloc[\"09:30\":\"10:00\"].close" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#PIPELINE - FOR - LOOP\n", "\n", "#indicator parameters\n", "mom_timeperiod = list(range(2, 12))\n", "\n", "#uzavreni okna od 1 do 200\n", "entry_window_closes = list(range(2, 50, 3))\n", "#entry_window_closes = [3, 7, 15, 29, 45, 50, 70]\n", "#threshold entries parameters\n", "#long\n", "mom_th = np.round(np.arange(0.01, 0.5 + 0.02, 0.02),4).tolist()#-0.02\n", "# short mom_th = np.round(np.arange(-0.01, -0.3 - 0.02, -0.02),4).tolist()#-0.02\n", "roc_th = np.round(np.arange(-0.2, -0.8 - 0.05, -0.05),4).tolist()#-0.2\n", "#print(mom_th, roc_th)\n", "\n", "#portfolio simulation parameters\n", "sl_stop =np.round(np.arange(0.03/100, 0.7/100, 0.05/100),4).tolist()\n", "tp_stop = np.round(np.arange(0.03/100, 0.7/100, 0.05/100),4).tolist()\n", "\n", "combs = list(product(mom_timeperiod, mom_th, roc_th, sl_stop, tp_stop))\n", "\n", "@vbt.parameterized(merge_func = \"concat\", random_subset = 1000, show_progress=True) \n", "def test_strat(entry_window_closes=60,\n", " mom_timeperiod=2,\n", " mom_th=-0.04,\n", " #roc_th=-0.2,\n", " sl_stop=0.19/100,\n", " tp_stop=0.19/100):\n", " # mom_timeperiod=2\n", " # mom_th=-0.06\n", " # roc_th=-0.2\n", " # sl_stop=0.04/100\n", " # tp_stop=0.04/100\n", "\n", " momshort = vbt.indicator(\"talib:MOM\").run(basic_data.close, timeperiod=mom_timeperiod, short_name = \"slope_short\")\n", " rocp = vbt.indicator(\"talib:ROC\").run(basic_data.close, short_name = \"rocp\")\n", " #rate of change + momentum\n", "\n", " #momshort.plot rocp.real_crossed_below(roc_th) & \n", " short_signal = momshort.real_crossed_below(mom_th)\n", " long_signal = momshort.real_crossed_above(mom_th)\n", " # print(\"short signal\")\n", " # print(short_signal.value_counts())\n", "\n", " #forced_exit = pd.Series(False, index=close.index)\n", " forced_exit = basic_data.symbol_wrapper.fill(False)\n", " #entry_window_open = pd.Series(False, index=close.index)\n", " entry_window_open= basic_data.symbol_wrapper.fill(False)\n", "\n", " #print(entry_window_closes, \"entry window closes\")\n", " # Calculate the time difference in minutes from market open for each timestamp\n", " elapsed_min_from_open = (forced_exit.index.hour - market_open.hour) * 60 + (forced_exit.index.minute - market_open.minute)\n", "\n", " entry_window_open[(elapsed_min_from_open >= entry_window_opens) & (elapsed_min_from_open < entry_window_closes)] = True\n", "\n", " #print(entry_window_open.value_counts())\n", "\n", " forced_exit[(elapsed_min_from_open >= forced_exit_start) & (elapsed_min_from_open < forced_exit_end)] = True\n", " short_entries = (short_signal & entry_window_open)\n", " short_exits = forced_exit\n", " entries = (long_signal & entry_window_open)\n", " exits = forced_exit\n", " #long_entries.info()\n", " #number of trues and falses in long_entries\n", " # print(short_exits.value_counts())\n", " # print(short_entries.value_counts())\n", "\n", " #fig = plot_2y_close([],[momshort, rocp], close)\n", " #short_signal.vbt.signals.plot_as_entries(close, fig=fig, add_trace_kwargs=dict(secondary_y=False))\n", " #print(sl_stop)\n", " #tsl_th=sl_stop, \n", " #short_entries=short_entries, short_exits=short_exits,\n", " pf = vbt.Portfolio.from_signals(close=basic_data.close, entries=entries, exits=exits, tsl_stop=sl_stop, tp_stop = tp_stop, fees=0.0167/100, freq=\"1s\", price=\"nextopen\") #sl_stop=sl_stop, tp_stop = sl_stop,\n", " \n", " return pf.stats([\n", " 'total_return',\n", " 'max_dd', \n", " 'total_trades', \n", " 'win_rate', \n", " 'expectancy'\n", " ])\n", "\n", "pf_results = test_strat(vbt.Param(entry_window_closes),\n", " vbt.Param(mom_timeperiod),\n", " vbt.Param(mom_th),\n", " #vbt.Param(roc_th)\n", " vbt.Param(sl_stop),\n", " vbt.Param(tp_stop, condition=\"tp_stop > sl_stop\"))\n", "pf_results = pf_results.unstack(level=-1)\n", "pf_results.sort_values(by=[\"Total Return [%]\", \"Max Drawdown [%]\"], ascending=[False, True])\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#pf_results.load(\"10tiscomb.pickle\")\n", "#pf_results.info()\n", "\n", "vbt.save(pf_results, \"8tiscomb_tsl.pickle\")\n", "\n", "# pf_results = vbt.load(\"8tiscomb_tsl.pickle\")\n", "# pf_results\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# parallel_coordinates method¶\n", "\n", "# attach_px_methods..plot_func(\n", "# *args,\n", "# layout=None,\n", "# **kwargs\n", "# )\n", "\n", "# pf_results.vbt.px.parallel_coordinates() #ocdf\n", "\n", "res = pf_results.reset_index()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf_results" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "from sklearn.decomposition import PCA\n", "from sklearn.preprocessing import StandardScaler\n", "import matplotlib.pyplot as plt\n", "\n", "# Assuming pf_results is your DataFrame\n", "# Convert columns to numeric, assuming NaNs where conversion fails\n", "metrics = ['Total Return [%]', 'Max Drawdown [%]', 'Total Trades']\n", "for metric in metrics:\n", " pf_results[metric] = pd.to_numeric(pf_results[metric], errors='coerce')\n", "\n", "# Handle missing values, for example filling with the median\n", "pf_results['Max Drawdown [%]'].fillna(pf_results['Max Drawdown [%]'].median(), inplace=True)\n", "\n", "# Extract the metrics into a new DataFrame\n", "data_for_pca = pf_results[metrics]\n", "\n", "# Standardize the data before applying PCA\n", "scaler = StandardScaler()\n", "data_scaled = scaler.fit_transform(data_for_pca)\n", "\n", "# Apply PCA\n", "pca = PCA(n_components=2) # Adjust components as needed\n", "principal_components = pca.fit_transform(data_scaled)\n", "\n", "# Create a DataFrame with the principal components\n", "pca_results = pd.DataFrame(data=principal_components, columns=['PC1', 'PC2'])\n", "\n", "# Visualize the results\n", "plt.figure(figsize=(8,6))\n", "plt.scatter(pca_results['PC1'], pca_results['PC2'], alpha=0.5)\n", "plt.xlabel('Principal Component 1')\n", "plt.ylabel('Principal Component 2')\n", "plt.title('PCA of Strategy Optimization Results')\n", "plt.grid(True)\n", "plt.savefig(\"ddd.png\")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Check if there is any unnamed level and rename it\n", "if None in df.index.names:\n", " # Generate new names list replacing None with 'stat'\n", " new_names = ['stat' if name is None else name for name in df.index.names]\n", " df.index.set_names(new_names, inplace=True)\n", "\n", "rs= df\n", "\n", "rs.info()\n", "\n", "\n", "# # Now, 'stat' is the name of the previously unnamed level\n", "\n", "# # Filter for 'Total Return' assuming it is a correct identifier in the 'stat' level\n", "# total_return_series = df.xs('Total Return [%]', level='stat')\n", "\n", "# # Sort the Series to get the largest 'Total Return' values\n", "# sorted_series = total_return_series.sort_values(ascending=False)\n", "\n", "# # Print the sorted filtered data\n", "# sorted_series.head(20)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sorted_series.vbt.save()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#df.info()\n", "total_return_series = df.xs('Total Return [%]')\n", "sorted_series = total_return_series.sort_values(ascending=False)\n", "\n", "# Display the top N entries, e.g., top 5\n", "sorted_series.head(5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "comb_stats_df.nlargest(10, 'Total Return [%]')\n", "#stats_df.info()\n", "\n", "\n", "8\t-0.06\t-0.2\t0.0028\t0.0048\t4.156254\n", "4 -0.02 -0.25 0.0028 0.0048 0.84433\n", "3 -0.02 -0.25 0.0033 0.0023 Total Return [%] 0.846753\n", "#2\t-0.04\t-0.2\t0.0019\t0.0019\n", "# 2\t-0.04\t-0.2\t0.0019\t0.0019\t0.556919\t91\t60.43956\t0.00612\n", "# 2\t-0.04\t-0.25\t0.0019\t0.0019\t0.556919\t91\t60.43956\t0.00612\n", "# 2\t-0.04\t-0.3\t0.0019\t0.0019\t0.556919\t91\t60.43956\t0.00612\n", "# 2\t-0.04\t-0.35\t0.0019\t0.0019\t0.556919\t91\t60.43956\t0.00612\n", "# 2\t-0.04\t-0.4\t0.0019\t0.0019\t0.556919\t91\t60.43956\t0.00612\n", "# 2\t-0.04\t-0.2\t0.0019\t0.0017\t0.451338\t93\t63.44086\t0.004853\n", "# 2\t-0.04\t-0.25\t0.0019\t0.0017\t0.451338\t93\t63.44086\t0.004853\n", "# 2\t-0.04\t-0.3\t0.0019\t0.0017\t0.451338\t93\t63.44086\t0.004853\n", "# 2\t-0.04\t-0.35\t0.0019\t0.0017\t0.451338\t93\t63.44086\t0.004853\n", "# 2\t-0.04\t-0.4\t0.0019\t0.0017\t0.451338\t93\t63.44086\t0.004853" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf.plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "basic_data.symbols" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def apply_func(ts, entries, exits, fastw, sloww, minp=None):\n", "... fast_ma = vbt.nb.rolling_mean_nb(ts, fastw, minp=minp)\n", "... slow_ma = vbt.nb.rolling_mean_nb(ts, sloww, minp=minp)\n", "... entries[:] = vbt.nb.crossed_above_nb(fast_ma, slow_ma) \n", "... exits[:] = vbt.nb.crossed_above_nb(slow_ma, fast_ma)\n", "... return (fast_ma, slow_ma) \n", "\n", ">>> CrossSig = vbt.IF(\n", "... class_name=\"CrossSig\",\n", "... input_names=['ts'],\n", "... in_output_names=['entries', 'exits'],\n", "... param_names=['fastw', 'sloww'],\n", "... output_names=['fast_ma', 'slow_ma']\n", "... ).with_apply_func(\n", "... apply_func,\n", "... in_output_settings=dict(\n", "... entries=dict(dtype=np.bool_), #initialize output with bool\n", "... exits=dict(dtype=np.bool_)\n", "... )\n", "... )\n", ">>> cross_sig = CrossSig.run(ts2, 2, 4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#PIPELINE - parameters in one go\n", "\n", "\n", "#TOTO prepsat do FOR-LOOPu\n", "\n", "\n", "#indicator parameters\n", "mom_timeperiod = list(range(2, 6))\n", "\n", "#threshold entries parameters\n", "mom_th = np.round(np.arange(-0.02, -0.1 - 0.02, -0.02),4).tolist()#-0.02\n", "roc_th = np.round(np.arange(-0.2, -0.4 - 0.05, -0.05),4).tolist()#-0.2\n", "#print(mom_th, roc_th)\n", "#jejich product\n", "# mom_th_prod, roc_th_prod = zip(*product(mom_th, roc_th))\n", "\n", "# #convert threshold to vbt param\n", "# mom_th_index = vbt.Param(mom_th_prod, name='mom_th_th') \n", "# roc_th_index = vbt.Param(roc_th_prod, name='roc_th_th')\n", "\n", "mom_th = vbt.Param(mom_th, name='mom_th')\n", "roc_th = vbt.Param(roc_th, name='roc_th')\n", "\n", "#portfolio simulation parameters\n", "sl_stop = np.arange(0.03/100, 0.2/100, 0.02/100).tolist()\n", "# Using the round function\n", "sl_stop = [round(val, 4) for val in sl_stop]\n", "tp_stop = np.arange(0.03/100, 0.2/100, 0.02/100).tolist()\n", "# Using the round function\n", "tp_stop = [round(val, 4) for val in tp_stop]\n", "sl_stop = vbt.Param(sl_stop) #np.nan mean s no stoploss\n", "tp_stop = vbt.Param(tp_stop) #np.nan mean s no stoploss\n", "\n", "\n", "#def test_mom(window=14, mom_th=0.2, roc_th=0.2, sl_stop=0.03/100, tp_stop=0.03/100):\n", "#close = basic_data.xloc[\"09:30\":\"10:00\"].close\n", "momshort = vbt.indicator(\"talib:MOM\").run(basic_data.get(\"Close\"), timeperiod=mom_timeperiod, short_name = \"slope_short\")\n", "\n", "#ht_trendline = vbt.indicator(\"talib:HT_TRENDLINE\").run(close, short_name = \"httrendline\")\n", "rocp = vbt.indicator(\"talib:ROC\").run(basic_data.get(\"Close\"), short_name = \"rocp\")\n", "#rate of change + momentum\n", "\n", "rocp_signal = rocp.real_crossed_below(mom_th)\n", "mom_signal = momshort.real_crossed_below(roc_th)\n", "\n", "#mom_signal\n", "print(rocp_signal.info())\n", "print(mom_signal.info())\n", "#print(rocp.real)\n", "\n", "\n", "short_signal = (mom_signal.vbt & rocp_signal)\n", "\n", "# #short_signal = (rocp.real_crossed_below(roc_th_index) & momshort.real_crossed_below(mom_th_index))\n", "# forced_exit = m1_data.symbol_wrapper.fill(False)\n", "# entry_window_open= m1_data.symbol_wrapper.fill(False)\n", "\n", "\n", "# # Calculate the time difference in minutes from market open for each timestamp\n", "# elapsed_min_from_open = (forced_exit.index.hour - market_open.hour) * 60 + (forced_exit.index.minute - market_open.minute)\n", "\n", "# entry_window_open[(elapsed_min_from_open >= entry_window_opens) & (elapsed_min_from_open < entry_window_closes)] = True\n", "# forced_exit[(elapsed_min_from_open >= forced_exit_start) & (elapsed_min_from_open < forced_exit_end)] = True\n", "# short_entries = (short_signal & entry_window_open)\n", "# short_exits = forced_exit\n", "# #long_entries.info()\n", "# #number of trues and falses in long_entries\n", "# #short_exits.value_counts()\n", "# #short_entries.value_counts()\n", "\n", "\n", "# pf = vbt.Portfolio.from_signals(close=close, short_entries=short_entries, short_exits=short_exits, sl_stop=sl_stop, tp_stop = tp_stop, fees=0.0167/100, freq=\"1s\") #sl_stop=sl_stop, tp_stop = sl_stop,\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# filter dates" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#filter na dny\n", "dates_of_interest = pd.to_datetime(['2024-04-22']).tz_localize('US/Eastern')\n", "filtered_df = df.loc[df.index.normalize().isin(dates_of_interest)]\n", "\n", "df = filtered_df\n", "df.info()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import plotly.io as pio\n", "# pio.renderers.default = 'notebook'\n", "\n", "#naloadujeme do vbt symbol as column\n", "basic_data = vbt.Data.from_data({\"BAC\": df}, tz_convert=zoneNY)\n", "\n", "vbt.settings.plotting.auto_rangebreaks = True\n", "#basic_data.data[\"BAC\"].vbt.ohlcv.plot()\n", "\n", "#basic_data.data[\"BAC\"]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1_data = basic_data[['Open', 'High', 'Low', 'Close', 'Volume']]\n", "\n", "m1_data.data[\"BAC\"]\n", "#m5_data = m1_data.resample(\"5T\")\n", "\n", "#m5_data.data[\"BAC\"].head(10)\n", "\n", "# m15_data = m1_data.resample(\"15T\")\n", "\n", "# m15 = m15_data.data[\"BAC\"]\n", "\n", "# m15.vbt.ohlcv.plot()\n", "\n", "# m1_data.wrapper.index\n", "\n", "# m1_resampler = m1_data.wrapper.get_resampler(\"1T\")\n", "# m1_resampler.index_difference(reverse=True)\n", "\n", "\n", "# m5_resampler.prettify()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# MOM indicator" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbt.phelp(vbt.indicator(\"talib:ROCP\").run)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "vyuzití rychleho klesani na sekundove urovni behem open rush\n", "- MOM + ROC during open rush\n", "- short signal\n", "- pipeline kombinace thresholdu pro vstup mom_th, roc_th + hodnota sl_stop a tp_stop (pripadne trailing) - nalezeni optimalni kombinace atributu" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# fig = plot_2y_close([ht_trendline],[momshort, rocp], close)\n", "# short_signal.vbt.signals.plot_as_entries(close, fig=fig, add_trace_kwargs=dict(secondary_y=False)) \n", "\n", "#parameters (primary y line, secondary y line, close)\n", "def plot_2y_close(priminds, secinds, close):\n", " fig = vbt.make_subplots(rows=1, cols=1, shared_xaxes=True, specs=[[{\"secondary_y\": True}]], vertical_spacing=0.02, subplot_titles=(\"MOM\", \"Price\" ))\n", " close.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False), trace_kwargs=dict(line=dict(color=\"blue\")))\n", " for ind in priminds:\n", " ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False))\n", " for ind in secinds:\n", " ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True))\n", " return fig\n", "\n", "close = m1_data.xloc[\"09:30\":\"10:00\"].close\n", "momshort = vbt.indicator(\"talib:MOM\").run(close, timeperiod=3, short_name = \"slope_short\")\n", "ht_trendline = vbt.indicator(\"talib:HT_TRENDLINE\").run(close, short_name = \"httrendline\")\n", "rocp = vbt.indicator(\"talib:ROC\").run(close, short_name = \"rocp\")\n", "#rate of change + momentum\n", "short_signal = (rocp.real_crossed_below(-0.2) & momshort.real_crossed_below(-0.02))\n", "#indlong = vbt.indicator(\"talib:MOM\").run(close, timeperiod=10, short_name = \"slope_long\")\n", "fig = plot_2y_close([ht_trendline],[momshort, rocp], close)\n", "short_signal.vbt.signals.plot_as_entries(close, fig=fig, add_trace_kwargs=dict(secondary_y=False)) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "close = m1_data.close\n", "#vbt.phelp(vbt.OLS.run)\n", "\n", "#oer steepmnes of regression line\n", "#talib.LINEARREG_SLOPE(close, timeperiod=timeperiod)\n", "#a také ON BALANCE VOLUME - http://5.161.179.223:8000/static/js/vbt/api/indicators/custom/obv/index.html\n", "\n", "\n", "\n", "mom_ind = vbt.indicator(\"talib:MOM\") \n", "#vbt.phelp(mom_ind.run)\n", "\n", "mom = mom_ind.run(close, timeperiod=10)\n", "\n", "plot_2y_close(mom, close)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# defining ENTRY WINDOW and forced EXIT window" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#m1_data.data[\"BAC\"].info()\n", "import datetime\n", "# Define the market open and close times\n", "market_open = datetime.time(9, 30)\n", "market_close = datetime.time(16, 0)\n", "entry_window_opens = 2\n", "entry_window_closes = 30\n", "\n", "forced_exit_start = 380\n", "forced_exit_end = 390\n", "\n", "forced_exit = m1_data.symbol_wrapper.fill(False)\n", "entry_window_open= m1_data.symbol_wrapper.fill(False)\n", "\n", "# Calculate the time difference in minutes from market open for each timestamp\n", "elapsed_min_from_open = (forced_exit.index.hour - market_open.hour) * 60 + (forced_exit.index.minute - market_open.minute)\n", "\n", "entry_window_open[(elapsed_min_from_open >= entry_window_opens) & (elapsed_min_from_open < entry_window_closes)] = True\n", "forced_exit[(elapsed_min_from_open >= forced_exit_start) & (elapsed_min_from_open < forced_exit_end)] = True\n", "\n", "#entry_window_open.info()\n", "# forced_exit.tail(100)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "close = m1_data.close\n", "\n", "#rsi = vbt.RSI.run(close, window=14)\n", "\n", "short_entries = (short_signal & entry_window_open)\n", "short_exits = forced_exit\n", "#long_entries.info()\n", "#number of trues and falses in long_entries\n", "#short_exits.value_counts()\n", "short_entries.value_counts()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def plot_rsi(close, entries, exits):\n", " fig = vbt.make_subplots(rows=1, cols=1, shared_xaxes=True, specs=[[{\"secondary_y\": True}]], vertical_spacing=0.02, subplot_titles=(\"RSI\", \"Price\" ))\n", " close.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True))\n", " #rsi.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False))\n", " entries.vbt.signals.plot_as_entries(close, fig=fig, add_trace_kwargs=dict(secondary_y=False)) \n", " exits.vbt.signals.plot_as_exits(close, fig=fig, add_trace_kwargs=dict(secondary_y=False)) \n", " return fig\n", "\n", "plot_rsi(close, short_entries, short_exits)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbt.phelp(vbt.Portfolio.from_signals)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sl_stop = np.arange(0.03/100, 0.2/100, 0.02/100).tolist()\n", "# Using the round function\n", "sl_stop = [round(val, 4) for val in sl_stop]\n", "print(sl_stop)\n", "sl_stop = vbt.Param(sl_stop) #np.nan mean s no stoploss\n", "\n", "pf = vbt.Portfolio.from_signals(close=close, short_entries=short_entries, short_exits=short_exits, sl_stop=0.03/100, tp_stop = 0.03/100, fees=0.0167/100, freq=\"1s\") #sl_stop=sl_stop, tp_stop = sl_stop,\n", "\n", "#pf.stats()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#list of orders\n", "#pf.orders.records_readable\n", "#pf.orders.plots()\n", "#pf.stats()\n", "pf.stats()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf.plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf[(0.0015,0.0013)].plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf[0.03].plot_trade_signals()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# pristup k pf jako multi index" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#pf[0.03].plot()\n", "#pf.order_records\n", "pf[(0.03)].stats()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#zgrupovane statistiky\n", "stats_df = pf.stats([\n", " 'total_return',\n", " 'total_trades',\n", " 'win_rate',\n", " 'expectancy'\n", "], agg_func=None)\n", "stats_df\n", "\n", "\n", "stats_df.nlargest(10, 'Total Return [%]')\n", "#stats_df.info()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pf[(0.0011,0.0013000000000000002)].plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pandas.tseries.offsets import DateOffset\n", "\n", "temp_data = basic_data['2024-4-22']\n", "temp_data\n", "res1m = temp_data[[\"Open\", \"High\", \"Low\", \"Close\", \"Volume\"]]\n", "\n", "# Define a custom date offset that starts at 9:30 AM and spans 4 hours\n", "custom_offset = DateOffset(hours=4, minutes=30)\n", "\n", "# res1m = res1m.get().resample(\"4H\").agg({ \n", "# \"Open\": \"first\",\n", "# \"High\": \"max\",\n", "# \"Low\": \"min\",\n", "# \"Close\": \"last\",\n", "# \"Volume\": \"sum\"\n", "# })\n", "\n", "res4h = res1m.resample(\"1h\", resample_kwargs=dict(origin=\"start\"))\n", "\n", "res4h.data\n", "\n", "res15m = res1m.resample(\"15T\", resample_kwargs=dict(origin=\"start\"))\n", "\n", "res15m.data[\"BAC\"]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@vbt.njit\n", "def long_entry_place_func_nb(c, low, close, time_in_ns, rsi14, window_open, window_close):\n", " market_open_minutes = 570 # 9 hours * 60 minutes + 30 minutes\n", "\n", " for out_i in range(len(c.out)):\n", " i = c.from_i + out_i\n", "\n", " current_minutes = vbt.dt_nb.hour_nb(time_in_ns[i]) * 60 + vbt.dt_nb.minute_nb(time_in_ns[i])\n", " #print(\"current_minutes\", current_minutes)\n", " # Calculate elapsed minutes since market open at 9:30 AM\n", " elapsed_from_open = current_minutes - market_open_minutes\n", " elapsed_from_open = elapsed_from_open if elapsed_from_open >= 0 else 0\n", " #print( \"elapsed_from_open\", elapsed_from_open)\n", "\n", " #elapsed_from_open = elapsed_minutes_from_open_nb(time_in_ns) \n", " in_window = elapsed_from_open > window_open and elapsed_from_open < window_close\n", " #print(\"in_window\", in_window)\n", " # if in_window:\n", " # print(\"in window\")\n", "\n", " if in_window and rsi14[i] > 60: # and low[i, c.col] <= hit_price: # and hour == 9: # (4)!\n", " return out_i\n", " return -1\n", "\n", "@vbt.njit\n", "def long_exit_place_func_nb(c, high, close, time_index, tp, sl): # (5)!\n", " entry_i = c.from_i - c.wait\n", " entry_price = close[entry_i, c.col]\n", " hit_price = entry_price * (1 + tp)\n", " stop_price = entry_price * (1 - sl)\n", " for out_i in range(len(c.out)):\n", " i = c.from_i + out_i\n", " last_bar_of_day = vbt.dt_nb.day_changed_nb(time_index[i], time_index[i + 1])\n", "\n", " #print(next_day)\n", " if last_bar_of_day: #pokud je dalsi next day, tak zavirame posledni\n", " print(\"ted\",out_i)\n", " return out_i\n", " if close[i, c.col] >= hit_price or close[i, c.col] <= stop_price :\n", " return out_i\n", " return -1\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame(np.random.random(size=(5, 10)), columns=list('abcdefghij'))\n", "\n", "df" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df.sum()" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "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.11" } }, "nbformat": 4, "nbformat_minor": 2 }