{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simple Trading Rule"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sysdata.sim.csv_futures_sim_data import csvFuturesSimData\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Work up a minimum example of a trend following system"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's get some data\n",
    "\n",
    "We can get data from various places; however for now we're going to use\n",
    "prepackaged 'legacy' data stored in csv files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "No datapaths provided for .csv, will use defaults  (may break in production, should be fine in sim)\n",
      "No datapaths provided for .csv, will use defaults  (may break in production, should be fine in sim)\n",
      "No datapaths provided for .csv, will use defaults  (may break in production, should be fine in sim)\n",
      "No datapaths provided for .csv, will use defaults  (may break in production, should be fine in sim)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "csvFuturesSimData object with 46 instruments"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = csvFuturesSimData()\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We get stuff out of data with methods"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['AEX', 'AUD', 'BITCOIN', 'BOBL', 'BTP', 'BUND', 'CAC', 'COPPER', 'CORN', 'CRUDE_W', 'CRUDE_W_mini', 'EDOLLAR', 'EUR', 'EUROSTX', 'GAS_US', 'GAS_US_mini', 'GBP', 'GOLD', 'GOLD_micro', 'JPY', 'KOSPI', 'KOSPI_mini', 'KR10', 'KR3', 'LEANHOG', 'LIVECOW', 'MXP', 'NASDAQ', 'NASDAQ_micro', 'NZD', 'OAT', 'PALLAD', 'PLAT', 'SHATZ', 'SMI', 'SOYBEAN', 'SP500', 'SP500_micro', 'US-REALESTATE', 'US10', 'US2', 'US20', 'US5', 'V2X', 'VIX', 'WHEAT']\n",
      "index\n",
      "2021-03-08 16:00:00    98.865\n",
      "2021-03-08 17:00:00    98.860\n",
      "2021-03-08 18:00:00    98.865\n",
      "2021-03-08 19:00:00    98.865\n",
      "2021-03-08 20:00:00    98.860\n",
      "Name: price, dtype: float64\n"
     ]
    }
   ],
   "source": [
    "print(data.get_instrument_list())\n",
    "print(data.get_raw_price(\"EDOLLAR\").tail(5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "data can also behave in a dict like manner (though it's not a dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "index\n",
       "1997-12-12 23:00:00    1081.25\n",
       "1997-12-15 23:00:00    1089.25\n",
       "1997-12-16 23:00:00    1095.25\n",
       "1997-12-17 23:00:00    1089.25\n",
       "1997-12-18 23:00:00    1079.25\n",
       "                        ...   \n",
       "2021-03-08 17:00:00    3869.50\n",
       "2021-03-08 18:00:00    3845.50\n",
       "2021-03-08 19:00:00    3849.75\n",
       "2021-03-08 20:00:00    3820.00\n",
       "2021-03-08 21:00:00    3822.50\n",
       "Name: price, Length: 16153, dtype: float64"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data['SP500']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['AEX',\n",
       " 'AUD',\n",
       " 'BITCOIN',\n",
       " 'BOBL',\n",
       " 'BTP',\n",
       " 'BUND',\n",
       " 'CAC',\n",
       " 'COPPER',\n",
       " 'CORN',\n",
       " 'CRUDE_W',\n",
       " 'CRUDE_W_mini',\n",
       " 'EDOLLAR',\n",
       " 'EUR',\n",
       " 'EUROSTX',\n",
       " 'GAS_US',\n",
       " 'GAS_US_mini',\n",
       " 'GBP',\n",
       " 'GOLD',\n",
       " 'GOLD_micro',\n",
       " 'JPY',\n",
       " 'KOSPI',\n",
       " 'KOSPI_mini',\n",
       " 'KR10',\n",
       " 'KR3',\n",
       " 'LEANHOG',\n",
       " 'LIVECOW',\n",
       " 'MXP',\n",
       " 'NASDAQ',\n",
       " 'NASDAQ_micro',\n",
       " 'NZD',\n",
       " 'OAT',\n",
       " 'PALLAD',\n",
       " 'PLAT',\n",
       " 'SHATZ',\n",
       " 'SMI',\n",
       " 'SOYBEAN',\n",
       " 'SP500',\n",
       " 'SP500_micro',\n",
       " 'US-REALESTATE',\n",
       " 'US10',\n",
       " 'US2',\n",
       " 'US20',\n",
       " 'US5',\n",
       " 'V2X',\n",
       " 'VIX',\n",
       " 'WHEAT']"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.keys()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "... however this will only access prices\n",
    "(note these prices have already been backadjusted for rolls)\n",
    "\n",
    "We have extra futures data here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "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>PRICE</th>\n",
       "      <th>CARRY</th>\n",
       "      <th>PRICE_CONTRACT</th>\n",
       "      <th>CARRY_CONTRACT</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>index</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2021-03-08 15:00:00</th>\n",
       "      <td>98.865</td>\n",
       "      <td>99.015</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-03-08 16:00:00</th>\n",
       "      <td>98.865</td>\n",
       "      <td>99.020</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-03-08 17:00:00</th>\n",
       "      <td>98.860</td>\n",
       "      <td>99.015</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-03-08 18:00:00</th>\n",
       "      <td>98.865</td>\n",
       "      <td>99.020</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-03-08 19:00:00</th>\n",
       "      <td>98.865</td>\n",
       "      <td>99.015</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-03-08 20:00:00</th>\n",
       "      <td>98.860</td>\n",
       "      <td>99.010</td>\n",
       "      <td>20231200</td>\n",
       "      <td>20230900</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      PRICE   CARRY PRICE_CONTRACT CARRY_CONTRACT\n",
       "index                                                            \n",
       "2021-03-08 15:00:00  98.865  99.015       20231200       20230900\n",
       "2021-03-08 16:00:00  98.865  99.020       20231200       20230900\n",
       "2021-03-08 17:00:00  98.860  99.015       20231200       20230900\n",
       "2021-03-08 18:00:00  98.865  99.020       20231200       20230900\n",
       "2021-03-08 19:00:00  98.865  99.015       20231200       20230900\n",
       "2021-03-08 20:00:00  98.860  99.010       20231200       20230900"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.get_instrument_raw_carry_data(\"EDOLLAR\").tail(6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Technical note: csvFuturesSimData inherits from FuturesData which itself inherits from simData\n",
    "The chain is 'data specific' <- 'asset class specific' <- 'generic'\n",
    "\n",
    "Let's create a simple trading rule\n",
    "\n",
    "No capping or scaling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sysquant.estimators.vol import robust_vol_calc\n",
    "\n",
    "\n",
    "def calc_ewmac_forecast(price, Lfast, Lslow=None):\n",
    "    \"\"\"\n",
    "    Calculate the ewmac trading rule forecast, given a price and EWMA speeds\n",
    "    Lfast, Lslow and vol_lookback\n",
    "\n",
    "    \"\"\"\n",
    "    # price: This is the stitched price series\n",
    "    # We can't use the price of the contract we're trading, or the volatility\n",
    "    # will be jumpy\n",
    "    # And we'll miss out on the rolldown. See\n",
    "    # https://qoppac.blogspot.com/2015/05/systems-building-futures-rolling.html\n",
    "\n",
    "    price = price.resample(\"1B\").last()\n",
    "\n",
    "    if Lslow is None:\n",
    "        Lslow = 4 * Lfast\n",
    "\n",
    "    # We don't need to calculate the decay parameter, just use the span\n",
    "    # directly\n",
    "    fast_ewma = price.ewm(span=Lfast).mean()\n",
    "    slow_ewma = price.ewm(span=Lslow).mean()\n",
    "    raw_ewmac = fast_ewma - slow_ewma\n",
    "    vol = robust_vol_calc(price.diff())\n",
    "    return raw_ewmac / vol"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Try it out\n",
    "\n",
    "(this isn't properly scaled at this stage of course)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "index\n",
       "2021-03-02   -1.961088\n",
       "2021-03-03   -2.065046\n",
       "2021-03-04   -2.260685\n",
       "2021-03-05   -2.515280\n",
       "2021-03-08   -2.784115\n",
       "Freq: B, Name: price, dtype: float64"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "instrument_code = 'EDOLLAR'\n",
    "price = data.daily_prices(instrument_code)\n",
    "ewmac = calc_ewmac_forecast(price, 32, 128)\n",
    "ewmac.columns = ['forecast']\n",
    "ewmac.tail(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 0, 'Time')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 40512 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ewmac.plot();\n",
    "plt.title('Forecast')\n",
    "plt.ylabel('Position')\n",
    "plt.xlabel('Time')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Did we make money?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19624 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from systems.accounts.account_forecast import pandl_for_instrument_forecast\n",
    "account = pandl_for_instrument_forecast(forecast=ewmac, price = price)\n",
    "account.curve().plot();\n",
    "plt.title('Profit and Loss')\n",
    "plt.ylabel('PnL')\n",
    "plt.xlabel('Time');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[('min', '-5.81'),\n",
       "  ('max', '5.141'),\n",
       "  ('median', '0'),\n",
       "  ('mean', '0.01502'),\n",
       "  ('std', '0.5036'),\n",
       "  ('skew', '-0.1824'),\n",
       "  ('ann_mean', '3.846'),\n",
       "  ('ann_std', '8.057'),\n",
       "  ('sharpe', '0.4773'),\n",
       "  ('sortino', '0.5659'),\n",
       "  ('avg_drawdown', '-11.37'),\n",
       "  ('time_in_drawdown', '0.9738'),\n",
       "  ('calmar', '0.1078'),\n",
       "  ('avg_return_to_drawdown', '0.3382'),\n",
       "  ('avg_loss', '-0.3198'),\n",
       "  ('avg_gain', '0.33'),\n",
       "  ('gaintolossratio', '1.032'),\n",
       "  ('profitfactor', '1.107'),\n",
       "  ('hitrate', '0.5175'),\n",
       "  ('t_stat', '2.935'),\n",
       "  ('p_value', '0.003342')],\n",
       " ('You can also plot / print:',\n",
       "  ['rolling_ann_std', 'drawdown', 'curve', 'percent'])]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "account.percent.stats()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
