{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Strategy Title\n", "\n", "Short description" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from btbox import *\n", "from pandas import Series" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "SYMBOL = 'SYMBOL'\n", "START = '2014-01-01'\n", "WINDOW = 500\n", "INTERVAL = 1" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "dfs = {SYMBOL: import_yahoo_csv(f'../../_data_/{SYMBOL}_bar1day.csv')}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Benchmark" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class BM_AllInAndForget(Strategy):\n", "\n", " def initial(self, b: Broker):\n", " b.portfolio.trade_target_weight(SYMBOL, 1)\n", "\n", "class BM_KeepAtHalf(Strategy):\n", "\n", " @interval(INTERVAL)\n", " def step(self, b: Broker):\n", " b.portfolio.trade_target_weight(SYMBOL, 0.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indicator" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def sma_cross(short: int, long: int, win: Series) -> bool | None:\n", " short_ma = win.iloc[-short - 1:].rolling(short).mean().dropna()\n", " long_ma = win.iloc[-long - 1:].rolling(long).mean().dropna()\n", " diff_ma = short_ma - long_ma\n", " if diff_ma[-1] > 0 and diff_ma[-2] < 0:\n", " return True\n", " if diff_ma[-1] < 0 and diff_ma[-2] > 0:\n", " return False\n", " return None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strategy" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def ST_SMACross(short: int, long: int):\n", "\n", " class ST(Strategy):\n", " name = f'ST_SMACross({short},{long})'\n", "\n", " @interval(1)\n", " def step(self, b: Broker):\n", " win = b.market.get_close_window(SYMBOL)\n", " ind = sma_cross(short, long, win)\n", " if ind == True:\n", " b.portfolio.trade_target_weight(SYMBOL, 1)\n", " if ind == False:\n", " b.portfolio.trade_target_weight(SYMBOL, 0)\n", "\n", " return ST" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Backtest" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "bt = create_backtest(\n", " [\n", " BM_AllInAndForget,\n", " BM_KeepAtHalf,\n", " ST_SMACross(10, 20),\n", " ST_SMACross(20, 50),\n", " ST_SMACross(50, 200),\n", " ],\n", " dfs,\n", " start=START,\n", " window=WINDOW,\n", ")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "results = bt.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dashboard" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
| \n", " | return | \n", "cagr | \n", "mu | \n", "sigma | \n", "mdd | \n", "duration | \n", "sharpe | \n", "calmar | \n", "
|---|---|---|---|---|---|---|---|---|
| BM_AllInAndForget | \n", "2,137.3% | \n", "41.92% | \n", "63.78% | \n", "75.38% | \n", "-83.43% | \n", "364 days 00:00 | \n", "0.846 | \n", "0.764 | \n", "
| BM_BuyHalfAndForget | \n", "1,068.6% | \n", "31.91% | \n", "46.24% | \n", "60.55% | \n", "-80.27% | \n", "364 days 00:00 | \n", "0.764 | \n", "0.576 | \n", "
| BM_KeepAtHalf | \n", "2,213.2% | \n", "42.46% | \n", "44.28% | \n", "42.09% | \n", "-52.79% | \n", "418 days 00:00 | \n", "1.052 | \n", "0.839 | \n", "
| ST_SMACross(10,20) | \n", "8,841.4% | \n", "65.90% | \n", "64.12% | \n", "51.82% | \n", "-71.42% | \n", "626 days 00:00 | \n", "1.237 | \n", "0.898 | \n", "
| ST_SMACross(20,50) | \n", "5,678.1% | \n", "57.93% | \n", "59.58% | \n", "52.61% | \n", "-74.14% | \n", "443 days 00:00 | \n", "1.132 | \n", "0.804 | \n", "
| ST_SMACross(50,200) | \n", "5,275.2% | \n", "56.65% | \n", "62.16% | \n", "58.28% | \n", "-71.29% | \n", "817 days 00:00 | \n", "1.067 | \n", "0.872 | \n", "