{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "source": [
    "Bollinger Bands&copy; are used in trend following strategies.  See https://www.bollingerbands.com for more information.\n",
    "\n",
    "We use a moving average of the price of a security, and an upper and lower band around this price.  When the price moves above the upper band, we buy and when the price moves below the lower band we sell."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-08-03T16:45:21.511071Z",
     "start_time": "2018-08-03T16:45:21.506687Z"
    }
   },
   "source": [
    "First, lets load some data.  We are going to use a subset of bitcoin 1 minute bars downloaded from [Kaggle](https://www.kaggle.com/mczielinski/bitcoin-historical-data)\n",
    "\n",
    "For the purposes of this tutorial, we will trade in 5 minute bars instead of 1 minute bars, so lets resample the OHLCV data to 5 minutes\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:53.885663Z",
     "start_time": "2018-10-16T02:43:52.907703Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\", message=\"numpy.dtype size changed\") # ignore pesky warning, see https://github.com/numpy/numpy/pull/432\n",
    "\n",
    "import math\n",
    "import datetime\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import scipy.stats\n",
    "import os\n",
    "\n",
    "import pyqstrat as pq\n",
    "\n",
    "pq.set_defaults() # Set some display defaults to make dataframes and plots easier to look at\n",
    "\n",
    "try:\n",
    "    file_path = os.path.dirname(os.path.realpath(__file__)) + '/../examples/bitcoin_1min.csv' # If we are running from unit tests\n",
    "except:\n",
    "    file_path = '../examples/bitcoin_1min.csv'\n",
    "    \n",
    "prices = pd.read_csv(file_path)\n",
    "\n",
    "dates = pd.to_datetime(prices.date).values\n",
    "o = prices.o.values\n",
    "h = prices.h.values\n",
    "l = prices.l.values\n",
    "c = prices.c.values\n",
    "v = prices['v.usd'].values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-08-03T18:52:40.058616Z",
     "start_time": "2018-08-03T18:52:40.052487Z"
    }
   },
   "source": [
    "Lets create a market data object from this data and plot the first day of the bars to see how they look.\n",
    "\n",
    "Note that the MarketData constructor **takes c as its second argument, not o**.  This is because h, l, c and v are optional, but c is not."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:55.597986Z",
     "start_time": "2018-10-16T02:43:53.887895Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Inferred Frequency: 5.0 minutes\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>o</th>\n",
       "      <th>h</th>\n",
       "      <th>l</th>\n",
       "      <th>c</th>\n",
       "      <th>v</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>1001</td>\n",
       "      <td>1001</td>\n",
       "      <td>1001</td>\n",
       "      <td>1001</td>\n",
       "      <td>1001</td>\n",
       "      <td>1001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>num_missing</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>pct_missing</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>2018-03-23 12:40:00</td>\n",
       "      <td>7873</td>\n",
       "      <td>7889</td>\n",
       "      <td>7831</td>\n",
       "      <td>7878</td>\n",
       "      <td>1425</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>2018-03-27 00:00:00</td>\n",
       "      <td>9006</td>\n",
       "      <td>9020</td>\n",
       "      <td>8970</td>\n",
       "      <td>9006</td>\n",
       "      <td>6.155e+06</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                            date     o     h     l     c         v\n",
       "count                       1001  1001  1001  1001  1001      1001\n",
       "num_missing                    0     0     0     0     0         0\n",
       "pct_missing                    0     0     0     0     0         0\n",
       "min          2018-03-23 12:40:00  7873  7889  7831  7878      1425\n",
       "max          2018-03-27 00:00:00  9006  9020  8970  9006 6.155e+06"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Errors:\n",
      "Warnings:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>v</th>\n",
       "      <th>l</th>\n",
       "      <th>h</th>\n",
       "      <th>o</th>\n",
       "      <th>c</th>\n",
       "      <th>ret</th>\n",
       "      <th>warning</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:05:00</th>\n",
       "      <td>1.771e+06</td>\n",
       "      <td>7908</td>\n",
       "      <td>8102</td>\n",
       "      <td>7915</td>\n",
       "      <td>8102</td>\n",
       "      <td>nan</td>\n",
       "      <td>o ret &gt; 10 std: 0.001931</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:10:00</th>\n",
       "      <td>1.361e+06</td>\n",
       "      <td>8046</td>\n",
       "      <td>8150</td>\n",
       "      <td>8103</td>\n",
       "      <td>8150</td>\n",
       "      <td>0.0237</td>\n",
       "      <td>o ret &gt; 10 std: 0.001931</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:00:00</th>\n",
       "      <td>9.338e+04</td>\n",
       "      <td>7876</td>\n",
       "      <td>7925</td>\n",
       "      <td>7888</td>\n",
       "      <td>7908</td>\n",
       "      <td>nan</td>\n",
       "      <td>h ret &gt; 10 std: 0.001774</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:05:00</th>\n",
       "      <td>1.771e+06</td>\n",
       "      <td>7908</td>\n",
       "      <td>8102</td>\n",
       "      <td>7915</td>\n",
       "      <td>8102</td>\n",
       "      <td>0.02233</td>\n",
       "      <td>h ret &gt; 10 std: 0.001774</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:00:00</th>\n",
       "      <td>9.338e+04</td>\n",
       "      <td>7876</td>\n",
       "      <td>7925</td>\n",
       "      <td>7888</td>\n",
       "      <td>7908</td>\n",
       "      <td>nan</td>\n",
       "      <td>c ret &gt; 10 std: 0.001952</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26 22:05:00</th>\n",
       "      <td>1.771e+06</td>\n",
       "      <td>7908</td>\n",
       "      <td>8102</td>\n",
       "      <td>7915</td>\n",
       "      <td>8102</td>\n",
       "      <td>0.02453</td>\n",
       "      <td>c ret &gt; 10 std: 0.001952</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                            v    l    h    o    c     ret  \\\n",
       "date                                                        \n",
       "2018-03-26 22:05:00 1.771e+06 7908 8102 7915 8102     nan   \n",
       "2018-03-26 22:10:00 1.361e+06 8046 8150 8103 8150  0.0237   \n",
       "2018-03-26 22:00:00 9.338e+04 7876 7925 7888 7908     nan   \n",
       "2018-03-26 22:05:00 1.771e+06 7908 8102 7915 8102 0.02233   \n",
       "2018-03-26 22:00:00 9.338e+04 7876 7925 7888 7908     nan   \n",
       "2018-03-26 22:05:00 1.771e+06 7908 8102 7915 8102 0.02453   \n",
       "\n",
       "                                      warning  \n",
       "date                                           \n",
       "2018-03-26 22:05:00  o ret > 10 std: 0.001931  \n",
       "2018-03-26 22:10:00  o ret > 10 std: 0.001931  \n",
       "2018-03-26 22:00:00  h ret > 10 std: 0.001774  \n",
       "2018-03-26 22:05:00  h ret > 10 std: 0.001774  \n",
       "2018-03-26 22:00:00  c ret > 10 std: 0.001952  \n",
       "2018-03-26 22:05:00  c ret > 10 std: 0.001952  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time distribution:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 34036 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 32596 characters]\n",
      "text/plain": [
       "<Figure size 1440x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "md = pq.MarketData(dates, c, o, h, l, v)\n",
    "md.resample(sampling_frequency='5 min', inplace = True)\n",
    "md.plot(date_range = ('2018-03-24 09:30', '2018-03-24 16:00'))\n",
    "md.describe(time_distribution_frequency = '30 mins')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-08-06T20:15:57.458367Z",
     "start_time": "2018-08-06T20:15:57.396777Z"
    }
   },
   "source": [
    "This looks reasonable.  The describe() function allows us to do some checks on the market data to make sure its ready for use in a strategy.  It tells us:\n",
    "\n",
    "1.  How much data is missing, and the most common bar frequency.\n",
    "\n",
    "2.  Errors - Negative values, highs or lows that are lower or higher than opens or closes.\n",
    "\n",
    "3.  Warnings - Returns for o, h, l, c, v that are more than n (default = 10) standard deviations off the mean.\n",
    "\n",
    "5.  Time distribution of price frequency and trade volume - This tells you, for example, if the market data includes after-market prices or not.\n",
    "\n",
    "\n",
    "The next step is to add the Bollinger Bands.  Lets set the middle band as the 20 bar simple moving average of the close, and the upper and lower bands to be 1 standard deviation away from the middle band. This time, instead of plotting candles, we will plot the close price to display a cleaner graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:55.996191Z",
     "start_time": "2018-10-16T02:43:55.601028Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 114328 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def sma(marketdata, lookback_period): # simple moving average\n",
    "    return pd.Series(marketdata.c).rolling(window = lookback_period).mean().values\n",
    "\n",
    "def band(marketdata, lookback_period, num_std, upper):\n",
    "    std = pd.Series(marketdata.c).rolling(window = 20).std()\n",
    "    return sma(marketdata, lookback_period = lookback_period) + num_std * std * (1 if upper else -1)\n",
    "\n",
    "num_std = 1 # Each band is 2 standard deviations away from the moving average of price\n",
    "\n",
    "lookback_period = 20 # Length of moving average window\n",
    "mid_band = sma(md, lookback_period)\n",
    "upper_band = band(md, lookback_period, num_std, upper = True)\n",
    "lower_band = band(md, lookback_period, num_std, upper = False)\n",
    "\n",
    "indicator_subplot = pq.Subplot([pq.TimeSeries('price', md.dates, md.c, color = 'blue'), \n",
    "                     pq.TimeSeries('sma', md.dates, mid_band, line_type = 'dotted', color = 'red'),\n",
    "                     pq.TimeSeries('upper band', md.dates, upper_band, line_type = 'dashed', color = 'green'),\n",
    "                     pq.TimeSeries('lower_band', md.dates, lower_band, line_type = 'dashed', color = 'green')],\n",
    "                     ylabel = 'Indicators')\n",
    "plot = pq.Plot(indicator_subplot, title = 'BTC')\n",
    "plot.draw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The bands and the moving average are called \"indicators\" in pyqstrat.  Indicators are the fundamental building blocks of any strategy.\n",
    "\n",
    "Now lets create a signal.  A signal uses marketdata and indicators and tells a strategy when to create orders.  In this case we buy when the price crosses the upper band and exit when the price crosses the moving average.  Similarly, we sell when the price crosses the lower band and exit when it crosses the moving average.  We create 4 different values of the signal, +2, -2, +1, -1 to signal all 4 of these conditions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:56.004013Z",
     "start_time": "2018-10-16T02:43:55.998481Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "def bollinger_band_signal(md, ind): # md is MarketData, ind is indicator values, a dictionary of indicator values\n",
    "    signal = np.where(md.h > np.nan_to_num(ind['upper_band']), 2, 0)\n",
    "    signal = np.where(md.l < np.nan_to_num(ind['lower_band']), -2, signal)\n",
    "    signal = np.where((md.h > np.nan_to_num(ind['mid_band'])) & (signal == 0), 1, signal) # price crossed above simple moving avg but not above upper band\n",
    "    signal = np.where((md.l < np.nan_to_num(ind['mid_band'])) & (signal == 0), -1, signal) # price crossed below simple moving avg but not below lower band\n",
    "    return signal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's plot the signal in a subplot along with the indicators and check whether it makes sense"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:56.551124Z",
     "start_time": "2018-10-16T02:43:56.006798Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 150676 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "signal = bollinger_band_signal(md, {'upper_band' : upper_band, 'lower_band' : lower_band, 'mid_band' : mid_band})\n",
    "signal_subplot = pq.Subplot([pq.TimeSeries('signal', md.dates, signal)], ylabel = 'Signal')\n",
    "plot = pq.Plot([indicator_subplot, signal_subplot], title = 'BTC', show_date_gaps = False)\n",
    "plot.draw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-08-06T19:51:47.743290Z",
     "start_time": "2018-08-06T19:51:47.739748Z"
    }
   },
   "source": [
    "This is hard to see clearly so let's look at a smaller date range"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:57.083910Z",
     "start_time": "2018-10-16T02:43:56.553850Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 129248 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot = pq.Plot([indicator_subplot, signal_subplot], title = 'BTC', date_range = ('2018-03-24', '2018-03-25'))\n",
    "plot.draw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This looks good.  The signal behaves as we would expect.\n",
    "\n",
    "The next step is to create a trading rule.  pyqstrat will call a trading rule function when the value of it's associated signal changes value, or when we have live orders in the market that have not been filled.  A trading rule decides whether or not to take action on the signal.  If it decides to take action, it returns a list of one or more orders.  This is where margin decisions are made as well, i.e. the trading rule knows how much margin is needed, and will not place orders if margin is exceeded.\n",
    "\n",
    "Trading rules are usually path dependent, i.e. they cannot be vectorized like indicators and signals can, since can depend on current position, risk, or other data that changes with time.  \n",
    "\n",
    "Because of this path dependence, pyqstrat will call order rule functions once per date.  This is the part of the code (along with market simulation) that you should optimize as much as you can.  My advice is to use numpy arrays as much as possible here, avoiding slow parts of pandas code.\n",
    "\n",
    "Lets build the trading rule.  We will risk 10% of our current equity when going long or short.  When entering we will enter a stop order.  This means the system will only enter if the price crosses the current close during the next bar.  We are trying to avoid a case where we cross a bollinger band in this bar but then price immediately goes the other way in the next bar, in which case we should not enter the trade.  We will ignore margin in this case for simplicity.  If we wanted to check margin, we would add code here that would check if margin would be exceeded (based on broker specific logic), and modify the order qty accordingly.\n",
    "\n",
    "We are using predefined order reason codes when we create orders below.  Reason codes are optional strings that we use to identify why we entered an order and are useful for debugging and for plotting.  You can use an arbitrary string as a reason code.  If you later want to identify those trades in a plot, you will have to provide a mapping between your reason codes and the markers used for that reason code in a trade plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:57.093281Z",
     "start_time": "2018-10-16T02:43:57.086331Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "def bollinger_band_trading_rule(strategy, symbol, i, date, marketdata, indicator_values, signal_values, account):\n",
    "    curr_pos = account.position(symbol, date)\n",
    "    signal_value = signal_values[i]\n",
    "    risk_percent = 0.1\n",
    "    \n",
    "    # if we don't already have a position, check if we should enter a trade\n",
    "    if math.isclose(curr_pos, 0):\n",
    "        if signal_value == 2 or signal_value == -2:\n",
    "            curr_equity = account.equity(date)\n",
    "            order_qty = np.round(curr_equity * risk_percent / marketdata.c[i] * np.sign(signal_value))\n",
    "            trigger_price = marketdata.c[i]\n",
    "            reason_code = pq.ReasonCode.ENTER_LONG if order_qty > 0 else pq.ReasonCode.ENTER_SHORT\n",
    "            return [pq.StopLimitOrder(symbol, date, order_qty, trigger_price, reason_code = reason_code)]\n",
    "        \n",
    "    else: # We have a current position, so check if we should exit\n",
    "        if (curr_pos > 0 and signal_value == -1) or (curr_pos < 0 and signal_value == 1):\n",
    "            order_qty = -curr_pos\n",
    "            reason_code = pq.ReasonCode.EXIT_LONG if order_qty < 0 else pq.ReasonCode.EXIT_SHORT\n",
    "            return [pq.MarketOrder(symbol, date, order_qty, reason_code = reason_code)]\n",
    "    return []\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We need to write one more function, a market simulator.  The market simulator decides whether open orders will be filled, and at what price.  This is where you would add slippage, commissions and fees.  You can add a different market simulator for each symbol, since liquidity and market rules are clearly different when trading an IBM stock on NYSE versus trading a E-mini future on CME.  pyqstrat will call the market simulator on the next bar after you add an order since you obviously cannot get filled using prices you already saw and used to construct your order.  In this simulator we fill buy market orders half way between the open and the high for the current bar, and sells half way between the open and the low. Stop orders are filled halfway between the trigger price and the high or low.  We ignore commissions and fees for simplicity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:57.103023Z",
     "start_time": "2018-10-16T02:43:57.096457Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "def market_simulator(strategy, orders, i, date, md):\n",
    "    trades = []\n",
    "    \n",
    "    o, h, l, c = md.o[i], md.h[i], md.l[i], md.c[i]\n",
    "    \n",
    "    for order in orders:\n",
    "        trade_price = np.nan\n",
    "        \n",
    "        if isinstance(order, pq.MarketOrder):\n",
    "            trade_price = 0.5 * (o + h) if order.qty > 0 else 0.5 * (o + l)\n",
    "        elif isinstance(order, pq.StopLimitOrder):\n",
    "            if (order.qty > 0 and h > order.trigger_price) or (order.qty < 0 and l < order.trigger_price): # A stop order\n",
    "                trade_price = 0.5 * (order.trigger_price + h) if order.qty > 0 else 0.5 * (order.trigger_price + l)\n",
    "        else:\n",
    "            raise Exception(f'unexpected order type: {order}')\n",
    "            \n",
    "        if np.isnan(trade_price): continue\n",
    "            \n",
    "        trade = pq.Trade(order.symbol, date, order.qty, trade_price, order = order, commission = 0, fee = 0)\n",
    "        order.status = 'filled'\n",
    "                           \n",
    "        trades.append(trade)\n",
    "                           \n",
    "    return trades"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now lets create the strategy and run it.\n",
    "\n",
    "We will instantiate a few objects:\n",
    "\n",
    "\n",
    "1.  Contract - a symbol represents a real or virtual instrument.  Each contract contains a symbol, marketdata and a multiplier. The multiplier is used in cases where price and quantity are in different units.  For example, for most equity options, a quantity of 1 represents 100 shares, but a price of 0.50 represents 0.50 per share.\n",
    "\n",
    "\n",
    "2.  Account - an account is tied to a strategy and keeps track of your current equity, realized and unrealized P&L as well as commissions and fees.  An account has a calculation frequency that is usually slower than the strategy.  For example, a strategy may trade with 1 minute bars, but you may only need to calculate P&L at end of day.  However, at some points along the way, you may need intraday equity, etc.  For example, the strategy may need to look at current equity to determine how to size orders.  In these cases, the account will automatically recalculate when you ask it for this data.  An account contains one or more symbols.  In this case we add one symbol, IBM, to the account, and set our starting equity to $1mm.\n",
    "\n",
    "\n",
    "3.  Strategy - You run a strategy after adding indicators, signals, trading rules, and market simulators to generate orders and trades.  Running a strategy also calculates returns and P&L.\n",
    "\n",
    "\n",
    "4.  Portfolio - A portfolio is a collection of strategies.  For example, you may have two or more uncorrelated strategies that you want to run concurrently and rebalance periodically.  You can add these to a single portfolio and add rebalance rules to compute returns and P&L."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:57.277730Z",
     "start_time": "2018-10-16T02:43:57.106468Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "contract = pq.Contract('BTC', multiplier = 1., marketdata = md)\n",
    "strategy = pq.Strategy([contract])\n",
    "\n",
    "# since pqstrat expects the indicator to take one argument, market data, and our sma function takes 2 arguments, we wrap it in a lambda \n",
    "strategy.add_indicator('mid_band', lambda md : sma(md, lookback_period))\n",
    "strategy.add_indicator('upper_band', lambda md: band(md, lookback_period, num_std, upper = True))\n",
    "strategy.add_indicator('lower_band', lambda md: band(md, lookback_period, num_std, upper = False))\n",
    "strategy.add_signal('bb_signal', bollinger_band_signal)\n",
    "\n",
    "# ask pqstrat to call our trading rule when the signal has one of the values [-2, -1, 1, 2]\n",
    "strategy.add_rule('bb_trading_rule', bollinger_band_trading_rule, \n",
    "                  signal_name = 'bb_signal', sig_true_values = [-2, -1, 1, 2])\n",
    "\n",
    "strategy.add_market_sim(market_simulator, symbols = ['BTC'])\n",
    "\n",
    "portfolio = pq.Portfolio()\n",
    "portfolio.add_strategy('bb_strategy', strategy)\n",
    "portfolio.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets plot our strategy and our portfolio and evaluate our returns  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:58.393118Z",
     "start_time": "2018-10-16T02:43:57.280205Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 241960 characters]\n",
      "text/plain": [
       "<Figure size 1440x1080 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "strategy.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:58.423374Z",
     "start_time": "2018-10-16T02:43:58.395604Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>equity</th>\n",
       "      <th>ret</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2018-03-23</th>\n",
       "      <td>1.005e+06</td>\n",
       "      <td>nan</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-24</th>\n",
       "      <td>9.991e+05</td>\n",
       "      <td>-0.006317</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-25</th>\n",
       "      <td>9.895e+05</td>\n",
       "      <td>-0.009643</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-26</th>\n",
       "      <td>9.914e+05</td>\n",
       "      <td>0.001963</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              equity       ret\n",
       "date                          \n",
       "2018-03-23 1.005e+06       nan\n",
       "2018-03-24 9.991e+05 -0.006317\n",
       "2018-03-25 9.895e+05 -0.009643\n",
       "2018-03-26 9.914e+05  0.001963"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "strategy.df_returns()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:59.121184Z",
     "start_time": "2018-10-16T02:43:58.426020Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>gmean</th>\n",
       "      <th>amean</th>\n",
       "      <th>std</th>\n",
       "      <th>shrp</th>\n",
       "      <th>srt</th>\n",
       "      <th>calmar</th>\n",
       "      <th>mar</th>\n",
       "      <th>mdd_pct</th>\n",
       "      <th>mdd_dates</th>\n",
       "      <th>dd_3y_pct</th>\n",
       "      <th>dd_3y_dates</th>\n",
       "      <th>up_dwn</th>\n",
       "      <th>2018</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <td>-0.5878</td>\n",
       "      <td>-0.003499</td>\n",
       "      <td>0.004684</td>\n",
       "      <td>-11.86</td>\n",
       "      <td>-13.35</td>\n",
       "      <td>55.46</td>\n",
       "      <td>55.46</td>\n",
       "      <td>-0.0159</td>\n",
       "      <td>2018-03-23/2018-03-25</td>\n",
       "      <td>-0.0159</td>\n",
       "      <td>2018-03-23/2018-03-25</td>\n",
       "      <td>1/2/0.333</td>\n",
       "      <td>-0.5878</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    gmean      amean       std    shrp     srt calmar    mar  mdd_pct  \\\n",
       "  -0.5878  -0.003499  0.004684  -11.86  -13.35  55.46  55.46  -0.0159   \n",
       "\n",
       "              mdd_dates dd_3y_pct            dd_3y_dates     up_dwn     2018  \n",
       "  2018-03-23/2018-03-25   -0.0159  2018-03-23/2018-03-25  1/2/0.333  -0.5878  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 62396 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "strategy.evaluate_returns();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that we calculate P&L once a day so the equity line produced when we evaluate returns has fewer points than the equity line when we plot the strategy itself.\n",
    "\n",
    "Lets add two to the portfolio and we will run the two strategies together.  We will use two bollinger band strategy with different lookback periods and standard deviations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:43:59.585209Z",
     "start_time": "2018-10-16T02:43:59.124110Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "from pyqstrat.examples.build_example_strategy import build_example_strategy\n",
    "\n",
    "strategy1 = build_example_strategy(lookback_period = 5, num_std = 1)\n",
    "strategy2 = build_example_strategy(lookback_period = 10, num_std = 2)\n",
    "portfolio = pq.Portfolio()\n",
    "portfolio.add_strategy('bb_strategy_1', strategy1)\n",
    "portfolio.add_strategy('bb_strategy_2', strategy2)\n",
    "portfolio.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets now plot the output of the two strategies as well as the portfolio output.  The portfolio returns will be the sum of the returns of the 2 strategies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:44:00.733408Z",
     "start_time": "2018-10-16T02:43:59.587183Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 259072 characters]\n",
      "text/plain": [
       "<Figure size 1440x1080 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "strategy1.plot(title = 'Strategy 1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:44:01.859258Z",
     "start_time": "2018-10-16T02:44:00.735978Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 261352 characters]\n",
      "text/plain": [
       "<Figure size 1440x1080 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "strategy2.plot(title = 'Strategy 2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-10-16T02:44:02.749711Z",
     "start_time": "2018-10-16T02:44:01.861702Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 63876 characters]\n",
      "text/plain": [
       "<Figure size 1080x576 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "portfolio.plot()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
