{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# PnL Ratio - long short\n", "\n", "Market sentiment is high when everyone is profit on paper, and vice versa. Can we use this as an indicator to trade?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comment\n", "\n", "While the long only follow version of this strategy performs great, the long-short version of it is not as good. Mainly due to the fact that short-selling adds extra risk to a position. Though you may gain on a bear market, but usually the short position will give away most return in the following bull market. A better modification is to increate the range of the weight, allowing close to full position when the rank is high, such that you still gain full access to a long bull market." ] }, { "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 = 'SPY'\n", "START = '2000-01-01'\n", "WINDOW = 504\n", "INTERVAL = 5" ] }, { "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", "\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 pnl_ratio(win: Series) -> float:\n", " pnlr = win.rank(pct=True)\n", " return pnlr[-1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strategy" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def ST_LongShortPnL(min, max):\n", "\n", " offset = max - min\n", "\n", " class ST(Strategy):\n", " name = f'ST_LongShortPnl_range[{min},{max}]'\n", "\n", " @interval(INTERVAL)\n", " def step(self, b: Broker):\n", " win = b.market.get_close_window(SYMBOL)\n", " pnlr = pnl_ratio(win)\n", " weight = min + offset * pnlr\n", " b.portfolio.trade_target_weight(SYMBOL, weight)\n", " self.journal.mark(weight, 'weight')\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_LongShortPnL(0, 1),\n", " ST_LongShortPnL(-0.2, 1),\n", " ST_LongShortPnL(-0.2, 1.5),\n", " ST_LongShortPnL(-0.5, 1.5),\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", "316.2% | \n", "6.43% | \n", "8.25% | \n", "19.90% | \n", "-55.19% | \n", "517 days 00:00 | \n", "0.415 | \n", "0.149 | \n", "
| BM_KeepAtHalf | \n", "125.8% | \n", "3.63% | \n", "4.07% | \n", "9.90% | \n", "-31.49% | \n", "517 days 00:00 | \n", "0.411 | \n", "0.129 | \n", "
| ST_LongShortPnl_range[0,1] | \n", "245.7% | \n", "5.57% | \n", "6.16% | \n", "11.85% | \n", "-23.52% | \n", "22 days 00:00 | \n", "0.520 | \n", "0.262 | \n", "
| ST_LongShortPnl_range[-0.2,1] | \n", "218.5% | \n", "5.20% | \n", "5.75% | \n", "11.47% | \n", "-23.56% | \n", "62 days 00:00 | \n", "0.501 | \n", "0.244 | \n", "
| ST_LongShortPnl_range[-0.2,1.5] | \n", "436.4% | \n", "7.62% | \n", "8.90% | \n", "17.37% | \n", "-33.45% | \n", "22 days 00:00 | \n", "0.512 | \n", "0.266 | \n", "
| ST_LongShortPnl_range[-0.5,1.5] | \n", "367.0% | \n", "6.97% | \n", "8.29% | \n", "17.39% | \n", "-34.69% | \n", "62 days 00:00 | \n", "0.477 | \n", "0.239 | \n", "