1
Fork 0
crypto_bot_training/Session_04/example_strat.ipynb
2025-06-21 15:58:39 +02:00

216 lines
8 KiB
Text

{
"cells": [
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"from backtesting import Strategy\n",
"from backtesting import Backtest\n",
"import pandas as pd\n",
"import numpy as np\n",
"import talib\n",
"from talib import MA_Type\n",
"from datetime import timedelta, datetime\n",
"import backtesting.lib as bt_lib\n",
"import math\n",
"import warnings\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"import pandas as pd\n",
"data = pd.read_csv(f'/Users/alex/Dev/MarketAlgorithms/test/data/DOGEUSDT_1.csv', parse_dates=[0], index_col=0)\n",
"data = data.rename(columns={'timestamp': 'Timestamp',\n",
" 'open': 'Open',\n",
" 'high': 'High',\n",
" 'low': 'Low',\n",
" 'close': 'Close',\n",
" 'volume': 'Volume',\n",
" 'turnover': 'Turnover'})\n",
"data"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"class BBDca(Strategy):\n",
" bb_len = 201\n",
" bb_mul = 1.8\n",
" bo_amount = 50\n",
" so_amount = 270\n",
" tp = 0.005\n",
" so_price_deviation = 0.02\n",
" so_volume_scale = 1.6\n",
" so_step_scale = 1.6\n",
" so_count = 5\n",
" \n",
" max_days_in_trade = 30000\n",
" so_enabled = False\n",
" so_order_policy = \"place_at_start\" #\"trigger_level\"|\"strategy\"\n",
" LONG = 'long'\n",
" SHORT = 'short'\n",
" \n",
" def safety_order_deviation(self, index):\n",
" return self.so_price_deviation * math.pow(self.so_step_scale, index - 1)\n",
" \n",
" def safety_order_price(self, index, last_safety_order_price, side):\n",
" qty = self.safety_order_qty(index)\n",
" if side == 'long':\n",
" return last_safety_order_price * (1 - self.safety_order_deviation(index)), qty\n",
" else:\n",
" return last_safety_order_price * (1 + self.safety_order_deviation(index)), qty\n",
" \n",
" def safety_order_qty(self, index):\n",
" return self.so_amount * math.pow(self.so_volume_scale, index - 1)\n",
" \n",
" def place_safety_order(self, bo_level, side):\n",
" tot_order_size = self.bo_amount\n",
" last_so_level = bo_level\n",
" for i in range(1, self.so_count + 1):\n",
" so_level, amount = self.safety_order_price(i, last_so_level, side)\n",
" average_price = (tot_order_size * last_so_level + amount * so_level) / (amount + tot_order_size)\n",
" tot_order_size += amount\n",
" last_so_level = so_level\n",
" if side == self.LONG:\n",
" so_tp_level = average_price * (1 + self.tp)\n",
" self.buy(tp=so_tp_level, limit=so_level, size=round(amount / so_level))\n",
" else:\n",
" so_tp_level = average_price * (1 - self.tp)\n",
" self.sell(tp=so_tp_level, limit=so_level, size=round(amount / so_level))\n",
" \n",
" def init(self):\n",
" super().init()\n",
" self.bb_up, self.bb_mid, self.bb_low = self.I(talib.BBANDS, self.data.Close, self.bb_len, self.bb_mul, self.bb_mul, matype=MA_Type.EMA)\n",
" self.tp_level = self.I(lambda: np.repeat(np.nan, len(self.data)), name='TP level', overlay=True)\n",
" self.trade_abort = self.I(lambda: np.repeat(np.nan, len(self.data)), name='TA', scatter=True)\n",
" self.tp_level.flags.writeable = True\n",
" self.trade_abort.flags.writeable = True\n",
" \n",
" def next(self):\n",
" super().next()\n",
" \n",
" if self.position:\n",
" if self.so_order_policy == \"place_at_start\":\n",
" if self.trades[-1].entry_bar == len(self.data) - 1:\n",
" # adjust tp of previous trade\n",
" #if len(self.trades) == 2:\n",
" new_tp = self.trades[-1].tp\n",
" for ti in range(0, len(self.trades) - 1):\n",
" self.trades[ti].tp = new_tp\n",
" # update tp level line on chart\n",
" self.tp_level[-1] = self.trades[0].tp \n",
" \n",
" else:\n",
" self.so_enabled = False\n",
" for order in self.orders:\n",
" order.cancel()\n",
"\n",
" # handle new trade\n",
" long_condition = self.data.Close[-1] >= self.bb_low[-1] and self.data.Close[-2] < self.bb_low[-1]\n",
" short_condition = self.data.Close[-1] <= self.bb_up[-1] and self.data.Close[-2] > self.bb_up[-1]\n",
"\n",
" be = self.data.Close[-1]\n",
" if long_condition and not self.position:\n",
" tp_level = self.data.Close[-1] * (1 + self.tp)\n",
" self.buy(tp=tp_level, size=round(self.bo_amount / self.data.Close[-1]))\n",
" if self.so_order_policy == \"place_at_start\":\n",
" self.place_safety_order(be, \"long\")\n",
" elif short_condition and not self.position:\n",
" tp_level = self.data.Close[-1] * (1 - self.tp)\n",
" self.sell(tp=tp_level, size=round(self.bo_amount / self.data.Close[-1]))\n",
" if self.so_order_policy == \"place_at_start\":\n",
" self.place_safety_order(be, \"short\")\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bt = Backtest(data, BBDca, cash=600, margin=0.2, commission=0.0003)\n",
"stats = bt.run()\n",
"print(stats)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bt.plot(show_legend=False, resample=False, plot_pl=True, relative_equity=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bt = Backtest(data, BBDca, cash=600, margin=0.2, commission=0.0003)\n",
"stats, heatmap = bt.optimize(\n",
" bb_len = range(190,210,1),\n",
" bb_mul = list(np.arange(1.8, 3.0, 0.1)),\n",
" bo_amount = range(50,100,10),\n",
" so_amount = range(100,300,10),\n",
" tp = list(np.arange(0.005, 0.01, 0.001)),\n",
" so_price_deviation = list(np.arange(0.02, 0.06, 0.01)),\n",
" so_volume_scale = list(np.arange(1.0, 2.0, 0.1)),\n",
" so_step_scale = list(np.arange(1.0, 2.0, 0.1)),\n",
" so_count = range(1,5,1),\n",
" constraint= lambda x: x.bo_amount < x.so_amount / 2, #and x.bo_amount + x.so_amount * x.count ,\n",
" maximize='Equity Final [$]',\n",
" method='grid',\n",
" max_tries=50,\n",
" random_state=0,\n",
" return_heatmap=True)\n",
"\n",
"print(stats)\n",
"print(heatmap.sort_values(ascending=False))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"bt.plot(show_legend=False, resample=False, plot_pl=True, relative_equity=False)"
]
}
],
"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.13.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}