From 0cc10b8dc15572086111d6e2ab3cc5e3255e6adb Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 1 Feb 2016 18:07:34 +0100 Subject: [PATCH 01/13] ENH Add new round-trip analysis that rests on portfolio reconstruction and does not require closing of positions. --- pyfolio/examples/round_trip_example.ipynb | 509 ++++++++++++++++++++-- pyfolio/round_trips.py | 420 ++++++++++++------ pyfolio/tears.py | 30 +- 3 files changed, 757 insertions(+), 202 deletions(-) diff --git a/pyfolio/examples/round_trip_example.ipynb b/pyfolio/examples/round_trip_example.ipynb index 08ffd9be..b72a74cd 100644 --- a/pyfolio/examples/round_trip_example.ipynb +++ b/pyfolio/examples/round_trip_example.ipynb @@ -67,55 +67,381 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rts = pf.round_trips.extract_round_trips(transactions, portfolio_value=positions.sum(axis='columns'))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
close_dtdurationlongopen_dtpnlrt_returnssymbolreturns
02004-01-131 daysTrue2004-01-12-208.800000-0.036779AMD-0.002110
12004-01-161 daysTrue2004-01-1535.2600000.054088AMD0.000349
22004-01-208 daysTrue2004-01-121637.6590650.112071AMD0.016318
32004-01-211 daysFalse2004-01-20287.1198060.085155AMD0.002866
42004-01-222 daysFalse2004-01-20103.3499470.112198AMD0.001038
\n", + "
" + ], + "text/plain": [ + " close_dt duration long open_dt pnl rt_returns symbol \\\n", + "0 2004-01-13 1 days True 2004-01-12 -208.800000 -0.036779 AMD \n", + "1 2004-01-16 1 days True 2004-01-15 35.260000 0.054088 AMD \n", + "2 2004-01-20 8 days True 2004-01-12 1637.659065 0.112071 AMD \n", + "3 2004-01-21 1 days False 2004-01-20 287.119806 0.085155 AMD \n", + "4 2004-01-22 2 days False 2004-01-20 103.349947 0.112198 AMD \n", + "\n", + " returns \n", + "0 -0.002110 \n", + "1 0.000349 \n", + "2 0.016318 \n", + "3 0.002866 \n", + "4 0.001038 " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rts.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " duration pnl returns long\n", - "count 1430 1430.000000 1430.000000 1430\n", - "mean 9 days 16:40:56.154545 45.737238 0.003543 0.523077\n", - "std 22 days 02:16:41.165898 1616.537844 0.031288 0.499642\n", - "min 0 days 00:00:00 -30697.460000 -0.218045 False\n", - "25% 0 days 23:59:59 -5.773144 -0.011450 0\n", - "50% 2 days 23:59:59 0.871629 0.003885 1\n", - "75% 5 days 23:59:59 40.438366 0.018126 1\n", - "max 286 days 00:00:00 17835.869482 0.204385 True\n", - "Percent of round trips profitable = 57.2%\n", - "Mean return per winning round trip = 0.02181\n", - "Mean return per losing round trip = -0.02108\n", - "A decision is made every 1.053 days.\n", - "0.9495 trading decisions per day.\n", - "19.94 trading decisions per month.\n", - "\n", - "Profitability (PnL / PnL total) per name:\n", - "symbol\n", - "COST 0.398964\n", - "INTC 0.382659\n", - "CERN 0.323077\n", - "MMM 0.221479\n", - "GPS 0.049385\n", - "AMD -0.064091\n", - "DELL -0.311473\n", - "Name: pnl, dtype: float64\n", - "\n", - "Profitability (PnL / PnL total) per name:\n", - "symbol\n", - "Consumer Goods 0.398964\n", - "Healthcare 0.323077\n", - "Construction 0.221479\n", - "Technology 0.056480\n", - "Name: pnl, dtype: float64\n" - ] + "data": { + "text/html": [ + "\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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Summary statsAll round_tripsLong round_tripsShort round_trips
Total number of round_trips5819.004664.001155.00
Percent profitable0.550.550.52
Winning round_trips3180.002584.00596.00
Losing round_trips2613.002060.00553.00
Even round_trips26.0020.006.00
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PnL statsAll round_tripsLong round_tripsShort round_trips
Total profit$66840.00$63308.68$3531.32
Gross profit$402341.03$381761.36$20579.67
Gross loss$-335501.03$-318452.68$-17048.35
Profit factor$1.20$1.20$1.21
Avg. trade net profit$11.49$13.57$3.06
Avg. winning trade$126.52$147.74$34.53
Avg. losing trade$-128.40$-154.59$-30.83
Ratio Avg. Win:Avg. Loss$0.99$0.96$1.12
Largest winning trade$9977.28$9977.28$1623.24
Largest losing trade$-18557.39$-18557.39$-661.29
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Duration statsAll round_tripsLong round_tripsShort round_trips
Avg duration7 days 18:01:03.1036269 days 01:33:23.7735842 days 10:39:35.064935
Median duration3 days 00:00:004 days 00:00:002 days 00:00:00
Avg # round_trips per day20.4216.3696.25
Avg # round_trips per month428.77343.662021.25
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { + "text/html": [ + "\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Return statsAll round_tripsLong round_tripsShort round_trips
Avg returns all round_trips0.01%0.01%0.00%
Avg returns winning0.10%0.12%0.03%
Avg returns losing-0.11%-0.13%-0.03%
Median returns all round_trips0.00%0.00%0.00%
Median returns winning0.01%0.02%0.01%
Median returns losing-0.01%-0.01%-0.00%
Largest winning trade7.08%7.08%1.33%
Largest losing trade-16.77%-16.77%-0.72%
" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -123,9 +449,106 @@ }, { "data": { - "image/png": "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\nUJGRkVq5cqX69euntWvXau3ataW+xvLly7V27VotXrxY9913X5nru2bNGv38889auHCh5s2bp++/\n/17Tp0836t99913NmjVL3bp104oVKxQUFKRnn332sv02ZcoUvf/++xo3bpxWr16tadOm6aefftJz\nzz1X7nyS9Pe//12FhYVaunSpnnjiCb322mtatGiR1TRXu315eXnpnXfekbe3t3r06KGNGzfqzjvv\ntOqTiRMnqlevXvL09NTGjRvVvXt35ebmatiwYTpx4oTmzp2rN954Q8OHD9f27dv18ssvW7Xpgw8+\n0PHjxxUdHa3Q0FC9//77mjx5cqnraLFYFBoaqk2bNunpp5/WihUr5Ovrq4kTJ2rXrl1l9s358+c1\nbNgwHTlyxNiuN2/erKSkJKvp5syZo+XLl+uxxx7Tq6++qh49emjWrFmKj483plm/fr2mTZumgIAA\nrVixQiEhIVq5cqWio6NtXreoqEhjx45Vfn6+oqKiFBcXpzp16mjChAlWOziXbhdLly7V9OnT1alT\nJy1fvlwhISF65513NG7cOKtlf/PNN3rzzTcVHh6u5cuXy8HBQWFhYcrOzi6zHwDgWm3fvl0///yz\nFi1apNmzZ+v777+3GqPeffddjR07VrfddpuWLl2qyZMn69NPP9Xw4cPLDJGLFy/WihUr9Pjjj2v5\n8uWqU6eOoqOjbcbMqhiL58yZo7Zt2+rOO+/Uxo0b1bp161KnO3nypGJiYjR58mQtXrxYP//8s8aO\nHauFCxdqwoQJWrJkiX755Rc9//zzVn0XFhamVq1aacWKFRo3bpzeeeedKxrjS7Z55syZuvXWWxUX\nF6dRo0Zp06ZNevXVV8uc/0rGwSvZV3z44Yfl5OSkbdu2WS1/69at6tWrl2rVqqX58+fr888/17Rp\n0/TGG2+od+/eWrRokfElPlDdON0dki7uqF+4cME4deq3337Tnj179M477+iBBx5QnTp1jGlvvfVW\nhYeHG39HRkYqOztb7777rnFKbI8ePdS/f39FRUVZHeXr0aOH5s6dK0nq0qWLTp8+rVWrVmnUqFFK\nS0uTh4eHIiIiFBAQIOniKffJycl69913rdrr6Oio119/XQ0aNJAk1a9fX08//bQ+/fRT3XvvvZKu\n7DS1evXqGaen3XnnnWrcuLEkyd/fX9u2bdPAgQMlXbxuPS0tTY8++mi5y7vrrruMwbdVq1Z67733\n5OnpaXy7fPfdd2v79u06ePCg+vTpo//85z9q06aNYmJi5OrqKkm655579OWXX2r//v0aPXq0sWyL\nxaK1a9dq+fLlioyM1AMPPGD12iXXt27duoqLizMGzRMnTmjZsmXKzs6Wu7u7YmNj1bdvX6NtXbp0\nUU5Ojt5+++0y1y8/P195eXmKiIgwjhZ06NBB2dnZioyM1G+//aa6deuWOb+3t7eWL18uSerWrZty\ncnK0bt06hYaGGtey/Znty9/fX05OTqpbt67V6X7FfdKkSRPVrVtXTk5ORv0PP/ygJk2aaNGiRcb7\n3rFjRx08eNDm6EW9evW0atUqOTk5SZJq1qypOXPm6PDhwzan+H311Vf64osvFBsba2yLXbt2VVZW\nlhYtWqTevXuX2jfvvfeeUlNTtWPHDjVv3lzSxe3w0i9ijh8/rk2bNmnq1KkaOXKkJKlz587GmSWD\nBw+Wo6Ojli9frr59+xo7LJ07d1ZmZqa++uorm9dNT0/X8ePHFRoaqm7dukmS2rZtq+XLl1sdOSnu\ny3PnzmnlypUaOnSopk2bZiy/YcOGmjx5snbv3m1cv56VlaWtW7fKx8dHkuTm5qZhw4Zp37596tWr\nV6n9AADXqnHjxsYXg5KUnJysuLg45efny9HRUUuWLFGPHj20cOFCY55WrVrp8ccf17vvvquhQ4da\nLS8zM1Pr1q3TqFGjNGHCBEn/24f5/PPPraatirG4RYsWMpvNKioqKvcU99zcXM2bN09BQUGSLh7g\niI+P15tvvqlOnToZfRMZGanc3Fy5uLgoKipKPXv21IIFCyRdHL+8vb01ceJEJSYmql27dmW+Xkm9\nevXSlClTJF3c//nyyy/12WefadKkSaVOfyXj4JXsK9aqVUv33nuvtm3bpokTJ0q6eNDp4MGDxpcE\n+/btU5cuXYx9qaCgIJnN5nL3YYCqxJF0SLoYQu+66y61adNGbdq0Ubdu3RQREaEePXrYHMUu+Y1t\nQkKC2rdvb3XNqslkUr9+/fTDDz9YnTbet29fq3l79eqlc+fO6dixY/L29tabb74pf39/nTx5Ul9+\n+aXWrVunxMREFRYWWs3Xrl07I6BLFwOfk5NThd3V9LHHHtPXX3+tM2fOSLo4cLRt2/ayN2Tx9/c3\nfq9Tp44cHBxsBtBatWopKytLktS9e3etXbtWNWvW1NGjR7Vr1y7FxcUpIyNDf/zxh9V8O3fu1IIF\nC9S5c2c9/PDDl10HPz8/q2+1i9+f3NxcJScn69SpUzaXBJQM/iU5Oztr1apV6tOnj9LS0vT1119r\nw4YN+vTTTyXJ5n0qqV+/flZ/9+nTR3/88YcOHjxolF3L9nU17rrrLsXHx8vb21s///yzdu/erddf\nf13//e9/bdajR48eRkCXZATMAwcO2Cz33//+txwcHNS1a1f98ccfxk/Pnj2VnJxsc+nGpet52223\nGTsm0sUvNYp3QqSL/6cWi0U9evSwWXZWVpa+/fZbHT9+XBkZGTbv7cSJE7V+/Xqb1/X09NTtt9+u\nmTNnatq0adqxY4cuXLigqVOnlrq9f/PNNyosLNSDDz5oVX7//ffL0dFR+/btM8q8vLyMgC5Zb4MA\nUFn8/f2NgC7J+BzKzMzU8ePHlZ6eroceeshqHj8/PzVt2tTqS9riMfTgwYP6448/bL5kLblPU5rK\nGIuvxqX7JfXq1bMpq127tqSLffPf//5XaWlp6tWrl9UY07VrVzk6Opb6RW95Sgb6hg0bljtmX8k4\neKX7io899piSk5P17bffSrp4FL1BgwbGDWXvvvtubdy4UWPGjNH69euVkpKi8ePHc5NU2A2OpEPS\nxQ/siIgISRcHJWdnZ91yyy1ydna2mdbNzc3q78zMTKsP1GKenp6yWCxW1+6WvPlc/fr1JckIrdu2\nbdOSJUuUmpqq2rVr684775Srq6vNN9PF812qXr16FXYabb9+/TR//nxt375dTzzxhP75z38a3waX\nx2w225QVHyEvTVFRkZYsWaL169crNzdXjRo1Utu2beXs7GyzzocOHVJwcLA+++wz/fvf/7a6QVpp\nSr5u8Wn6RUVFysjIkPS/AbvYldwc8PPPP9f8+fN1/Phxmc1mtW7d2nity5294OXlZfV38ft46TXg\nf2b7KjnPlVq9erVeeeUV/f777/L09FSbNm3k5uZmEyJLbm/F/Vba9nbu3DlduHDBaqeimMlk0unT\np40j95f6/fffbd4P6eJ6Fl/3WHy9ZGk7hsXLLn6fS1tWaUwmk9544w3FxcVp586d2rp1q2rWrKn7\n7rtPc+fOVa1atWzaWdyuS9WoUUP16tUz/pclycXFxea1JJV5XwcAqAglx4RLx7/iz9HSxruSn2HF\nij/3Sh5lvfRgQVkqayy+Eg4ODlZfMBcr+dlcrLhvZs2aZfM4teIx5mqUfJ0aNWqUu59Q3jh46f0C\nrmRfsXPnzmrUqJHef/99+fn5GZcsFo9DM2bMkLe3t7Zt26Z58+ZJkgICAjRnzhxugge7QEiHpIvh\n8s8+B7lWrVrGEedLFX+Y16lTx3iGaMmbrBTPV79+fSUkJBin8YaEhBiBbtGiRVZHWktbjsVi0dmz\nZ684mFyOu7u7+vTpow8//FDe3t66cOGCzbfuFeG1117Tm2++qXnz5unee+81TvkeNGiQzbRDhw7V\nCy+8oEGDBmn27Nnavn17qV+iXInib/KLdxCKlfy7pBMnTmjixIm6//77tXLlSt1yyy2SLl4DXfKU\nv9KUvClP8c3+ynvfrmT7+jO2b9+uyMhITZ06VY888oixnEmTJunQoUNW05bc3tLT08tst4eHhzw8\nPGxuiihd3E6bNWtWanvq1q2r77//3qb83Llzxk6Fh4eHJCk+Pt5mx89iseiWW24x+qXke5menq6f\nfvpJ7du3t3kNLy8vzZ49W7Nnz9bhw4f10UcfaeXKlapfv77N84aLj7qcOXPG6k7GRUVFSk9P51RB\nAHat+DPs0pvNFjtz5kypX7AWf66lp6dbfe6Vd6O5K/Fnx+LKUjzGzJgxw2assFgslf75fiXj4JXu\nK5pMJg0cOFCbNm3SQw89pF9//VWPPPKIUe/k5KRx48Zp3LhxSk1NNc5kfP7557V9+/ZKXU/gSnC6\nO65ZUFCQDhw4YARx6eIO+0cffSQ/Pz85Ojoa5Xv27LGa96OPPpK3t7duvfVWJSUlyWKx6JlnnjE+\ndC9cuKCvvvrK5pvXxMREqyP0u3bt0h9//GFcY3U1Lj0l7lKPPfaYvv/+e7399tvq3bu3MXhVpAMH\nDsjX11cDBw40AnpaWpp++uknm6ONnp6eMplMmjt3rk6ePKlly5b96ddt1KiRbrnlFv3zn/+0Ki/5\nd0nff/+9CgoKNG7cOCOgSzIC+uWOpBefFl/s448/lqura6k7RcWuZvsqT8n3+cCBA6pbt65CQkKM\ngJ6Tk6MDBw7YrMdXX31l9X58+OGHki5ew15ae7OysuTg4KC77rrL+Dl48KDVdYkl3XPPPTpx4oTV\nXXYzMjKsdjo6dOgg6eIOy6XL/uWXX7R06VLl5eWpefPmqlOnjs3d5Dds2GBcS3mpb7/9Vp07d9Z3\n330n6eJd+MPDw3XHHXcoNTXVZvri6/8/+OADq/KPPvpIf/zxh9WOHc+1BWBvmjdvLk9PT+3YscOq\n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\nf/87Xn75ZXTo0AGZmZmyuszMTDg6OgIAHB0d1V7JVrF85WnwVcnKym9I8w1a+/bWjI8GjI9mjM//\n5OXlo6CwBCoUS2XWVmbILyjGg8ISZGfno7S0yd94qdd4/mjGAQwiIqKWq9GT9HXr1smuhGdmZmLC\nhAlYuXIl/Pz8sGnTJtk70wEgISEBXl5eAABPT0+sX78e6enpUuKekJAAKysruLq6NnbziYiIiIiI\niJpMoyfpla92m5iYSOW2traYOHEiRo8ejS1btmD48OE4duwYLl26hBUrVgAA+vbtC3d3d4SGhiI8\nPBxZWVmIjIxEYGAgjI0bvflERERERERETUYn8y8VCoX07+7du2Pr1q04fvw4Ro0ahZMnTyImJgZd\nunSRlomOjoadnR0mTJiAxYsXY+zYsZg1a5Yumk5ERERERETUaJr8UrSjo6Pa+839/f3h7+9f7Tp2\ndnaIjo5u7KYRERERERER6RSfZERERERERESkJ5ikExEREREREekJJulEREREREREeoJJOhERERER\nEZGeYJJOREREREREpCeYpBMRERERERHpCSbpRERERERERHqCSToRERERERGRnmCSTkRERERERKQn\nmKQTERERERER6Qkm6URERERERER6gkk6ERERERERkZ5gkk5ERERERESkJ5ikExEREREREekJJulE\nREREREREeoJJOhEREREREZGeYJJOREREREREpCeMdd0AIiIiIqKWTqVSoaAgv8q6/Pw8CJVo4hYR\nka4wSSciIiIi0rGCgnx8k5AKcwtLtbrc7AxYWLaGpXVrHbSMiJoap7sTERFRnaWmpsLFxUXtJyUl\nBQBw5swZjBw5En369EFAQABOnz6t4xYT6T9zC0tYWFqr/ZiZqyfuRGS4eCWdiIiI6uyXX35B27Zt\ncezYMVm5jY0NUlNTMWPGDMyaNQtDhw5FfHw8goODceTIEXTr1k1HLSYiImoeeCWdiIiI6uyXX35B\nt27d0K5dO9mPsbEx9u3bBw8PD0ybNg2dO3dGSEgIPDw8sG/fPl03m4iISO8xSSciIqI6u3HjBrp2\n7VplXVJSEnx8fGRlPj4+SEpKaoqmERERNWuc7k5ERER1duPGDZSWlmLcuHH4448/8PTTT2POnDlw\nc3NDRkYGHBwcZMvb29vjzp07OmotERFR88Er6URERFQnxcXFSEtLQ0FBARYsWIBt27bB3t4ekyZN\nws2bN1FcXAxTU1PZOkqlEqWlpTpqMRERUfPBK+lERERUJ2ZmZkhMTIRSqYSJiQkAoHfv3rhy5QoO\nHjwIU1NTtYS8tLQU5ubmumguERFRs8IknYiIiOrM0lL+SiiFQoFu3brhzp076NChAzIzM2X1mZmZ\ncHR0rHG77dtba7WdhobxqVlzjZFSqYKVZS4srczU6ooKlTAyMoF1pbq6lwOWlmZa2E7V5VAVw8RE\nBaVSpXYM1tbWMDLS/0m8zfX8aSqMT9Ngkk5ERER1cvnyZUyePBn79+9Hz549AQDl5eW4du0aXnzx\nRbRr1w6JiYmydRISEuDl5VXjtrOy8hulzYagfXtrxqcGzTlGeXn5KCgsgQrFanWFhaUwMiqHqXlx\ng8of1RU3eDvVlWdn38WRb9PRxradrLzoQSGG+HZD69Y21Ry9fmjO509TYHw00+YABpN0IiIiqhNX\nV1c88cQTCA8Px7Jly2Bubo6dO3fi3r17mDx5MrKzszF69Ghs2bIFw4cPx7Fjx3Dp0iWsWLFC100n\nokZmZm4BC0tebSVqCP2fc0JERER6pVWrVti5cyc6d+6M6dOn49VXX0VOTg4+/vhj2Nraonv37ti6\ndSuOHz+OUaNG4eTJk4iJiUGXLl103XQiIiK9xyvpREREVGcODg6IjIystt7f3x/+/v5N2CIiIiLD\nwCvpRERERERERHqCSToRERERERGRnmCSTkRERERERKQnmKQTERERERER6Qkm6URERERERER6gkk6\nERERERERkZ5gkk5ERERERESkJ5ikExEREREREekJJulEREREREREeoJJOhEREREREZGeaJIkPTs7\nG++++y4GDBgAb29vvPXWW7hx44ZUf+bMGYwcORJ9+vRBQEAATp8+LVs/JycHISEh8Pb2hp+fHyIj\nI1FeXt4UTSciIiIiIiJqMo2epKtUKsyaNQu3bt1CTEwMDh06BGtrawQGBuLevXtITU3FjBkzMHz4\ncMTFxWHQoEEIDg5GamqqtI23334bubm5iI2NxerVq3H48GFs3ry5sZtORERERERE1KQaPUm/fv06\nLl68iFWrVqF3797o2rUr1q5diwcPHuDkyZPYt28fPDw8MG3aNHTu3BkhISHw8PDAvn37AAAXLlxA\nSkoKIiIi4OzsDH9/fyxYsACxsbEoKytr7OYTERERERERNZlGT9I7duyIHTt2oHPnzlKZQqEAAOTl\n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\nlStXolevXhg+fHiVy5iZmQGA2kGXlpbC3NwcwKMPYGHf4gAAHSdJREFU5KrqgUdTnczMzKoMWsU2\nqttHWVmZtI/Goik+Rkb/u0tBoVCgV69eAIA1a9bg1VdfxcWLFw0+PkDtY1ReXo733nsPn376KVas\nWIHnnnsOAM+hmhh6fBqDmZkZVCoVVCqVLMaPx8xQVXcuVBx3VedCWVkZhBAaz4W6nG/64vDhwwgP\nD8eIESPwzjvvAGi58WnMvkyf/s8bojH7MkOIUWP2ZYYQn5q05H6pPmr6rG5J6tOXtSTdu3cHAGzc\nuBH+/v6Ii4vTanx0lqQbGxvL7neo7MiRIzA1NYWHhwcASK+h8fDwwPvvvw8/Pz8AQGZmpmwaWGZm\nJp5++mkAQIcOHWSPxK+ot7CwgLW1NRwdHZGTkwMhhHS/xcOHD5GbmwsHBwfY2NjA3NwcWVlZattw\ndHRsYAQ0qyk+qampyMzMlOIAQDrujIwM6b5EQ40PUHOMgEdXj0JCQnDmzBlERkZixIgRUl2HDh0A\nGG6MahMfTQw9Po2hImZZWVmy6U4ZGRnVXgkyFNWdCxX/j46OjmqvIalY3sHBQSvnmz6IiYlBVFQU\nJk6cKHutT0uNT1P0Zc1dU/RlzVlT9GWGrCX3S/VR02d1S1HfvszQ5eTk4Pz587LPYDMzMzz11FPI\nyMjQanz09sFx33zzDY4dO4b4+HjEx8djzpw5AB69T/m5556Dra0tOnXqhB9++EFap7CwEFeuXJE6\ndU9PT7Ub9RMSEuDp6SnVl5eXyx6qU/Ewq759+0KhUKBv376yfahUKiQmJqo9nKepfffdd5g7d65s\ntOann34CAHTr1g3t2rVr0fGpaEtISAgSEhKwY8cO2R8UAMaoBoxP3bm4uMDS0hIJCQlSWVpaGv78\n8094e3vrsGWNz9PTE4mJibKyhIQE2bly+/Zt2T2gCQkJsLS0hKurq1bON13buXMnoqKiEBoaqvbe\nXcanatroywydNvqylqylx6cl90v1UdNndUvQkL7M0P3xxx+YN2+e7LlJ+fn5+O2339CtWzftxqfe\nz6BvYnFxcWqvYDt48KBwd3cXX3zxhfj555/FtGnTxLBhw0RZWZkQQojs7Gzh5eUlli5dKlJTU8W+\nfftEz549xfnz56VtzJkzRwwbNkwkJyeLxMREMWTIENnrYE6fPi169uwpYmNjRWpqqli8eLF45pln\n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\n", + "text/html": [ + "\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", + " \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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Symbol statsAMDCERNCOSTDELLGPSINTCMMM
Avg returns all round_trips-0.35%1.80%2.46%-2.93%-0.06%1.91%1.04%
Avg returns winning16.52%12.64%8.21%8.66%7.86%8.46%8.13%
Avg returns losing-18.75%-12.22%-5.54%-15.03%-9.46%-5.70%-9.17%
Median returns all round_trips0.02%0.06%0.10%0.00%0.03%0.02%0.08%
Median returns winning1.79%1.68%1.23%1.25%1.18%0.96%1.12%
Median returns losing-1.28%-0.94%-0.71%-0.86%-0.79%-0.50%-0.64%
Largest winning trade708.48%605.28%228.45%270.27%195.77%248.91%254.67%
Largest losing trade-1477.84%-544.99%-415.15%-1676.90%-348.04%-511.02%-339.08%
" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -133,7 +556,7 @@ } ], "source": [ - "pf.tears.create_round_trip_tear_sheet(positions, transactions, sector_mappings=sect_map)" + "pf.round_trips.print_round_trip_stats(rts)" ] } ], diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index 3eb6b521..e831b1ca 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -13,168 +13,252 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division -from collections import defaultdict +from math import copysign +import warnings +from collections import deque, defaultdict, OrderedDict import pandas as pd import numpy as np - -def extract_round_trips(transactions): - """ - Group transactions into "round trips." A round trip is started when a new - long or short position is opened and is only completed when the number - of shares in that position returns to or crosses zero. - Computes pnl for each round trip. - - For example, the following transactions would constitute one round trip: - index amount price symbol - 2004-01-09 12:18:01 186 324.12 'AAPL' - 2004-01-09 15:12:53 -10 344.54 'AAPL' - 2004-01-13 14:41:23 24 320.21 'AAPL' - 2004-01-30 10:23:34 -200 340.43 'AAPL' +from .utils import print_table + +PNL_STATS = OrderedDict( + [('Total profit', lambda x: x.sum()), + ('Gross profit', lambda x: x[x > 0].sum()), + ('Gross loss', lambda x: x[x < 0].sum()), + ('Profit factor', lambda x: x[x > 0].sum() / x[x < 0].abs().sum() + if x[x < 0].abs().sum() != 0 else np.nan), + ('Avg. trade net profit', 'mean'), + ('Avg. winning trade', lambda x: x[x > 0].mean()), + ('Avg. losing trade', lambda x: x[x < 0].mean()), + ('Ratio Avg. Win:Avg. Loss', lambda x: x[x > 0].mean() / + x[x < 0].abs().mean() if x[x < 0].abs().mean() != 0 else np.nan), + ('Largest winning trade', 'max'), + ('Largest losing trade', 'min'), + ]) + +SUMMARY_STATS = OrderedDict( + [('Total number of round_trips', 'count'), + ('Percent profitable', lambda x: len(x[x > 0]) / float(len(x))), + ('Winning round_trips', lambda x: len(x[x > 0])), + ('Losing round_trips', lambda x: len(x[x < 0])), + ('Even round_trips', lambda x: len(x[x == 0])), + ]) + +RETURN_STATS = OrderedDict( + [('Avg returns all round_trips', lambda x: x.mean()), + ('Avg returns winning', lambda x: x[x > 0].mean()), + ('Avg returns losing', lambda x: x[x < 0].mean()), + ('Median returns all round_trips', lambda x: x.median()), + ('Median returns winning', lambda x: x[x > 0].median()), + ('Median returns losing', lambda x: x[x < 0].median()), + ('Largest winning trade', 'max'), + ('Largest losing trade', 'min'), + ]) + +DURATION_STATS = OrderedDict( + [('Avg duration', lambda x: x.mean()), + ('Median duration', lambda x: x.median()), + ('Avg # round_trips per day', lambda x: float(len(x)) / + (x.max() - x.min()).days), + ('Avg # round_trips per month', lambda x: float(len(x)) / + (((x.max() - x.min()).days) / 21)), + ]) + + +def agg_all_long_short(round_trips, col, stats_dict): + stats_all = round_trips.assign(ones=1)\ + .groupby('ones')[col]\ + .agg(stats_dict)\ + .T\ + .rename_axis({1.0: 'All trades'}, + axis='columns') + stats_long_short = round_trips.groupby('long')[col]\ + .agg(stats_dict)\ + .T\ + .rename_axis({False: 'Short trades', + True: 'Long trades'}, + axis='columns') + + return stats_all.join(stats_long_short)[['All trades', + 'Long trades', + 'Short trades']] + + +def _groupby_consecutive(txn, max_delta=pd.Timedelta('8h')): + """Merge transactions of the same direction separated by less than + max_delta time duration. Parameters ---------- transactions : pd.DataFrame - Prices and amounts of executed trades. One row per trade. + Prices and amounts of executed round_trips. One row per trade. - See full explanation in tears.create_full_tear_sheet - Returns - ------- - round_trips : pd.DataFrame - DataFrame with one row per round trip. - """ - # Transactions that cross zero must be split into separate - # long and short transactions that end/start on zero. - transactions_split = split_trades(transactions) - - transactions_split['txn_dollars'] = \ - -transactions_split['amount'] * transactions_split['price'] + max_delta : pandas.Timedelta (optional) + Merge transactions in the same direction separated by less + than max_delta time duration. - round_trips = defaultdict(list) - - for sym, trans_sym in transactions_split.groupby('symbol'): - trans_sym = trans_sym.sort_index() - amount_cumsum = trans_sym.amount.cumsum() - # Find indicies where the position amount returns to zero. - closed_idx = np.where(amount_cumsum == 0)[0] + 1 - # Identify the first trade as the beginning of a round trip. - closed_idx = np.insert(closed_idx, 0, 0) - - for trade_start, trade_end in zip(closed_idx, closed_idx[1:]): - txn = trans_sym.iloc[trade_start:trade_end] - - if len(txn) == 0: - continue - - assert txn.amount.sum() == 0 - long_trade = txn.amount.iloc[0] > 0 - pnl = txn.txn_dollars.sum() - round_trips['symbol'].append(sym) - round_trips['pnl'].append(pnl) - round_trips['duration'].append(txn.index[-1] - txn.index[0]) - round_trips['long'].append(long_trade) - round_trips['open_dt'].append(txn.index[0]) - round_trips['close_dt'].append(txn.index[-1]) - - # Investing txns push the position amount farther from zero. - # invested is always a positive value. Returned - Invested = PnL. - if long_trade: - invested = -txn.query('txn_dollars < 0').txn_dollars.sum() - else: - invested = txn.query('txn_dollars > 0').txn_dollars.sum() - - if invested == 0: - round_trips['returns'].append(0) - else: - round_trips['returns'].append(pnl / invested) - - if len(round_trips) == 0: - return pd.DataFrame([]) - - round_trips = pd.DataFrame(round_trips) - round_trips = round_trips[['open_dt', 'close_dt', 'duration', - 'pnl', 'returns', 'long', 'symbol']] - - return round_trips + Returns + ------- + transactions : pd.DataFrame -def split_trades(transactions): """ - Splits transactions that cause total position amount to cross zero. - In other words, separates of the closing of one short/long position - with the opening of a new long/short position. - - For example, the second transaction in this transactions DataFrame - would be divided as shown in the second DataFrame: - index amount price symbol - 2004-01-09 12:18:01 180 324.12 'AAPL' - 2004-01-09 15:12:53 -200 344.54 'AAPL' + def vwap(transaction): + if transaction.amount.sum() == 0: + warnings.warn('Zero transacted shares, setting vwap to nan.') + return np.nan + return (transaction.amount * transaction.price).sum() / \ + transaction.amount.sum() + + out = [] + for sym, t in txn.groupby('symbol'): + t = t.sort_index() + t.index.name = 'dt' + t = t.reset_index() + + t['order_sign'] = t.amount > 0 + t['block_dir'] = (t.order_sign.shift( + 1) != t.order_sign).astype(int).cumsum() + t['block_time'] = ((t.dt - t.dt.shift(1)) > + max_delta).astype(int).cumsum() + grouped_price = t.groupby(['block_dir', 'block_time'])[['price', 'amount']]\ + .apply(vwap) + grouped_price.name = 'price' + grouped_rest = t.groupby(['block_dir', 'block_time']).agg({ + 'amount': 'sum', + 'symbol': 'first', + 'dt': 'first'}) + + grouped = grouped_rest.join(grouped_price) + + out.append(grouped) + + out = pd.concat(out) + out = out.set_index('dt') + return out + + +def extract_round_trips(transactions, + portfolio_value=None): + """Group transactions into "round trips". First, transactions are + grouped by day and directionality. Then, long and short + transactions are matched to create round-trip round_trips for which + PnL, duration and returns are computed. Crossings where a position + changes from long to short and vice-versa are handled correctly. + + Under the hood, we reconstruct the individual shares in a + portfolio over time and match round_trips in a LIFO-order. + For example, the following transactions would constitute one round trip: index amount price symbol - 2004-01-09 12:18:01 180 324.12 'AAPL' - 2004-01-09 15:12:53 -180 344.54 'AAPL' - 2004-01-09 15:12:54 -20 344.54 'AAPL' + 2004-01-09 12:18:01 10 50 'AAPL' + 2004-01-09 15:12:53 10 100 'AAPL' + 2004-01-13 14:41:23 -10 100 'AAPL' + 2004-01-13 15:23:34 -10 200 'AAPL' + + First, the first two and last two round_trips will be merged into a two + single transactions (computing the price via vwap). Then, during + the portfolio reconstruction, the two resulting transactions will + be merged and result in 1 round-trip trade with a PnL of + (150 * 20) - (75 * 20) = 1500. + + Note, that round trips do not have to close out positions + completely. For example, we could have removed the last + transaction in the example above and still generated a round-trip + over 10 shares with 10 shares left in the portfolio to be matched + with a later transaction. Parameters ---------- transactions : pd.DataFrame - Prices and amounts of executed trades. One row per trade. + Prices and amounts of executed round_trips. One row per trade. - See full explanation in tears.create_full_tear_sheet + portfolio_value : pd.Series (optional) + Portfolio value (all net assets including cash) over time. + Returns ------- - transactions_split : pd.DataFrame - Prices and amounts of executed trades. Trades that cause - total position amount to cross zero are divided. + round_trips : pd.DataFrame + DataFrame with one row per round trip. The returns column + contains returns in respect to the portfolio value while + rt_returns are the returns in regards to the invested capital + into that partiulcar round-trip. """ - trans_split = [] + transactions = _groupby_consecutive(transactions) + roundtrips = [] for sym, trans_sym in transactions.groupby('symbol'): trans_sym = trans_sym.sort_index() - - while True: - cum_amount = trans_sym.amount.cumsum() - # find the indicies where position amount crosses zero - sign_flip = np.where(np.abs(np.diff(np.sign(cum_amount))) == 2)[0] - - if len(sign_flip) == 0: - break # all sign flips are converted - - sign_flip = sign_flip[0] + 2 - - txn = trans_sym.iloc[:sign_flip] - - left_over_txn_amount = txn.amount.sum() - assert left_over_txn_amount != 0 - - split_txn_1 = txn.iloc[[-1]].copy() - split_txn_2 = txn.iloc[[-1]].copy() - - split_txn_1['amount'] -= left_over_txn_amount - split_txn_2['amount'] = left_over_txn_amount - - # Delay 2nd trade by a second to avoid overlapping indices - split_txn_2.index += pd.Timedelta(seconds=1) - - assert split_txn_1.amount.iloc[0] + \ - split_txn_2.amount.iloc[0] == txn.iloc[-1].amount - assert trans_sym.iloc[:sign_flip - 1].amount.sum() + \ - split_txn_1.amount.iloc[0] == 0 - - # Recreate transactions so far with split transaction - trans_sym = pd.concat([trans_sym.iloc[:sign_flip - 1], - split_txn_1, - split_txn_2, - trans_sym.iloc[sign_flip:]]) - - assert np.all(np.abs(np.diff(np.sign(trans_sym.amount.cumsum()))) != 2) - trans_split.append(trans_sym) - - transactions_split = pd.concat(trans_split) - - return transactions_split + price_stack = [] + dt_stack = [] + for dt, t in trans_sym.iterrows(): + if t.price < 0: + warnings.warn('Negative price detected, ignoring for round-trip.') + continue + signed_price = t.price * np.sign(t.amount) + abs_amount = int(abs(t.amount)) + indiv_prices = [signed_price] * abs_amount + if (len(price_stack) == 0) or \ + (copysign(1, price_stack[-1]) == copysign(1, t.amount)): + price_stack.extend(indiv_prices) + dt_stack.extend([dt] * len(indiv_prices)) + else: + # Close round-trip + pnl = 0 + invested = 0 + cur_open_dts = [] + + for price in indiv_prices: + if len(price_stack) != 0 and \ + (copysign(1, price_stack[-1]) != copysign(1, price)): + # Retrieve last dt, stock-price pair from + # stack + prev_price = price_stack.pop() + prev_dt = dt_stack.pop() + + pnl += -(price + prev_price) + cur_open_dts.append(prev_dt) + invested += abs(prev_price) + + else: + # Push additional stock-prices onto stack + price_stack.append(price) + dt_stack.append(dt) + + roundtrips.append({'pnl': pnl, + #'duration': np.median(cur_durations), + 'open_dt': cur_open_dts[len(cur_open_dts) // + 2], + 'close_dt': dt, + 'long': price < 0, + 'rt_returns': pnl / invested, + 'symbol': sym, + }) + + roundtrips = pd.DataFrame(roundtrips) + + roundtrips['duration'] = roundtrips['close_dt'] - roundtrips['open_dt'] + + if portfolio_value is not None: + # Need to normalize so that we can join + pv = pd.DataFrame(portfolio_value, + columns=['portfolio_value'])\ + .assign(date=portfolio_value.index) + roundtrips['date'] = roundtrips.close_dt.apply(lambda x: x.replace(hour=0, minute=0, second=0)) + + # tmp = roundtrips.assign(date=roundtrips.close_dt + # .apply(lambda x: x.normalize()))\ + # .join(pv, on='date', lsuffix='_') + tmp = roundtrips.assign(date=roundtrips.close_dt)\ + .join(pv, on='date', lsuffix='_') + + roundtrips['returns'] = tmp.pnl / tmp.portfolio_value + + return roundtrips def add_closing_transactions(positions, transactions): @@ -188,7 +272,7 @@ def add_closing_transactions(positions, transactions): positions : pd.DataFrame The positions that the strategy takes over time. transactions : pd.DataFrame - Prices and amounts of executed trades. One row per trade. + Prices and amounts of executed round_trips. One row per trade. - See full explanation in tears.create_full_tear_sheet Returns @@ -201,8 +285,8 @@ def add_closing_transactions(positions, transactions): pos_at_end = positions.drop('cash', axis=1).iloc[-1] open_pos = pos_at_end.replace(0, np.nan).dropna() - # Add closing trades one second after the close to be sure - # they don't conflict with other trades executed at that time. + # Add closing round_trips one second after the close to be sure + # they don't conflict with other round_trips executed at that time. end_dt = open_pos.name + pd.Timedelta(seconds=1) for sym, ending_val in open_pos.iteritems(): @@ -248,3 +332,67 @@ def apply_sector_mappings_to_round_trips(round_trips, sector_mappings): sector_round_trips = sector_round_trips.dropna(axis=0) return sector_round_trips + + +def gen_round_trip_stats(round_trips): + """Generate various round-trip statistics. + + Parameters + ---------- + round_trips : pd.DataFrame + DataFrame with one row per round trip trade. + - See full explanation in round_trips.extract_round_trips + + Returns + ------- + stats : dict + A dictionary where each value is a pandas DataFrame containing + various round-trip statistics. + + See also + -------- + round_trips.print_round_trip_stats + """ + + stats = {} + stats['pnl'] = agg_all_long_short(round_trips, 'pnl', PNL_STATS) + stats['summary'] = agg_all_long_short(round_trips, 'pnl', + SUMMARY_STATS) + stats['duration'] = agg_all_long_short(round_trips, 'duration', + DURATION_STATS) + stats['returns'] = agg_all_long_short(round_trips, 'returns', + RETURN_STATS) + + stats['symbols'] = \ + round_trips.groupby('symbol')['returns'].agg(RETURN_STATS).T * 100 + + return stats + + +def print_round_trip_stats(round_trips, hide_pos=False): + """Print various round-trip statistics. Tries to pretty-print tables + with HTML output if run inside IPython NB. + + Parameters + ---------- + round_trips : pd.DataFrame + DataFrame with one row per round trip trade. + - See full explanation in round_trips.extract_round_trips + + See also + -------- + round_trips.gen_round_trip_stats + """ + + stats = gen_round_trip_stats(round_trips) + + print_table(stats['summary'], fmt='{:.2f}', name='Summary stats') + print_table(stats['pnl'], fmt='${:.2f}', name='PnL stats') + print_table(stats['duration'], fmt='{:.2f}', + name='Duration stats') + print_table(stats['returns'] * 100, fmt='{:.2f}%', + name='Return stats') + + if not hide_pos: + print_table(stats['symbols'] * 100, + fmt='{:.2f}%', name='Symbol stats') diff --git a/pyfolio/tears.py b/pyfolio/tears.py index e04ab1fb..067bbe90 100644 --- a/pyfolio/tears.py +++ b/pyfolio/tears.py @@ -64,6 +64,7 @@ def create_full_tear_sheet(returns, hide_positions=False, cone_std=(1.0, 1.5, 2.0), bootstrap=False, + unadjusted_returns=None, set_context=True): """ Generate a number of tear sheets that are useful @@ -153,13 +154,12 @@ def create_full_tear_sheet(returns, if returns.index[0] < benchmark_rets.index[0]: returns = returns[returns.index > benchmark_rets.index[0]] - if slippage is not None and transactions is not None: + if (unadjusted_returns is None) and (slippage is not None) and\ + (transactions is not None): turnover = txn.get_turnover(positions, transactions, period=None, average=False) unadjusted_returns = returns.copy() returns = txn.adjust_returns_for_slippage(returns, turnover, slippage) - else: - unadjusted_returns = None create_returns_tear_sheet( returns, @@ -544,7 +544,8 @@ def create_round_trip_tear_sheet(positions, transactions, transactions_closed = round_trips.add_closing_transactions(positions, transactions) - trades = round_trips.extract_round_trips(transactions_closed) + trades = round_trips.extract_round_trips(transactions_closed, + portfolio_value=positions.sum(axis='columns')) if len(trades) < 5: warnings.warn( @@ -552,24 +553,7 @@ def create_round_trip_tear_sheet(positions, transactions, Skipping round trip tearsheet.""", UserWarning) return - ndays = len(positions) - - print(trades.drop(['open_dt', 'close_dt', 'symbol'], - axis='columns').describe()) - print('Percent of round trips profitable = {:.4}%'.format( - (trades.pnl > 0).mean() * 100)) - - winning_round_trips = trades[trades.pnl > 0] - losing_round_trips = trades[trades.pnl < 0] - print('Mean return per winning round trip = {:.4}'.format( - winning_round_trips.returns.mean())) - print('Mean return per losing round trip = {:.4}'.format( - losing_round_trips.returns.mean())) - - print('A decision is made every {:.4} days.'.format(ndays / len(trades))) - print('{:.4} trading decisions per day.'.format(len(trades) * 1. / ndays)) - print('{:.4} trading decisions per month.'.format( - len(trades) * 1. / (ndays / 21))) + round_trips.print_round_trip_stats(trades) plotting.show_profit_attribution(trades) @@ -600,7 +584,7 @@ def create_round_trip_tear_sheet(positions, transactions, sns.distplot(trades.pnl, kde=False, ax=ax_pnl_per_round_trip_dollars) ax_pnl_per_round_trip_dollars.set(xlabel='PnL per round-trip trade in $') - sns.distplot(trades.returns * 100, kde=False, + sns.distplot(trades.returns.dropna() * 100, kde=False, ax=ax_pnl_per_round_trip_pct) ax_pnl_per_round_trip_pct.set( xlabel='Round-trip returns in %') From 5e8035684a7acd8b119df2e5aebed0b601c3bd12 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 12:42:49 +0200 Subject: [PATCH 02/13] ENH Change round-trip to be FIFO instead of LIFO. --- pyfolio/round_trips.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index e831b1ca..ce6f3136 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -149,7 +149,7 @@ def extract_round_trips(transactions, changes from long to short and vice-versa are handled correctly. Under the hood, we reconstruct the individual shares in a - portfolio over time and match round_trips in a LIFO-order. + portfolio over time and match round_trips in a FIFO-order. For example, the following transactions would constitute one round trip: index amount price symbol @@ -193,8 +193,8 @@ def extract_round_trips(transactions, for sym, trans_sym in transactions.groupby('symbol'): trans_sym = trans_sym.sort_index() - price_stack = [] - dt_stack = [] + price_stack = deque() + dt_stack = deque() for dt, t in trans_sym.iterrows(): if t.price < 0: warnings.warn('Negative price detected, ignoring for round-trip.') @@ -215,10 +215,10 @@ def extract_round_trips(transactions, for price in indiv_prices: if len(price_stack) != 0 and \ (copysign(1, price_stack[-1]) != copysign(1, price)): - # Retrieve last dt, stock-price pair from + # Retrieve first dt, stock-price pair from # stack - prev_price = price_stack.pop() - prev_dt = dt_stack.pop() + prev_price = price_stack.popleft() + prev_dt = dt_stack.popleft() pnl += -(price + prev_price) cur_open_dts.append(prev_dt) From 9dc8768123248e103cb36ce41c3d6d8d3b12b27d Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 12:43:43 +0200 Subject: [PATCH 03/13] WIP Add new test for groupby_consecutive. Fix old tests to work with new code. --- pyfolio/round_trips.py | 4 +- pyfolio/tests/test_round_trips.py | 75 +++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index ce6f3136..e4ca5a6c 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -230,9 +230,7 @@ def extract_round_trips(transactions, dt_stack.append(dt) roundtrips.append({'pnl': pnl, - #'duration': np.median(cur_durations), - 'open_dt': cur_open_dts[len(cur_open_dts) // - 2], + 'open_dt': cur_open_dts[0], 'close_dt': dt, 'long': price < 0, 'rt_returns': pnl / invested, diff --git a/pyfolio/tests/test_round_trips.py b/pyfolio/tests/test_round_trips.py index 058f3458..2ffdecde 100644 --- a/pyfolio/tests/test_round_trips.py +++ b/pyfolio/tests/test_round_trips.py @@ -15,52 +15,90 @@ import gzip from pyfolio.round_trips import (extract_round_trips, - add_closing_transactions) + add_closing_transactions, + _groupby_consecutive, +) class RoundTripTestCase(TestCase): dates = date_range(start='2015-01-01', freq='D', periods=20) + dates_intraday = date_range(start='2015-01-01', + freq='2BH', periods=8) + + @parameterized.expand([ + (DataFrame(data=[[2, 10., 'A'], + [2, 20., 'A'], + [-2, 20., 'A'], + [-2, 10., 'A'], + ], + columns=['amount', 'price', 'symbol'], + index=dates_intraday[:4]), + DataFrame(data=[[4, 15., 'A'], + [-4, 15., 'A'], + ], + columns=['amount', 'price', 'symbol'], + index=dates_intraday[[0, 2]]) + .rename_axis('dt', axis='index') + ), + (DataFrame(data=[[2, 10., 'A'], + [2, 20., 'A'], + [2, 20., 'A'], + [2, 10., 'A'], + ], + columns=['amount', 'price', 'symbol'], + index=dates_intraday[[0, 1, 4, 5]]), + DataFrame(data=[[4, 15., 'A'], + [4, 15., 'A'], + ], + columns=['amount', 'price', 'symbol'], + index=dates_intraday[[0, 4]]) + .rename_axis('dt', axis='index') + ), + ]) + def test_groupby_consecutive(self, transactions, expected): + grouped_txn = _groupby_consecutive(transactions) + assert_frame_equal(grouped_txn.sort(axis=1), expected.sort(axis=1)) @parameterized.expand([ - (DataFrame(data=[[2, 10, 'A'], - [-2, 15, 'A']], + (DataFrame(data=[[2, 10., 'A'], + [-2, 15., 'A']], columns=['amount', 'price', 'symbol'], index=dates[:2]), DataFrame(data=[[dates[0], dates[1], - Timedelta(days=1), 10, .5, + Timedelta(days=1), 10., .5, True, 'A']], columns=['open_dt', 'close_dt', - 'duration', 'pnl', 'returns', + 'duration', 'pnl', 'rt_returns', 'long', 'symbol'], index=[0]) ), - (DataFrame(data=[[2, 10, 'A'], - [2, 15, 'A'], - [-9, 10, 'A']], + (DataFrame(data=[[2, 10., 'A'], + [2, 15., 'A'], + [-9, 10., 'A']], columns=['amount', 'price', 'symbol'], index=dates[:3]), DataFrame(data=[[dates[0], dates[2], - Timedelta(days=2), -10, -.2, + Timedelta(days=2), -10., -.2, True, 'A']], columns=['open_dt', 'close_dt', - 'duration', 'pnl', 'returns', + 'duration', 'pnl', 'rt_returns', 'long', 'symbol'], index=[0]) ), - (DataFrame(data=[[2, 10, 'A'], - [-4, 15, 'A'], - [3, 20, 'A']], + (DataFrame(data=[[2, 10., 'A'], + [-4, 15., 'A'], + [3, 20., 'A']], columns=['amount', 'price', 'symbol'], index=dates[:3]), DataFrame(data=[[dates[0], dates[1], - Timedelta(days=1), 10, .5, + Timedelta(days=1), 10., .5, True, 'A'], - [dates[1] + Timedelta(seconds=1), dates[2], - Timedelta(days=1) - Timedelta(seconds=1), + [dates[1], dates[2], + Timedelta(days=1), -10, (-1. / 3), False, 'A']], columns=['open_dt', 'close_dt', - 'duration', 'pnl', 'returns', + 'duration', 'pnl', 'rt_returns', 'long', 'symbol'], index=[0, 1]) ) @@ -68,7 +106,8 @@ class RoundTripTestCase(TestCase): def test_extract_round_trips(self, transactions, expected): round_trips = extract_round_trips(transactions) - assert_frame_equal(round_trips, expected) + assert_frame_equal(round_trips.sort(axis=1), + expected.sort(axis=1)) def test_add_closing_trades(self): dates = date_range(start='2015-01-01', periods=20) From 3419af04c100eaa6abbcf66b69f2375e071cf706 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 12:58:07 +0200 Subject: [PATCH 04/13] TST Add additional test for computing non-zero-crossing round-trip and one that has portfolio values to compute portfolio round-trip return. --- pyfolio/round_trips.py | 4 +-- pyfolio/tests/test_round_trips.py | 42 ++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index e4ca5a6c..b140d616 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -248,13 +248,11 @@ def extract_round_trips(transactions, .assign(date=portfolio_value.index) roundtrips['date'] = roundtrips.close_dt.apply(lambda x: x.replace(hour=0, minute=0, second=0)) - # tmp = roundtrips.assign(date=roundtrips.close_dt - # .apply(lambda x: x.normalize()))\ - # .join(pv, on='date', lsuffix='_') tmp = roundtrips.assign(date=roundtrips.close_dt)\ .join(pv, on='date', lsuffix='_') roundtrips['returns'] = tmp.pnl / tmp.portfolio_value + roundtrips = roundtrips.drop('date', axis='columns') return roundtrips diff --git a/pyfolio/tests/test_round_trips.py b/pyfolio/tests/test_round_trips.py index 2ffdecde..62c22bbd 100644 --- a/pyfolio/tests/test_round_trips.py +++ b/pyfolio/tests/test_round_trips.py @@ -3,6 +3,7 @@ from unittest import TestCase from pandas import ( + Series, DataFrame, DatetimeIndex, date_range, @@ -60,6 +61,7 @@ def test_groupby_consecutive(self, transactions, expected): assert_frame_equal(grouped_txn.sort(axis=1), expected.sort(axis=1)) @parameterized.expand([ + # Simple round-trip (DataFrame(data=[[2, 10., 'A'], [-2, 15., 'A']], columns=['amount', 'price', 'symbol'], @@ -72,6 +74,7 @@ def test_groupby_consecutive(self, transactions, expected): 'long', 'symbol'], index=[0]) ), + # Round-trip with left-over txn that shouldn't be counted (DataFrame(data=[[2, 10., 'A'], [2, 15., 'A'], [-9, 10., 'A']], @@ -85,6 +88,7 @@ def test_groupby_consecutive(self, transactions, expected): 'long', 'symbol'], index=[0]) ), + # Round-trip with sell that crosses 0 and should be split (DataFrame(data=[[2, 10., 'A'], [-4, 15., 'A'], [3, 20., 'A']], @@ -101,10 +105,42 @@ def test_groupby_consecutive(self, transactions, expected): 'duration', 'pnl', 'rt_returns', 'long', 'symbol'], index=[0, 1]) - ) + ), + # Round-trip that does not cross 0 + (DataFrame(data=[[4, 10., 'A'], + [-2, 15., 'A'], + [2, 20., 'A']], + columns=['amount', 'price', 'symbol'], + index=dates[:3]), + DataFrame(data=[[dates[0], dates[1], + Timedelta(days=1), 10., .5, + True, 'A']], + columns=['open_dt', 'close_dt', + 'duration', 'pnl', 'rt_returns', + 'long', 'symbol'], + index=[0]) + ), + # Round-trip that does not cross 0 and has portfolio value + (DataFrame(data=[[4, 10., 'A'], + [-2, 15., 'A'], + [2, 20., 'A']], + columns=['amount', 'price', 'symbol'], + index=dates[:3]), + DataFrame(data=[[dates[0], dates[1], + Timedelta(days=1), 10., .5, + True, 'A', 0.1]], + columns=['open_dt', 'close_dt', + 'duration', 'pnl', 'rt_returns', + 'long', 'symbol', 'returns'], + index=[0]), + Series([100., 100., 100.], index=dates[:3]), + ), + ]) - def test_extract_round_trips(self, transactions, expected): - round_trips = extract_round_trips(transactions) + def test_extract_round_trips(self, transactions, expected, + portfolio_value=None): + round_trips = extract_round_trips(transactions, + portfolio_value=portfolio_value) assert_frame_equal(round_trips.sort(axis=1), expected.sort(axis=1)) From c88fb72254929657033ca7b11aeb20e4853f0ae3 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 13:01:39 +0200 Subject: [PATCH 05/13] STY PPE8 fixes. --- pyfolio/round_trips.py | 13 +++++++++---- pyfolio/tears.py | 6 +++--- pyfolio/tests/test_round_trips.py | 8 ++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index b140d616..b5530d7b 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -15,7 +15,7 @@ from __future__ import division from math import copysign import warnings -from collections import deque, defaultdict, OrderedDict +from collections import deque, OrderedDict import pandas as pd import numpy as np @@ -123,7 +123,8 @@ def vwap(transaction): 1) != t.order_sign).astype(int).cumsum() t['block_time'] = ((t.dt - t.dt.shift(1)) > max_delta).astype(int).cumsum() - grouped_price = t.groupby(['block_dir', 'block_time'])[['price', 'amount']]\ + grouped_price = t.groupby(['block_dir', + 'block_time'])[['price', 'amount']]\ .apply(vwap) grouped_price.name = 'price' grouped_rest = t.groupby(['block_dir', 'block_time']).agg({ @@ -197,7 +198,8 @@ def extract_round_trips(transactions, dt_stack = deque() for dt, t in trans_sym.iterrows(): if t.price < 0: - warnings.warn('Negative price detected, ignoring for round-trip.') + warnings.warn('Negative price detected, ignoring for' + 'round-trip.') continue signed_price = t.price * np.sign(t.amount) abs_amount = int(abs(t.amount)) @@ -246,7 +248,10 @@ def extract_round_trips(transactions, pv = pd.DataFrame(portfolio_value, columns=['portfolio_value'])\ .assign(date=portfolio_value.index) - roundtrips['date'] = roundtrips.close_dt.apply(lambda x: x.replace(hour=0, minute=0, second=0)) + roundtrips['date'] = roundtrips.close_dt.apply(lambda x: + x.replace(hour=0, + minute=0, + second=0)) tmp = roundtrips.assign(date=roundtrips.close_dt)\ .join(pv, on='date', lsuffix='_') diff --git a/pyfolio/tears.py b/pyfolio/tears.py index 067bbe90..41ee71b2 100644 --- a/pyfolio/tears.py +++ b/pyfolio/tears.py @@ -744,16 +744,16 @@ def create_capacity_tear_sheet(returns, positions, transactions, llt = capacity.get_low_liquidity_transactions(transactions, market_data) print('Tickers with daily transactions consuming >{}% of daily bar \n' - 'all backtest:'.format(trade_daily_vol_limit*100)) + 'all backtest:'.format(trade_daily_vol_limit * 100)) utils.print_table( - llt[llt['max_pct_bar_consumed'] > trade_daily_vol_limit*100]) + llt[llt['max_pct_bar_consumed'] > trade_daily_vol_limit * 100]) llt = capacity.get_low_liquidity_transactions( transactions, market_data, last_n_days=last_n_days) print("last {} trading days:".format(last_n_days)) utils.print_table( - llt[llt['max_pct_bar_consumed'] > trade_daily_vol_limit*100]) + llt[llt['max_pct_bar_consumed'] > trade_daily_vol_limit * 100]) bt_starting_capital = positions.iloc[0].sum() / (1 + returns.iloc[0]) fig, ax_capacity_sweep = plt.subplots(figsize=(14, 6)) diff --git a/pyfolio/tests/test_round_trips.py b/pyfolio/tests/test_round_trips.py index 62c22bbd..cfac4eb5 100644 --- a/pyfolio/tests/test_round_trips.py +++ b/pyfolio/tests/test_round_trips.py @@ -18,7 +18,7 @@ from pyfolio.round_trips import (extract_round_trips, add_closing_transactions, _groupby_consecutive, -) + ) class RoundTripTestCase(TestCase): @@ -46,8 +46,8 @@ class RoundTripTestCase(TestCase): [2, 20., 'A'], [2, 10., 'A'], ], - columns=['amount', 'price', 'symbol'], - index=dates_intraday[[0, 1, 4, 5]]), + columns=['amount', 'price', 'symbol'], + index=dates_intraday[[0, 1, 4, 5]]), DataFrame(data=[[4, 15., 'A'], [4, 15., 'A'], ], @@ -159,7 +159,7 @@ def test_add_closing_trades(self): index=[dates[:3]]) expected_ix = dates[:3].append(DatetimeIndex([dates[2] + - Timedelta(seconds=1)])) + Timedelta(seconds=1)])) expected = DataFrame(data=[[2, 10, 'A'], [-5, 10, 'A'], [-1, 10., 'B'], From 23e4c4b2b969c76ea4fa90aa663b9189dd38a5e5 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 18:17:05 +0200 Subject: [PATCH 06/13] STY Use paranetheses for method chaining. --- pyfolio/round_trips.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index b5530d7b..eb502608 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -67,18 +67,18 @@ def agg_all_long_short(round_trips, col, stats_dict): - stats_all = round_trips.assign(ones=1)\ - .groupby('ones')[col]\ - .agg(stats_dict)\ - .T\ + stats_all = (round_trips.assign(ones=1) + .groupby('ones')[col] + .agg(stats_dict) + .T .rename_axis({1.0: 'All trades'}, - axis='columns') - stats_long_short = round_trips.groupby('long')[col]\ - .agg(stats_dict)\ - .T\ + axis='columns')) + stats_long_short = (round_trips.groupby('long')[col] + .agg(stats_dict) + .T .rename_axis({False: 'Short trades', True: 'Long trades'}, - axis='columns') + axis='columns')) return stats_all.join(stats_long_short)[['All trades', 'Long trades', From 9ce08a00d42142ad063e9a7e4eb3a4a6476ed5f2 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Mon, 18 Apr 2016 18:18:23 +0200 Subject: [PATCH 07/13] STY Use APPROX_BDAYS_PER_MONTH instead of 21. --- pyfolio/round_trips.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index eb502608..466500f9 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -62,7 +62,7 @@ ('Avg # round_trips per day', lambda x: float(len(x)) / (x.max() - x.min()).days), ('Avg # round_trips per month', lambda x: float(len(x)) / - (((x.max() - x.min()).days) / 21)), + (((x.max() - x.min()).days) / utils.APPROX_BDAYS_PER_MONTH)), ]) From 88daaf27f0a98f7010a7301fa3f5340a011c662b Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 10:50:52 +0200 Subject: [PATCH 08/13] BUG Use BoD portfolio value to compute round-trip returns. --- pyfolio/round_trips.py | 2 ++ pyfolio/tears.py | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index 466500f9..0cf6a29d 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -179,6 +179,8 @@ def extract_round_trips(transactions, portfolio_value : pd.Series (optional) Portfolio value (all net assets including cash) over time. + Note that portfolio_value needs to beginning of day, so either + use .shift() or positions.sum(axis='columns') / (1+returns). Returns ------- diff --git a/pyfolio/tears.py b/pyfolio/tears.py index 41ee71b2..fe142261 100644 --- a/pyfolio/tears.py +++ b/pyfolio/tears.py @@ -186,6 +186,7 @@ def create_full_tear_sheet(returns, set_context=set_context) if round_trips: create_round_trip_tear_sheet( + returns=returns, positions=positions, transactions=transactions, sector_mappings=sector_mappings) @@ -517,7 +518,7 @@ def create_txn_tear_sheet(returns, positions, transactions, @plotting_context -def create_round_trip_tear_sheet(positions, transactions, +def create_round_trip_tear_sheet(returns, positions, transactions, sector_mappings=None, return_fig=False): """ @@ -529,6 +530,9 @@ def create_round_trip_tear_sheet(positions, transactions, Parameters ---------- + returns : pd.Series + Daily returns of the strategy, noncumulative. + - See full explanation in create_full_tear_sheet. positions : pd.DataFrame Daily net position values. - See full explanation in create_full_tear_sheet. @@ -544,8 +548,11 @@ def create_round_trip_tear_sheet(positions, transactions, transactions_closed = round_trips.add_closing_transactions(positions, transactions) - trades = round_trips.extract_round_trips(transactions_closed, - portfolio_value=positions.sum(axis='columns')) + # extract_round_trips requires BoD portfolio_value + trades = round_trips.extract_round_trips( + transactions_closed, + portfolio_value=positions.sum(axis='columns') / (1 + returns) + ) if len(trades) < 5: warnings.warn( From 6dd4b43fb2ed5fadfa6309a070819bea97a1a9f5 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 10:51:34 +0200 Subject: [PATCH 09/13] STY Vectorize signed and abs price computations. --- pyfolio/round_trips.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index 0cf6a29d..634e01c8 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -198,14 +198,16 @@ def extract_round_trips(transactions, trans_sym = trans_sym.sort_index() price_stack = deque() dt_stack = deque() + trans_sym['signed_price'] = trans_sym.price * \ + np.sign(trans_sym.amount) + trans_sym['abs_amount'] = trans_sym.amount.abs().astype(int) for dt, t in trans_sym.iterrows(): if t.price < 0: warnings.warn('Negative price detected, ignoring for' 'round-trip.') continue - signed_price = t.price * np.sign(t.amount) - abs_amount = int(abs(t.amount)) - indiv_prices = [signed_price] * abs_amount + + indiv_prices = [t.signed_price] * t.abs_amount if (len(price_stack) == 0) or \ (copysign(1, price_stack[-1]) == copysign(1, t.amount)): price_stack.extend(indiv_prices) From aa6c7498021265c7ed0c7399d42bc976c974d299 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 10:54:53 +0200 Subject: [PATCH 10/13] STY PEP8 fixes. --- pyfolio/round_trips.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index 634e01c8..c3bd9f67 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -20,7 +20,7 @@ import pandas as pd import numpy as np -from .utils import print_table +from .utils import print_table, APPROX_BDAYS_PER_MONTH PNL_STATS = OrderedDict( [('Total profit', lambda x: x.sum()), @@ -62,23 +62,25 @@ ('Avg # round_trips per day', lambda x: float(len(x)) / (x.max() - x.min()).days), ('Avg # round_trips per month', lambda x: float(len(x)) / - (((x.max() - x.min()).days) / utils.APPROX_BDAYS_PER_MONTH)), + (((x.max() - x.min()).days) / APPROX_BDAYS_PER_MONTH)), ]) def agg_all_long_short(round_trips, col, stats_dict): - stats_all = (round_trips.assign(ones=1) - .groupby('ones')[col] - .agg(stats_dict) - .T - .rename_axis({1.0: 'All trades'}, - axis='columns')) - stats_long_short = (round_trips.groupby('long')[col] - .agg(stats_dict) - .T - .rename_axis({False: 'Short trades', - True: 'Long trades'}, - axis='columns')) + stats_all = (round_trips + .assign(ones=1) + .groupby('ones')[col] + .agg(stats_dict) + .T + .rename_axis({1.0: 'All trades'}, + axis='columns')) + stats_long_short = (round_trips + .groupby('long')[col] + .agg(stats_dict) + .T + .rename_axis({False: 'Short trades', + True: 'Long trades'}, + axis='columns')) return stats_all.join(stats_long_short)[['All trades', 'Long trades', @@ -199,7 +201,7 @@ def extract_round_trips(transactions, price_stack = deque() dt_stack = deque() trans_sym['signed_price'] = trans_sym.price * \ - np.sign(trans_sym.amount) + np.sign(trans_sym.amount) trans_sym['abs_amount'] = trans_sym.amount.abs().astype(int) for dt, t in trans_sym.iterrows(): if t.price < 0: From c89de377be96c160081a2f5486215d5288a7b1fe Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 11:06:16 +0200 Subject: [PATCH 11/13] BUG Do not multiply symbol returns twice by 100. --- pyfolio/round_trips.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfolio/round_trips.py b/pyfolio/round_trips.py index c3bd9f67..85646aee 100644 --- a/pyfolio/round_trips.py +++ b/pyfolio/round_trips.py @@ -371,7 +371,7 @@ def gen_round_trip_stats(round_trips): RETURN_STATS) stats['symbols'] = \ - round_trips.groupby('symbol')['returns'].agg(RETURN_STATS).T * 100 + round_trips.groupby('symbol')['returns'].agg(RETURN_STATS).T return stats From 73d2cdc1842ea221f2f2a42d07e665554b62f305 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 11:06:33 +0200 Subject: [PATCH 12/13] DOC Update round-trip notebook. --- pyfolio/examples/round_trip_example.ipynb | 396 +++++++++++++--------- 1 file changed, 231 insertions(+), 165 deletions(-) diff --git a/pyfolio/examples/round_trip_example.ipynb b/pyfolio/examples/round_trip_example.ipynb index b72a74cd..7bae4baa 100644 --- a/pyfolio/examples/round_trip_example.ipynb +++ b/pyfolio/examples/round_trip_example.ipynb @@ -11,13 +11,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "When evaluating the performance of an investing strategy, it is helpful to quantify the frequency, duration, and profitability of its independent bets, or \"round trip\" trades. A round trip trade is started when a new long or short position is opened and is only completed when the number of shares in that position returns to or crosses zero. \n", + "When evaluating the performance of an investing strategy, it is helpful to quantify the frequency, duration, and profitability of its independent bets, or \"round trip\" trades. A round trip trade is started when a new long or short position is opened and then later completely or partially closed out.\n", "\n", "The intent of the round trip tearsheet is to help differentiate strategies that profited off a few lucky trades from strategies that profited repeatedly from genuine alpha. Breaking down round trip profitability by traded name and sector can also help inform universe selection and identify exposure risks. For example, even if your equity curve looks robust, if only two securities in your universe of fifteen names contributed to overall profitability, you may have reason to question the logic of your strategy.\n", "\n", - "To identify round trips, pyfolio groups transactions by symbol and identifies the points at which each position amount leaves and returns to zero. Behind the scenes, transactions that cause position amounts to flip directly from long to short or short to long are divided into separate transactions so that distinct round trips can be identified. In calculating round trips, pyfolio will also append position closing transactions at the last timestamp in the positions data. This closing transaction will cause the PnL from any open positions to realized as completed round trips.\n", - "\n", - "**Note: The round trip method of quantifying performance is not applicable to every style of strategy.** For instance, simple rebalancing algorithms make very few, if any, round trip trades. The results of the round trip tearsheet will be less informative for any strategy that doesn't entirely exit positions." + "To identify round trips, pyfolio reconstructs the complete portfolio based on the transactions that you pass in. When you make a trade, pyfolio checks if shares are already present in your portfolio purchased at a certain price. If there are, we compute the PnL, returns and duration of that round trip trade. In calculating round trips, pyfolio will also append position closing transactions at the last timestamp in the positions data. This closing transaction will cause the PnL from any open positions to realized as completed round trips." ] }, { @@ -48,7 +46,7 @@ "positions = pd.read_csv(gzip.open('../tests/test_data/test_pos.csv.gz'),\n", " index_col=0, parse_dates=0)\n", "returns = pd.read_csv(gzip.open('../tests/test_data/test_returns.csv.gz'),\n", - " index_col=0, parse_dates=0)" + " index_col=0, parse_dates=0, header=None)[1]" ] }, { @@ -67,18 +65,18 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "rts = pf.round_trips.extract_round_trips(transactions, portfolio_value=positions.sum(axis='columns'))" + "rts = pf.round_trips.extract_round_trips(transactions, portfolio_value=positions.sum(axis='columns') / (returns + 1))" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": { "collapsed": false }, @@ -92,12 +90,12 @@ " \n", " \n", " close_dt\n", - " duration\n", " long\n", " open_dt\n", " pnl\n", " rt_returns\n", " symbol\n", + " duration\n", " returns\n", " \n", " \n", @@ -105,79 +103,79 @@ " \n", " 0\n", " 2004-01-13\n", - " 1 days\n", " True\n", - " 2004-01-12\n", - " -208.800000\n", - " -0.036779\n", + " 2004-01-09\n", + " -126.000000\n", + " -0.022523\n", " AMD\n", - " -0.002110\n", + " 4 days\n", + " -0.001249\n", " \n", " \n", " 1\n", " 2004-01-16\n", - " 1 days\n", " True\n", - " 2004-01-15\n", - " 35.260000\n", - " 0.054088\n", + " 2004-01-09\n", + " 50.020000\n", + " 0.078507\n", " AMD\n", - " 0.000349\n", + " 7 days\n", + " 0.000503\n", " \n", " \n", " 2\n", " 2004-01-20\n", - " 8 days\n", " True\n", - " 2004-01-12\n", - " 1637.659065\n", - " 0.112071\n", + " 2004-01-09\n", + " 1540.099065\n", + " 0.104696\n", " AMD\n", - " 0.016318\n", + " 11 days\n", + " 0.015257\n", " \n", " \n", " 3\n", " 2004-01-21\n", - " 1 days\n", " False\n", " 2004-01-20\n", " 287.119806\n", " 0.085155\n", " AMD\n", - " 0.002866\n", + " 1 days\n", + " 0.002861\n", " \n", " \n", " 4\n", " 2004-01-22\n", - " 2 days\n", " False\n", " 2004-01-20\n", " 103.349947\n", " 0.112198\n", " AMD\n", - " 0.001038\n", + " 2 days\n", + " 0.001032\n", " \n", " \n", "\n", "" ], "text/plain": [ - " close_dt duration long open_dt pnl rt_returns symbol \\\n", - "0 2004-01-13 1 days True 2004-01-12 -208.800000 -0.036779 AMD \n", - "1 2004-01-16 1 days True 2004-01-15 35.260000 0.054088 AMD \n", - "2 2004-01-20 8 days True 2004-01-12 1637.659065 0.112071 AMD \n", - "3 2004-01-21 1 days False 2004-01-20 287.119806 0.085155 AMD \n", - "4 2004-01-22 2 days False 2004-01-20 103.349947 0.112198 AMD \n", + " close_dt long open_dt pnl rt_returns symbol duration \\\n", + "0 2004-01-13 True 2004-01-09 -126.000000 -0.022523 AMD 4 days \n", + "1 2004-01-16 True 2004-01-09 50.020000 0.078507 AMD 7 days \n", + "2 2004-01-20 True 2004-01-09 1540.099065 0.104696 AMD 11 days \n", + "3 2004-01-21 False 2004-01-20 287.119806 0.085155 AMD 1 days \n", + "4 2004-01-22 False 2004-01-20 103.349947 0.112198 AMD 2 days \n", "\n", " returns \n", - "0 -0.002110 \n", - "1 0.000349 \n", - "2 0.016318 \n", - "3 0.002866 \n", - "4 0.001038 " + "0 -0.001249 \n", + "1 0.000503 \n", + "2 0.015257 \n", + "3 0.002861 \n", + "4 0.001032 " ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -196,13 +194,14 @@ { "data": { "text/html": [ + "
\n", "\n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -214,33 +213,39 @@ " \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", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - "
Summary statsAll round_tripsLong round_tripsShort round_tripsAll tradesLong tradesShort trades
Percent profitable0.550.550.500.490.52
Winning round_trips3180.002584.002888.002292.00596.00
Losing round_trips2613.002060.002914.002361.00553.00
Even round_trips26.0020.0017.0011.006.00
" + "\n", + "
" ], "text/plain": [ - "" + "Summary stats All trades Long trades Short trades\n", + "Total number of round_trips 5819.00 4664.00 1155.00\n", + "Percent profitable 0.50 0.49 0.52\n", + "Winning round_trips 2888.00 2292.00 596.00\n", + "Losing round_trips 2914.00 2361.00 553.00\n", + "Even round_trips 17.00 11.00 6.00" ] }, "metadata": {}, @@ -249,81 +254,93 @@ { "data": { "text/html": [ + "
\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", + " \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", " \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", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - "
PnL statsAll round_tripsLong round_tripsShort round_tripsAll tradesLong tradesShort trades
Total profit$66840.00$63308.68$67003.94$63472.61$3531.32
Gross profit$402341.03$381761.36$448674.42$428094.75$20579.67
Gross loss$-335501.03$-318452.68$-381670.48$-364622.13$-17048.35
Profit factor$1.20$1.20$1.18$1.17$1.21
Avg. trade net profit$11.49$13.57$11.51$13.61$3.06
Avg. winning trade$126.52$147.74$155.36$186.78$34.53
Avg. losing trade$-128.40$-154.59$-130.98$-154.44$-30.83
Ratio Avg. Win:Avg. Loss$0.99$0.96$1.19$1.21$1.12
Largest winning trade$9977.28$9977.28$9500.14$9500.14$1623.24
Largest losing trade$-18557.39$-18557.39$-22902.83$-22902.83$-661.29
" + "\n", + "
" ], "text/plain": [ - "" + "PnL stats All trades Long trades Short trades\n", + "Total profit $67003.94 $63472.61 $3531.32\n", + "Gross profit $448674.42 $428094.75 $20579.67\n", + "Gross loss $-381670.48 $-364622.13 $-17048.35\n", + "Profit factor $1.18 $1.17 $1.21\n", + "Avg. trade net profit $11.51 $13.61 $3.06\n", + "Avg. winning trade $155.36 $186.78 $34.53\n", + "Avg. losing trade $-130.98 $-154.44 $-30.83\n", + "Ratio Avg. Win:Avg. Loss $1.19 $1.21 $1.12\n", + "Largest winning trade $9500.14 $9500.14 $1623.24\n", + "Largest losing trade $-22902.83 $-22902.83 $-661.29" ] }, "metadata": {}, @@ -332,45 +349,57 @@ { "data": { "text/html": [ + "
\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", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - "
Duration statsAll round_tripsLong round_tripsShort round_tripsAll tradesLong tradesShort trades
Avg duration7 days 18:01:03.1036269 days 01:33:23.77358413 days 03:27:07.70235415 days 19:02:40.5488852 days 10:39:35.064935
Median duration3 days 00:00:004 days 00:00:008 days 00:00:0012 days 00:00:002 days 00:00:00
Avg # round_trips per day20.4216.3670.1156.1996.25
Avg # round_trips per month428.77343.661472.281180.052021.25
" + "\n", + "
" ], "text/plain": [ - "" + "Duration stats All trades Long trades \\\n", + "Avg duration 13 days 03:27:07.702354 15 days 19:02:40.548885 \n", + "Median duration 8 days 00:00:00 12 days 00:00:00 \n", + "Avg # round_trips per day 70.11 56.19 \n", + "Avg # round_trips per month 1472.28 1180.05 \n", + "\n", + "Duration stats Short trades \n", + "Avg duration 2 days 10:39:35.064935 \n", + "Median duration 2 days 00:00:00 \n", + "Avg # round_trips per day 96.25 \n", + "Avg # round_trips per month 2021.25 " ] }, "metadata": {}, @@ -379,13 +408,14 @@ { "data": { "text/html": [ + "
\n", "\n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -397,8 +427,8 @@ " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -409,39 +439,48 @@ " \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", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", - "
Return statsAll round_tripsLong round_tripsShort round_tripsAll tradesLong tradesShort trades
Avg returns winning0.10%0.12%0.13%0.15%0.03%
Median returns all round_trips0.00%0.00%-0.00%-0.00%0.00%
Median returns winning0.01%0.02%0.03%0.01%
Median returns losing-0.01%-0.01%-0.02%-0.00%
Largest winning trade7.08%7.08%1.33%6.78%6.78%1.37%
Largest losing trade-16.77%-16.77%-17.23%-17.23%-0.72%
" + "\n", + "
" ], "text/plain": [ - "" + "Return stats All trades Long trades Short trades\n", + "Avg returns all round_trips 0.01% 0.01% 0.00%\n", + "Avg returns winning 0.13% 0.15% 0.03%\n", + "Avg returns losing -0.11% -0.13% -0.03%\n", + "Median returns all round_trips -0.00% -0.00% 0.00%\n", + "Median returns winning 0.02% 0.03% 0.01%\n", + "Median returns losing -0.01% -0.02% -0.00%\n", + "Largest winning trade 6.78% 6.78% 1.37%\n", + "Largest losing trade -17.23% -17.23% -0.72%" ] }, "metadata": {}, @@ -450,6 +489,7 @@ { "data": { "text/html": [ + "
\n", "\n", " \n", " \n", @@ -466,89 +506,108 @@ " \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", + " \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", - " \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", + " \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", - " \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", " \n", " \n", - "
Avg returns all round_trips-0.35%1.80%2.46%-2.93%-0.06%1.91%1.04%-0.00%0.02%0.02%-0.03%0.00%0.02%0.01%
Avg returns winning16.52%12.64%8.21%8.66%7.86%8.46%8.13%0.20%0.15%0.10%0.11%0.10%0.11%0.10%
Avg returns losing-18.75%-12.22%-5.54%-15.03%-9.46%-5.70%-9.17%-0.19%-0.13%-0.07%-0.15%-0.09%-0.06%-0.09%
Median returns all round_trips0.02%0.06%0.10%-0.00%0.00%0.00%-0.00%-0.00%-0.00%0.00%0.03%0.02%0.08%
Median returns winning1.79%1.68%1.23%1.25%1.18%0.96%1.12%0.03%0.02%0.02%0.02%0.02%0.01%0.02%
Median returns losing-1.28%-0.94%-0.71%-0.86%-0.79%-0.50%-0.64%-0.02%-0.01%-0.01%-0.02%-0.01%-0.01%-0.01%
Largest winning trade708.48%605.28%228.45%270.27%195.77%248.91%254.67%6.78%6.14%3.96%2.78%1.80%2.40%2.45%
Largest losing trade-1477.84%-544.99%-415.15%-1676.90%-348.04%-511.02%-339.08%-17.23%-3.92%-2.32%-6.39%-6.86%-4.45%-1.79%
" + "\n", + "
" ], "text/plain": [ - "" + "Symbol stats AMD CERN COST DELL GPS INTC \\\n", + "Avg returns all round_trips -0.00% 0.02% 0.02% -0.03% 0.00% 0.02% \n", + "Avg returns winning 0.20% 0.15% 0.10% 0.11% 0.10% 0.11% \n", + "Avg returns losing -0.19% -0.13% -0.07% -0.15% -0.09% -0.06% \n", + "Median returns all round_trips -0.00% 0.00% 0.00% -0.00% -0.00% -0.00% \n", + "Median returns winning 0.03% 0.02% 0.02% 0.02% 0.02% 0.01% \n", + "Median returns losing -0.02% -0.01% -0.01% -0.02% -0.01% -0.01% \n", + "Largest winning trade 6.78% 6.14% 3.96% 2.78% 1.80% 2.40% \n", + "Largest losing trade -17.23% -3.92% -2.32% -6.39% -6.86% -4.45% \n", + "\n", + "Symbol stats MMM \n", + "Avg returns all round_trips 0.01% \n", + "Avg returns winning 0.10% \n", + "Avg returns losing -0.09% \n", + "Median returns all round_trips 0.00% \n", + "Median returns winning 0.02% \n", + "Median returns losing -0.01% \n", + "Largest winning trade 2.45% \n", + "Largest losing trade -1.79% " ] }, "metadata": {}, @@ -558,6 +617,13 @@ "source": [ "pf.round_trips.print_round_trip_stats(rts)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternatively, when calling `pyfolio.create_full_tear_sheet()` you can set `round_trips=True` to create the last tables automatically." + ] } ], "metadata": { @@ -576,7 +642,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.5.0" } }, "nbformat": 4, From cf5f7bd9de4c82890b94185546deb15eb2409067 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Tue, 19 Apr 2016 11:08:46 +0200 Subject: [PATCH 13/13] DOC Update release notes. --- WHATSNEW.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/WHATSNEW.md b/WHATSNEW.md index b4560f79..95584829 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -2,6 +2,14 @@ These are new features and improvements of note in each release. +## v0.5.0 (upcoming) + +### New features + +* Refactored round-trip analysis to be more general and have better output. Now does full portfolio reconstruction to match trades [PR293](https://github.com/quantopian/pyfolio/pull/293). Thomas, Andrew + +### Bug fixes + ## v0.4.0 (Dec 10, 2015) This is a major release from 0.3.1 that includes new features and quite a few bug fixes. We recommend that all users upgrade to this new version.