Skip to content

Instantly share code, notes, and snippets.

@yhilpisch
Last active September 18, 2022 18:06
Show Gist options
  • Save yhilpisch/ff4722776b0c10ab44e12d8716045795 to your computer and use it in GitHub Desktop.
Save yhilpisch/ff4722776b0c10ab44e12d8716045795 to your computer and use it in GitHub Desktop.

Executive Program in Algorithmic Trading (QuantInsti)

Python Sessions by Dr. Yves J. Hilpisch | The Python Quants GmbH

Online, 26. & 27. August 2017

Resources

Slides

You find the introduction slides under http://hilpisch.com/epat.pdf

Python

We are using Python 3.6. Download and install Miniconda 3.6 from https://conda.io/miniconda.html

If you have either Miniconda or Anaconda already installed, there is no need to install anything new. You should then execute the following lines on the shell/command prompt:

conda create -n epat python=3.6
(source) activate epat
conda install numpy pandas=0.19 scikit-learn matplotlib
conda install pandas-datareader pytables
conda install ipython jupyter
jupyter notebook

Management of environments: https://conda.io/docs/using/envs.html

Cloud

Use this link to get a 10 USD bonus on DigitalOcean when signing up for a new account.

Books

Good book about everything import in Python data analysis: Python Data Science Handbook, O'Reilly

Good book covering object-oriented programming in Python: Fluent Python, O'Reilly

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"http://hilpisch.com/tpq_logo.png\" width=350px align=right>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# EPAT Session 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Executive Program in Algorithmic Trading**\n",
"\n",
"**_Event-based Backtesting_**\n",
"\n",
"Dr. Yves J. Hilpisch | The Python Quants GmbH | http://tpq.io\n",
"\n",
"<img src=\"http://hilpisch.com/images/tpq_bootcamp.png\" width=350px align=left>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Basic Imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"from pylab import plt\n",
"plt.style.use('ggplot')\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Financial Data Class"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from pandas_datareader import data as web"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class FinData(object):\n",
" def __init__(self, symbol):\n",
" self.symbol = symbol # class attribute\n",
" self.get_data() # executes method during instantiation\n",
" \n",
" def get_data(self):\n",
" self.data = pd.DataFrame(web.DataReader(self.symbol,\n",
" data_source='google')['Close'])\n",
" self.data['Returns'] = np.log(self.data['Close'] / self.data['Close'].shift(1))\n",
" self.data.dropna(inplace=True)\n",
" \n",
" def plot_data(self, column='Close'):\n",
" self.data[column].plot(figsize=(10, 6), title=self.symbol)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Event-based View on Data"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"fd = FinData('AAPL')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAloAAAFyCAYAAAAtTHQsAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3XecHVX9//HXmbslPZtk0xOSEHpHOgiKFClCsGSEryhN\n8lNpoiiICCLGghRRioJUpY0Kgoj0KhBCS4CEGlJIz6Zv371zfn/M3Lp39265m3v33vfz8fBxZ86c\nOffsJLifnHPmc4y1FhERERHJPSffHRAREREpVgq0RERERHqJAi0RERGRXqJAS0RERKSXKNASERER\n6SUKtERERER6iQItERERkV6iQEtECpoxZrwxpskYs9wYU9ZOnf2MMVFjzGvtXF9kjLHh/xqNMe8b\nY35sjHHC658Pr03ozZ9FREqPAi0RKXRnAI8AG4Dj2qnz/4CbgKnGmD3aqfNbYCywY1j3N8APc9tV\nEZFUCrREpGCFI05nAHcAdwIzMtQZCnwd+DNwP0HQlUmttXaltXahtfY64Gngy73RbxGRGAVaIlLI\njgYqgf8CfwUOM8ZMTqtzMvC+tfYdgoDsG8aYgZ1ouwGoyFlPRUQyUKAlIoVsBnC3tbbVWrsceAb4\ndlqdMwkCLKy1rwLLgZPaa9AY4xhjjgW+CDzVG50WEYlRoCUiBckYMx44ljCICt0JnB5bFG+M2Y9g\nzdU9aXUyTR/+zBhTCzQCD4T1Ls99z0VEEjK+wSMiUgDOACLAW8aY5PIIwaL4BwkCqgpgVVIdAzjG\nmD2stXOS7rsBuJFgynCFtdbv3e6LiCjQEpEClLQI/lfAvWmXLwZmGGOeIVgEfxbwQlqdGwiCsO8m\nla2z1n7cOz0WEclMgZaIFKKjgYnAn621S5IvGGPuIFgcfzLgA7dbaxvS6twNXGWMucBaW9eF793J\nGFOdVvahtba+qz+AiAhojZaIFKYZwKvpQVboGWAdwWjVI+lBVugBoD8dLIpvx+PAW2n/262LbYiI\nxBlrbb77ICIiIlKUNKIlIiIi0ksUaImIiIj0EgVaIiIiIr1EgZaIiIhIL1GgJSIiItJLCiWPll59\nFBERkb7EZK9SOIEWy5cvz3cXClp1dTU1NTX57kZB0zPKTs8oOz2j7PSMstMzyq4vP6Nx48Z1uq6m\nDkVERER6iQItERERkV6iQEtERESklyjQEhEREeklCrREREREeokCLREREZFeokBLREREpJco0BIR\nERHpJQq0RERERHqJAi0RERGRXqJAS0RERCQLu2wx/l3XY6PRLt2Xda9D13VvA74ErPY8b5ek8nOA\ns4Ao8B/P834clv8EOCMsP9fzvMe71CMRERGRAmLfm4t/zc8AMAd/ESZO7PS9nRnRugM4KrnAdd1D\ngWnA7p7n7QxcFZbvBJwI7Bzec6PrupFO90ZERESkwMSCLADqNnXp3qyBlud5LwDr0oq/C/zG87ym\nsM7qsHwacJ/neU2e5y0EPgb27VKPRERERAqU//iDXaqfdeqwHdsBB7uuOxNoBC7wPO81YDwwK6ne\n0rCsDdd1ZwAzADzPo7q6uptdKQ1lZWV6RlnoGWWnZ5SdnlF2ekbZ6Rll15ee0arkk/ff7tK93Q20\nyoDhwP7APoDnuu7WXWnA87ybgZvDU1tTU9PNrpSG6upq9Iw6pmeUnZ5RdnpG2ekZZadnlF1feUZd\nXfyerrtvHS4FHvA8z3qeNxvwgWpgGZC8QmxCWCYiIiLS92xc36Pbuzui9S/gUOBZ13W3AyqAGuBh\n4B7Xda8BxgHbArN71EMRERGRfFnfs1G3zqR3uBf4PFDtuu5S4DLgNuA213XfBZqBUzzPs8A813U9\nYD7QCpzleV7PxtxERERE8qW3Ay3P805q59LJ7dSfCczsSadERERE8s36Pv6fr+xRG92dOhQREREp\nbi3NKafO+Zdj16dnvOqYtuARERGRomQ/+YDoDTOxdbXda8D3U8/7D8I56LAuNaFAS0RERIqSfWsW\nzHkVe/dNwXk0iv/co9h338Ram72B9ECrvLzLfdDUoYiIiBSnSLALoP3kg+DzzVewd/8JCxj3DMwR\n0zq+3097n2/osC53QYGWiIiIFKempuAzTDpqIhHi41ifLsx+f+y+k2ZgPnMAZvDQLndBU4ciIiJS\nlOxTDwUHG9bi3/w77JoViYtVnRidik0dlldgqkZ0qw8a0RIREZGiY+s2p56/9iK89mKiINJxCGQ3\nrcc+92hw4nR/XEqBloiIiBSfzZs6vp5lD0P/9z9PTC86kW53Q1OHIiIiUnxqUwMtM/00GDkmOKmo\naLvQPV3yGq4ejGgp0BIREZHiU7sx+CwLUjKYSdvg/OQqnJl/DqYNs4xopdCIloiIiEiCjU0d9h8Q\nfFZUYgYPwYwaGwROHQRaNi1/loloREtEREQkoTYt0CpLSjbqOB1OHdqH7kkt0NShiIiISJLaTVBR\nmZj2K0t6/y9S1jbrexL7qJdaoKlDERERkSSbN8KgIZip2wfnAwcnrkUi0Nqa8TabaaRLI1oiIiIi\nCbZ2MwweivnGd3Eu+wNmSFXiYkdTh8s/BcAc8sVEWUW/bvdDgZaIiIgUn80bYdBgTHkFZsLk1Gsd\nTB3a//4TKiowXzoxUdiNrXdiFGiJiIhI8amvwwwYlPlaRSW2sSHjJbvwA8zu+2GGjYCd9ggKh3Q/\n0FJmeBERESk+zU1Q2c6U35ChwYhXJvV1MChYz+Wc/TNYsgCTvL6rizSiJSIiIkXFLl8CG9ZCeXnG\n62ZQ5kDLWgsNddB/YFCvvBwzdYce9UWBloiIiBQV/67rAbCrVmSu0N6IVlNjsHZrwMCc9UWBloiI\niBSXWDqGus2Zrw8cDM1N+A/fi31vLra1JSivrws+Y0lOc0BrtERERKS49AsCJeeUczqsZv99LxbA\nODh/uAca6oML/dtZRN8NGtESERGR4rJxPey6N2bilMzXjUk9tz7+738OG9cGlwcq0BIRERHBrlmZ\nmPqL2bAWUzW83XvM3p9tW7jgfey8t4IcW1tvl7P+KdASERGRPsk2NeFfPAN75x/jZf4j98GmDdBR\noDVyDIwa17a9N16GHXfH9MvdGi0FWiIiItLn2JXL8M+eHhzPei5R/tA9wUHViGwtBB/jJyWK1q7G\n7JNhtKsHFGiJiIhIn2PnzEo9b23FtjTHz83Q9ke0ghuCQMtsu1NKsRkzITcdDCnQEhERkb4nGm4K\nvcNuANgH7oQlnwRlVSNg5z071Yw54AuYU89LFOQwhxYo0BIREZG+qKUZjMH5wRUwZjx2+RL8e28G\nwPnp1ZiyLBmswhEtBgzCOegwzOeOip/nkgItERER6XtamqG8AmMMDB4K896CxR8DdPjGYYzZ66Dg\nYPCQ4PzEM3GuuBEzpCqn3VTCUhEREekzrLX4f/gFvPtGfPNnPpqfqLDNTplvTGO+8k3MkSfEN4w2\nZeWQ4/VZ0IlAy3Xd24AvAas9z9sl7doPgauAkZ7n1YRlPwHOAKLAuZ7nPZ7zXouIiEhp+nRhEGQB\nmGBizpxwMvZffwvKmho61YxxIpDj0atMOjN1eAdwVHqh67oTgSOBJUllOwEnAjuH99zoum4kJz0V\nERGRkmatxb/i+4mC4SMBMIcfj/nsEcFxL4xK9UTWQMvzvBeAdRkuXQv8mHgiCgCmAfd5ntfked5C\n4GNg31x0VEREREqTXboQO/c1qK9NKXcu+CUAprIfzinn4Fx8FeZbZ+Wji+3q1hot13WnAcs8z5vr\num7ypfFAcmKLpWFZpjZmADMAPM+jurq6O10pGWVlZXpGWegZZadnlJ2eUXZ6RtnpGWXXlWe06szj\nAVIytlfudwhVE7ZKrViAz7zLgZbrugOAiwmmDbvN87ybgZvDU1tTU9OT5opedXU1ekYd0zPKTs8o\nOz2j7PSMstMzyq47z8g21gNgZvyI1n0OztszHjeu7fY97enOiNZUYAoQG82aALzpuu6+wDJgYlLd\nCWGZiIiISE6YHXfPdxc6rcuBlud57wCjYueu6y4C9vY8r8Z13YeBe1zXvQYYB2wLzM5RX0VERKQU\nVfbDHPJFzO77wXY7B7mz+oisi+Fd170XeAXY3nXdpa7rntFeXc/z5gEeMB94DDjL87xorjorIiIi\npcVaC83NUF6J2X6XPhVkQSdGtDzPOynL9clp5zOBmT3rloiIiJQ6u3Qh/uXhPoQVFfntTDdpCx4R\nEREpSPaZ/8SPzS575bEn3acteERERKTgWD+KnfcmAM6l12EmTslzj7pHI1oiIiJScOytv4d1NTjf\nubDPBlmgQEtEREQKkJ39fHDQR6cMYzR1KCIiIoVn+EjM9rtiKvvluyc9ohEtERERKTwN9dB/QPZ6\nBU6BloiIiBQU6/vQqEBLREQkI7uuhui1l2JrN3X+ntZWbGtLL/ZK+owNa8FaGFyV7570mAItERHJ\nOfvYP2D+HOwrz3b6Hv8X5+Gfm5oj2//X3/Bv/l2uuycFLvZnbrbbOc896TkthhcRkdwrKw8+uzJC\nteLTNkX2Px4A0WiUyHcvytpE9NKzMLvtg/O1Uzv/vVJQrB+FBe8HJ+Mn5bczOaARLRERyb2mpuAz\nkqN/z7/5MralucMq1vdhxafYxx/IzXdKfixfAoA5fBrG6fthSt//CUREpPA01AWf0dZOVbf1tdkr\n1WWps2l9p75LCtzaNQCYfQ/Oc0dyQ4GWiIjknG2oDz6ff6xzN9SsTtwbjQafaSNY/p9+0+k2pO+y\nmzcGB4OG5LcjOaJAS0REci/2y3JtJ4OfNSsSx02NANh/35taZ8H72JXL2m3Cdva7pLCtWQWOA0OG\n5bsnOaFAS0REci8WaAF2zqys1VMCqMaGoOyj+W3rLf64/UbWBVNODC2OX9Clyn74LkzaBlNZme+u\n5IQCLRERySnr+4mgB/Bv+FX2m5IDs0fuw25YCx+/B7vtg3PZH3Bm/im49vA92A/nddxG7I1H6XPs\n5k3w8fyiSOsQo0BLRERyyr7yTNsy38d/8Qn8h+/NcAcpC93ti09gn/kPAGb8JMyEyZhR46BqOKxe\ngf+7nwT1olGstYk2ajcHn51cgC+Fx3q3BgfVY/LbkRxSoCUiIrkVvnFoTjwTTPhrpqUZe9f1bddd\nhWzd5tSC8A1Cs//n40Vmxz3ix/5fb8D/zpexT/+7bRvhYnrpg0aOBsDsfVCeO5I7CrRERCRnrLXY\nt2bBkCrMocdiTpoRXFhXk6gTvr7vv/YidtFH2LpaeOf11HZeejo4KK9IFO7ymcT1Fx4PPsOEpgDE\ntvtRoNV3xaZ9K/vntx85pMzwIiKSOwvegw/nYf7v/2EcB1vZDwD/0u/Fq/gXnYHzpwexN/8O2147\nMRWJBdFmzwPa1q/dhG1txZSVJU0dKtDqs/zwz64IEpXGFM9PIiIieWcXBW8Fmr0ODAock7Gef2OG\nBfI779m2rDyxsN2Ul+Nc72H2PSS1rfNOCvJ2xaYOfQVafZbvB58KtERERDLYtCH4JTm4CgCzw26Z\n6739Wpsi59Avta1XnvqKv6nsh3PmBTg/uAJz6LFBYXMT/m3XJgItLYbvu6I+GAdjMgfofZECLRER\nyZ3mJqjsF/9FaapGYE49r3P3VqXmvzIHH4kpz5yqwey4e+qGw3NeDT4rKsD3U99GlL7DRotqNAsU\naImISC41NkC4LismJfHk2Ikp15wLk7bVSUs06nzr7A6/yoxsmwLAHHJ0cLBkQSc6KwXH9yFSXKGJ\nFsOLiEjuNDdBRWqglbygnbETYcWn8VOzzU6w/a6wbDGmagTOFTdhlyzAjB6X/buGVbcpMp8/GvvU\nQ9jFH2MmbdPdn0LyJeqDieS7FzmlQEtERHLGNjVCv7RAK2mEywwfGX9z0BwzHYDIBTMT18eMx4wZ\n36nvMmMnYE4/HzZvwP79digrg5FjgsBu+afZG5DCY4tvRKu4fhoREcmvpsaOR7SSfok6X/5mj7/O\nOeDQxMjWkCqM48DQYdin/41trO9x+7KFRbVGS0REpH2ZRrRiC9qNgzl8WnC86945+0oTS2o6YFDw\nuWYlAPbZR3P2HVpcv4X4PjjFNXWoQEtERHKnqbHNYvj4XOG4iZiq4URueZjIuZfm7jsrYtnjwzcd\nv/7t4HTTxsz1uyh6/S/xzz85J21JFr5GtERERNrX1IhJnzocHkztmc8f3TvfGc+1FUR0zuHHw5jx\n2PVrctP+3NlQtxmrjPO9yn/sn9j/PQmbN+W7KzmVdTG867q3AV8CVnuet0tY9jvgOKAZWACc5nne\nhvDaT4AzgChwrud5j/dS30VEpNBkmDo0AwcTueXh3vvO2IhW8vTe0OGwYV1uv6d2U5sUFJI79ulH\ngoMiSzjbmRGtO4Cj0sqeBHbxPG834EPgJwCu6+4EnAjsHN5zo+u6xTXZKiIi7cu0GL63RcJfM0mB\nlqnKfaBlH/17TtuTNK3NAJgjT8hzR3Ira6Dled4LwLq0sic8z4uFnLOACeHxNOA+z/OaPM9bCHwM\n7JvD/oqISIGy0Si0trRdDN/rwu1akke0qkbAxnU9XsQeve7n8WP7zCOaPuwl1lqo3Yw56qs400/P\nd3dyKhdrtE4H/hsejweSk5csDctERKTI2Tv+EBxs6RGt/gMBMBOnJMqqhkNrKyxZgF2+pPttv/tm\n8LlTuOF1S1P325I27Krl+Pffij8jfBu1eLY4jOtRwlLXdX8KtAJ3d+PeGcAMAM/zqK5um+FXEsrK\nyvSMstAzyk7PKDs9o+wyPSO/dhNrZj0LwOBxE+i/JZ9hdTXNv7yB8qk7YPr1B6Bx4mQ2Av4vfwDA\n6Adf7nKztrWV1eHxwB13pW7+WwzvV0nj/55gwLHT292HEfT3qDPKysrwL/lO/Lx85z0ZcvyJlBXZ\nc+t2oOW67qkEi+QP8zwvNja7DEjeyGpCWNaG53k3AzeHp7ampqa7XSkJ1dXV6Bl1TM8oOz2j7Er9\nGdmGevyf/j/Mfp/DiaVJSJP+jOymDfi/vTB+Xrv1jtRt6Wc4eiLU1gX/A2wk9ddbd/5Mo2ceHxyU\nlVEf5uhae/ct2Ocepfa+WzHf/B72L1fjXHcvZsDAlHtL/e9RZ4wYMjh+bNwz8I+YxgaAPvDcxo3r\nxBZRoW5NHbquexTwY+B4z/OSU+8+DJzoum6l67pTgG2B2d35DhER2fL8ay+FzRuxT3X+LUH7Hw9W\nrwDAHD6tTdCRF1UjctaUOfAwiISjV5vD3FxNDdi/XA2AfempnH1XX2P9KP6sZ7F+19euNc+fC4DZ\n52DMocfmumsFI2ug5bruvcArwPau6y51XfcM4HpgMPCk67pzXNf9E4DnefMAD5gPPAac5XmeVg6K\niPQVCz/s+j2xzOyA8/UzctiZHuifw2AvEgn2UQRsU0Oby/blZ3L3XX2EbW3FrlqOffIh7K3XYmc9\n3+U2mufMhrIyzCnnYMqKd+vlrD+Z53knZSi+tYP6M4GZ7V0XEZG+wUajmEgnMvRUVGSvs6WVpa6f\nsosXYCZN7V5bkXJMeXmQDnXD+rbXG+q6124f5v/mx7D440SB07lV7La1Jdjwu3Yj0eVLYPR4TPpO\nAkVGmeFFRCRhYGLdDPW1nbsn9tbfvp/rhQ51U9oIif/L87Hz3+peWxEnMXVYuxHGT8L5432J680l\n+CZicpAFiefTAetH8b/7Vfwrvo9/7WVE19fA4KG91MHCoUBLREQAsOvXQt1mmLRNULC5k3sFhm/6\nma98q5d61nWZRuLs6pWp58uXEP3DL7C1bbd8ScmX1dwMA8MNqzesg7JyTL8BieubN5bUptPx9VjJ\nQVJngs05qUu2Wz9+HzNoSA57VpgUaImISOCTDwAwuwd5pv07/9i5+2JbphT6Opu0ETr/rzfCO6/D\nssVt67a2pN43YVLiPFNah3ndHC3rA2xTWhC1+BMAjHs6zg+uCMqyBFrWWvxYZv2ttk5cKIEtjRRo\niYgIAP6dQcJRM3FyUPDJB517myw2+tOZ9Vz5lD4VWrcZAPvai21HpJICLVtXG4xghZtjp6//AiDD\nIvliYD9+D//s6dikQNIuXQiAmbojTNkuKMz28y9fAos/xkw/DeenV2P2OojyXT6DOdbtra4XDAVa\nIiISaAiz9YxO2tBjZcZUiKn6yohWXVqgtXo5APb5xxKZyWMakwKHWIAWy3gfe8ty6g6JOpmCryJg\nlwejff7T/8Y2hn8/Vi0Lft4RI6GyX/C/jRleEkhu553XATDb7IRxIjjfuZDhV1yP0RotEREpBbY+\n6c25pEDLfjgv+82tYaAVKfBAq6kxfmg3rU+MxMXKkp9B0puEZnSYnDIWTFkfAOfC3+L8PJhetc3N\nvdDh/DNDqoKDd17Hv/w8AOzKZTBqLMaJYIwJcpatX9txQ7FnHxsBKyEKtEREBPvMI8HBHvtjHAfn\nsuuC8rtvwvpRbFMj0Z+cSfTqS9pOsxXo1KFz3T3xhfoMHY5NCrRY8knbG2pWxQ/t0kUAmONOwnzj\nu0FhONUY2//QGJMY3WopzkArJRitWUX0pl/Doo9gzIRE+bAR2OVL2n0hwK6rwT5yPxA+sxKjQEtE\nRGDjOgCc6acG5+OSFn83N8GalUEg8v7bbRc+rw12BDROYQVaZsCgxOjc0CpoasR/9O/YNSuxDRnW\nFNUkvZW4Ksx0f9BhiTxP68OtYZIXcFcUd6BlW1pSC958BTaux+y4e7zITN4WVnyKnf1C5kYWdSMJ\nbhFRoCUiIlBfDyPHYEYF02TGSfr1sHoF/uXnxk/9pLVO9vX/FfQWNM65P8M56+IgFcGC97AP/hV/\n5g8hXG9kpp8eX2tl1yRGtGhugvIKzIhRbdv82e8TJ/0HBiN5Kz7t1Z8jb1pbMhabsYkRLTPt/4KD\nVcsz1o2nykgKzkqJAi0REcHW10K4cXI6/4rzU+s21GH9YJ2Snftar/etJ8yQYZg99oeKysRasrrN\n2L/dGFw/6HAiF10Z/Ow1q7B1tdgNa4O36GLTjuli65YAU9kP85kDsS8/nZp7K8fsuppebb9dYaBl\nDj4ytXy7XeKHpqw8GNlLnppNFr5k4Zx6Xq90sdAp0BIRkWD90cDUQKvNL9dQw5MP43/va9iaVdja\nTiY1zbM205phoEhsWnDgIKivw7/xV/g/Og37/GOJa7E2vv1DzJe/2Xad0dbbBcFE7K28HLNLFuBf\neDr2pSd7pf0OhcGp+eopmK+eAoDzgyvaPgMTwSZNvdo5rxK94nzswo8Sb7P2H0ApUqAlIiJQX4dJ\n3n4HMEd9JfU8zHlU/28vSOmwbHHf2X6mnYX68c2MyyuwmzfAh+8mLqalq3D2+xzOMdPbNhJL+7Do\n47bXesiuWo5dGiZUnT835+1nFZs6LCvHfPErOH9+MGV9VlxTA7z5SjAyCvg3zIQlC/B/9UPsgveC\nlwbaGyEscgq0REQkyBU1YGBq2dDhiePd9sHsfVBwHGZGt+vXBtvT9AXZFuqXlcN7qYGMOfiLnWt7\n7RoA/Jt+3Z2etcuuXYN/yXewt4drwvKRpyz251tejjGm/Rcexk4EwD/v/4JRrGTvvglDqkryjUNQ\noCUiUvKstWGglbZGq6ISTPBrwpRXQLi/X+wXpn3u0b7ztp2T5dfdmhVtiswR0zJUzGBwuF/fwMxr\n3LrLfvB2akE+8pS1NkOkLOsbpWavA+PH9o2XgrIZPw4KWpqhanim20qCAi0RkVLX1BjkS0pfo2VM\nYrqnvCIY4YpEsLGs6csWQ83qLdzZbsqW46shbX3VmPGdHoExhx4bfO77ue70rF32rVdz2l7W78uU\nB6ulJfPejumSpp3t4w8AYHbYNV5mqkb0uH99lQItEZES5j/5EPavNwQng4a0rRDbIqWiAlNeDmO3\nSr3eV/b4yzCi5dz4z3arR664qdNNm0gkWOidw9E929gAc2allm3qeJubnvBfexF/xjT8v1ydeqGl\nOZGUtSP906adK/unbK9j+8pavl6gQEtEpIRZ79Z4okkzrLrNdbPV1sFB+Ms2OX9Sn5Jh6sskj9SE\n2+s4F1+N85u/dL39ikrshrXYRR/hz3q2u71MSN4OKGb1yrZlOWDffg178++C41efx3/634mLLS2d\nC7QaUwNus18wuud858LgfOvS23onpsA3phIRkd5iY1vKQLDQOtMvw0lT4fX/Jd4uTM6KHjKnfR+z\nz8G91MscSRvRMtNPT7185W3Q0owZPrJ77ZdXwBsv47/xMgD+oUd3r52YWE6q8orEGqe1q7F+NOcZ\n+P0/XhEcDBgE9bXY+26Bw47Df+R+7CvPwqixWdswB3weO2dWsHMAxDPmm70OwrnqzsyjpSVCI1oi\nIqVqcZCOwJx+PpGbHsD0a5vnyIRThXZd8GZdxkBr3MTU0aFClL5GK239lRk8tPtBFgQvDiSx6Wu+\nuqo5CLTMKefgXHQl5riTgpQa62p61m4am7S/oznh5GCD6Mp+2LmzsQ/dHWyg3Yk/WzNgEE5s8Tuk\njIKZocOC6dUSpUBLRKRE+f/xADDb7tR+pcowgIjteTc0w9tjnRjxyLu0USCz6965bT8t9YJtyDD1\n1xWNYaA1pAozdQfMyDFBuwve71m7aey8t4LvOfhIzIGHYb5wbLAn5C1Ja7U6M3UIMDBpnVZFJ+8p\nAQq0RERK1Yfzgs8Mo1Rx5ambJpsMr+mbdrbuKSixQKusnMgtD2PGjM9t+yuXpZwm7wfZVXbJJ8E0\nHCTe+gz3oLTpi9V7asM6MAZz8vcwlZWYMB9WyksOnRytNE4E89kjgpO0Eb5SpjVaIiKlrHp0kCOr\nPeMnwaDBOMeHGwd3FJQVstgard7KRRVbw7b7vjB3NjbTYvZOsNbiX/H9REEs6/zw8EWFcGQrZ1Yv\nh34DEpuI77IXVPZPC7S6MDoVD7BKMzlpJhrREhEpQdZacBzMvod0WM/060/k2rsxu3wmKKgeTdnW\n22O+eVZwnrYfYMGKhL/usiUu7a4wlYHz5W8BxLei6Sr/ku+kFvQLnq8xBvbcP3uG+y6wc18L3jhN\nmuY0ZWWYw44LTmKbZ3cn0CrhdA7pNKIlIlKK3psbbKycvu1OFqaikhFX305NTQ124pS+M8JVGU7B\ntfROAOCyNMJ3AAAgAElEQVRcel0QXIRpIjZefSnO7+9us39kVqvTMtQnBbJmh92wb83CfjS/43V1\nnWTfeiVjuTnyBMw2O2JnPYed/XzHI57p9+5/KPaxf2I+c0CP+1csNKIlIlKC/Hv+DICpHt3tNsyU\n7Xr2pt4WZGJTb62tvdN+1XDMqLHBKFAYbLF0UdcbKivDfPErmCNPgBGjUhKBmoOOgEGDsS88npM+\n243rgoOkxKIAZuAgzK57JV6EiI1sdYIZv1WwBm7cVtkrlwgFWiIipWjzxiD31Z4lMvKQIRlrbzBl\nZTgXzAxOurjhtm1pDgLB/gNwpp+O8+tbUtIimMpKmLg1dtWyDlrp5Hf5frDZMwS50jKJ5fLK9bqw\nEqNAS0SkxFhrobEeRo5NLIIudsO3TKAFJNYpdXVLnthaqXA6N9Nei2bQEOjBG41xmzbED50zf5Sx\nig3r9GTUUxRoiYgUDdvSjH/3n7Crl3dcsbk5WJ/Vv/+W6VghGLIF15KFa5psFwIt29QI9WGS0/5t\nE8fGRcqCxKU9Fe4KYGb8GNPeOr2N4d6KW2g0sFgp0BIRKRL2kfuxzz2KfenpRNniBdgN61Irxt6I\ny5AJvljFR+522qP3vyy2eLyTb97Zj9/DP9uNL0436Rs0JyvLcaA1sP3vMgccGhyM0tRhT+itQxGR\nImBbmrFPPhScJC1e9n95PlT2J3L9/YnKKz4FyH3SzgLn3PjP3kvvkCyWFb21pVPV7fIlwecDdwUF\naYvTU0QiEI32pHeBWN/K208sao76KuaIaZiyAt9eqcAp0BIRKQL2rVmJNUGtLfiznsO++ERwnpx8\nErCxNT4d/UIvQltsP8b4iFYX12gBbL8rTMmwuXdMWXluRrSifvDZwR6ExpjEG5TSbVkDLdd1bwO+\nBKz2PG+XsGw4cD8wGVgEuJ7nrQ+v/QQ4A4gC53qel5v3UEVEJCO7dg32lqsS5598AG+2zZFkm5rA\nRhO5pLRNSu+Ib1sUPGf//r9gF7xP5OKrMtcPp/Eg2Hcy0yL4uEgkNykq/GiiPelVnRlDvQM4Kq3s\nIuBpz/O2BZ4Oz3FddyfgRGDn8J4bXdfVn6KISC+ys19ILXj79TZ1/Efux//1BfiXnZ0YaelKxm/p\nNBOJBAFMuBG3fephWPhh8LZnJjWrE/du1U6qhZhIWW6mDmNt5DDTvGSWNdDyPO8FIG0lJdOAO8Pj\nO4ETksrv8zyvyfO8hcDHwL456qtIyfAfvhf/v//Idzekj7BPBWuzzLfODkc8wvU3Sdm57UN3w7LF\nsK4GPl0YFGpEq9eY8sq2U4frazLWtR/Ng212wrn8esye+3fccPjWYXrQ5j/+ANGZP8QmjY51xCrQ\n2mK6uypwtOd5sX0CVgKxJBvjgU+T6i0Ny0Skk+yGtdh/34t94C7smpX57o4UOGst1G3GfPYInIOP\nTGyaPGAgke/+JOMaGzvr2eCgQiNavaaiAvvUQ0TPPB5M8KvWv/TszHUb6jGjx3Uum3psqi9tVMu+\n8TIs+gj/rhuwn3yATd/KJ1avtZXoL87D3nxl2J6SD/S2Hi+G9zzPuq7bznho+1zXnQHMCNugulp5\nOjpSVlamZ5RFsTyjhndfY1N4PGjFYvrvuEvO2i6WZ9Sb+sIziq5fS2TYCAD8+jrWRKMMnLo9A6ur\nWV1egW1uwqnsT3V1NavI8H/PzU2Y/gOoHj2m4/VA7egLzyjfair7EQ+FbLjwvKkh43Nb7UfpN3gw\nQzrxTOuGDqUWqB5WhUnaB3FtxKEVcBZ+gP/rIAHp6AdfbnN/87tvsT42ogkMG1FNWZ7+LEvl71F3\nA61VruuO9Txvheu6Y4HYBPMyYGJSvQlhWRue590M3Bye2pqazEOqEqiurkbPqGPF8oz82f+DgYPB\nj7J57uvU7bZfztoulmfUmwr9GfmznsXeei3OJddiJk3FLvkEgLryShpqauJTR35TQ/Bz+H7GduzI\nsaxdu7ZbfSj0Z1QQMq1/22mPjM/NNjfR2BqluRPP1G8MFtjXrFqJGTAoXh7dECQX9dcn/kwzfVf0\nrzelnK/ftAlTnp8/y77892jcuHGdrtvdMcOHgVPC41OAh5LKT3Rdt9J13SnAtsDsbn6HSEmyK5bC\npG1g4hTs8k+z3yAlxc5+Mfhc9FHw+dF8AMw2O6VWrA+3cwnX8jjX/A123hPCTaDN6M7/opCuM5nW\nv/VLZOK39XXYD+cFJ62tiSnfbMrCeukL4ms3tXmD0GZaNL8qbdcArdHqdVkDLdd17wVeAbZ3XXep\n67pnAL8BjnBd9yPg8PAcz/PmAR4wH3gMOMvzvBy8HiFSQuprMYMGw4BBwX50Islii52XLADAfvQu\njBiFGREEUGy9fWr9WPLSAQOJfP9yzPbhVPSosVugs6XLxjZkTpYU+Ph/+g3+736CbawPXl7obI6v\nWDCVlOLBtrZAYwOMGJVad+6rbe9vacIcekxSe1qj1duyhtCe553UzqXD2qk/E5jZk06JlCLrR7GP\n/wvWrApGHlqaYeki7IqlmLET8t09KQC2vg4++SA4aWrEtrbCB+9gdtk7Xse56EpYvzae1NK58LfY\nD98NUg5AIlFl+i9lyanoigyj0XNnY9euxowYBQveD8piyWM7mxg0EtZLTloatmH2/iz2vbk4x0zH\nv2Em/k2/wbnh7/HRNbtkAdTXYdcnJRLQiFavUygrkmfW94O3C+e9hX3gzmDh7IBBsOhjAPx/3pHf\nDkpBsNYG2d9j581NsG411G6GHXaNlxtjMMOrMSOD/enMyDE4Bx2eaCi2Bc2W2IpG2vB/+QNsY0N8\n7Zx/0beDC53988j01mFt8PqMmTglSIq6e1JWpXBU3FqLf8cfgrKaVYnrCrR6nf5LE8kzO/sF/Itn\n4P/hF4nCgYNhQLjZazuLmaU0WN/Hrl6BP2Ma9o2XEhfemgWbNgBghgzrfIPtpAeQHAsDGOesi1PL\nazdhH7m/zT6IWROVxurF1mglZ4cP/x4wcHBQxxjMad8HwM6fEwR269YE+dP69cc552dBzrX+A5VL\nbQvQXocieWT9KPaVZ9peGDAo+D9BgHdex3/gTpyvnNK2nhQ9+/fb4wlJeSc147t/b/jidtXwTrdn\nTvgGtqEes+/BueqiZFB94/2sW7EMM2EK5utnYO+/NX7Nrl4e5NYK0z6Ygw7H7Lxn5xqOLZpPmjq0\nsenkiVPiZaZfPyxgb70Wm/RdzvcvD0Y8Dz4SDj6y+z+gdJpGtETyyP7rbzB/TptyM3BQyr807X//\nuSW7JQUkHmQli62vWvJJ8BbahMmdbs9UjSDy3Ysw/QbkpoOSUWT0OMyEIPBxDp+WenHlMkjOb9a/\nC38W4YikffzBYI0eYD94ByZMxgwakqhXmXjDMZ7HC2B8J5KiSk4p0BLJozYBVGwUa8AgzE57bPkO\nSUGx1mZcJO388qb4Ohxz8Be7lXRU8mjFp0HajXAdXXLah6zCqUM7+3nss/8J/o68NxczaZvUelN3\ngOFtk4EqwN7yFGiJFILPHIjz3Z/AlO2C8/4DMEeeAGO0g1Up8R9/APve3ETBhnXQ2oI5xk2pZ8rK\nMbFAa/vc7RwgW5Y54WQYPBRzYMaX+DPrn0hSyro1wVo9wL7/dmrb/foT+e1tEMsev90uODP/3NMu\nSzdojZZIntikxbDOdy7EGIOz/a7Bmq0Jk4Pzb1+A/8vzu/YvXumTbHMT9h93YIHILQ8HZe8F08pm\nt72xj3op9c1Bh2PGTsRss+OW7qrkiNl1b5x9D+naTbG8aAANdfj3BMGTOdbNXL+yHzQ1YsZthVHu\ntLzQiJZIvqxLbD0Rm/oxAwfhHH584nzSVMznj05kg5bitXRRmyL7VBBwMSGxyNn50a8BMI6jIKsP\ncq6+E3PCyZhDjsJ0ZW1WTNXwYFoQsC89DRuDnFhmn3ZebohNPQ8e2p3uSg4o0BLJl7XBFqHOD3/Z\ncb0hw6CuFrvwQ6JXnI+tr90CnZMtLWXKkHB91trVsNXWmMpKzBHhguptd8pwtxQ6Z+afcH56NWbI\nMJxjXZxvfq9b7ZhIhMhFV8J2SVPGI8dg2hv1ji2QH6JAK18UaInkiY1t/jqs493rzbiJYC3+X66G\nJQuwb7/eYX3pe6zvB2+ghqI3/RoWvAf1dZjDjgfATD8d588PauF7H2VGjcNM3jZ37e33ucTxDru1\nXy+24L6zeylKzinQEsmXhnDT34GDOq43Lnwde/WK4LNOI1pFJxzdjHvzlSBHljGY3fcBwiSUyuIt\nIeeQL2IO+EJwkrxuK00sIDOj9WJNvijQEsnAWpu9Uk/Vh4FWttetR6YtYLXK6F10Ypm9t9s5Ubbk\nk+CNtDDbt0gbsRdqOgq09tw/WBeW/HdLtigFWiJp/Af/iv/Db2F7e+Sovg4qKhNbarQj/bp9+/V4\nokLp++z6tfjXXAKAc9TXMJ87Si8/SKfYpkYATAeBVnC9C1s0Sc4p0BJJYlctxz76d9i8MTFV11vf\n9dRD0NzUucq77p04fm8u9pH7eqdTssXZl5+G5ubgZPxWOCd/D/PlbwbnGZKVisSYweFC9y5swSRb\nnv7ZJJLEv/WaxMmm9b32PbZmVXCQZSF8jJm0DTZ5n7u1a3qhV5IXyWv0wlfwzWHHw6aN7b+yLwKY\nL50IE7eGqUrzUcg0oiWSbOGH8UO75JNe+QrrR7FhNmfn/F906h6zz2cheUseJTAtGvbuPwFBlnBT\nXhEcRyI4XzsVM2lqPrsmBc5Uj8Y57Di9iVrgFGiJJIvtDTZyDPaTD3rlK+w/78J6t8KAQZ3eYseM\n24pIclDWX4FWMUh+6cIcMz2PPRGR3qKpQ5GQ/9JTQbb27XaBSCSRfiGHrLXYJx4EwHzp693+l6hd\ntiSX3ZJ8WfEpAOaUczQqIVKkNKIlErJ3/AEAM3QYVFRCUycXqrfXXksL/j9ux9aswr/5d9i1q2HN\nyuA7pp+OE8v03R1vv9ajvklhsB/OA8Bsp42hRYqVRrREANvSnDgZVo3ZsBa7dCF20UfYBR9gDvxC\nl/cl8//8W5g7Gzvredi4DutHMZHgLTIzcUqWu6UkrFwarLeLZe8WkaKjES0pebalGfvyM4mC4dXB\niBbgz/wh9r6b8W+5qmttRqMwd3ZwEtv01YlgZz8flGXJe9Ou3fclbCz4DunT7NrVUDVC04YiRUyB\nlpQ8+9Dd2L/dmCgYMgwq+6VW+uCdrjW6vqbt97z2YuJkzISutReKnH0J5uTvgfUzfof0Hfbj+TDn\nVU0bihQ5BVpS8my4birGVFbCoLRtTzqbWDQmLc+VOfjIxPH+h2Ii3d+zzmyzEwD2jZe73Ybkh928\nkehZ07Hz52BnB4G3OeHkPPdKRHqTAi2R5H0NR4yCbXaEQUN71mRsk+DtdwXAfPEriYv9+mW4o/PM\n+K1gwmRsuNBe+g47701obsJ/5pHgeLd9Etm9RaQoKdASWRMEK+ZLXyfym79gBgzCDGkbaHVpTVQY\naDnnXYbz53+lbqXSxUX1mZgDDg36FFsHJgXPf+6/2FuvDU7mzobVK7RhtEgJUKAlJc2+NxeWLsQc\ndhzOtG8kLmQa0dq0IXt7DfXB59JFMGIUprwC4zhQnvSC78Ste9hrMPseEhwkBXC2pYXo5efi33dL\nj9uX3LP//UfbsnXaSkmk2CnQkpLmX/Oz4GBo2qasmUa0/vv3DtuySxfin3si/qzn4KN5mO12TlxM\nCojMlO26292E8uCtSN6bmyh7/21Yugj79L/xw6SoUkDGTwo+d/lMvMg55mt56oyIbCkKtKS0jZ0I\ngNn1M6nlgzMEWs8+2m4ztrUVO++t4PjWa2DzRggXrQOpU4cjRnW/vzEVwZ549o2XsO+/HZQ1NST6\n8+ITPf8Oya3aTbDTHjjuGTBlO5yr78TstGe+eyUivUwJS6WkmXFbYa3FTEhLINp/YNZ7bVMj/m3X\nYiZOwT50D0zdIbXt5FGy5BGtXORMSp4yXFeDCT/jfL/n3yG5tXE9Zsx4zNiJRC7uWl42Eem7NKIl\nJc02N8WTkyYzjoOZflqiYOc9wZiUTYBZ8gm8+UoQZAEseD+1kaS3C42T2//UUoK11pbgc90aqOyP\n+fwxUF+b0++TnrHWwqb1QY42ESkpCrSktLU0x6fh0pld904c9x8YpIH4cB42GsXW1WI/eLvtTbvs\nlThOD+B22hNz9Fdz0WsAnO9fHhy0BIGWXbcmyGpfWdn1vF8lzjY1xl9k6BX1tdDaClUKtERKTY+m\nDl3XPR/4NmCBd4DTgAHA/cBkYBHgep63vke9FOktzU3BXnOZJGdvD1My+FddjDn1XOzzj8HCD9vc\n4nztVPx33whO0qbvIudfnpMux8XWgLWG+zTWrArWf0XKQNvzdMjWbcY+9TDmC8dhBg/B3n4ddsNa\nIhdd2TtfuDrcTHx4DtbniUif0u0RLdd1xwPnAnt7nrcLEAFOBC4CnvY8b1vg6fBcpDC1M3UI4fRc\n7E2xxsRCcxYvaBtk7b4vkVsexoyfFCxy/uopsPX2vdTpUCxlREsz/lMPwacLMaPHgROBaDR1mlNS\n+N//BvaR+/F/cDJ203rsyqWw4P1EotlcWx+mcahWoCVSano6dVgG9Hddt4xgJGs5MA24M7x+J3BC\nD79DpPc0N2PKM08dAonRrj0PwBz5ZZi6A3bBe23rJQU1ZsgwnKO+2usbBRsnEoxeNTdj7781KBw0\nBGLb+2hUq1PsB/NgQ7Dxt/+L7xNdl/s9JG00HN1MfvtUREpCt6cOPc9b5rruVcASoAF4wvO8J1zX\nHe153oqw2kpgdKb7XdedAcwI26K6urq7XSkJZWVlekZZdOcZrYm2UDFkKEPbua/hSy6brvsFI/Y7\niMjRJ1Dr3U7dvYmEoAOmnUTLh/OpuuAKnDxspbK6ooL+ZRGaxm9FdNkShh91Ak0vP0MtUD2sCpO2\nObb+HoFtaSZ53MrenDRdWF/L5utnMuJn11D/8H30++zhYCAyfGSPvrNh4AA2AcNGVFNWBM9ff4+y\n0zPKrlSeUbcDLdd1hxGMXk0BNgB/d103ZXdUz/Os67oZ5y88z7sZuDk8tTU1uf9XZDGprq5Gz6hj\n3XlGfkMDTb5t/75d9iZyy8Os94GaGuyI1H83NH3pJADWNTVD05b/87Fl5TRs3oQdPgoi5Wwoq8Rv\nDBbC16xahRmQmqZCf4/Avzf8v50p22VcZ9ey8CNq3nkL/44/UnvHHwFwbn6oRyOU/oZgV4H1mzZh\nKvv+89ffo+z0jLLry89o3Lhxna7bk6nDw4GFnuet8TyvBXgAOBBY5bruWIDws5cWPYj0jG1thabG\ndtdoZTQs8a8vc9p5vdCrLiovD96cbKxP7KEYCf/9lDZ1aBvr8RvqtnAHC4+dPyc4qNuMOeWceLn5\n1tkAOFXDg78Xyfe88mzPvjTaGnw6kZ61IyJ9Tk8CrSXA/q7rDnBd1wCHAe8BDwOnhHVOAR7qWRdF\ncs82NcFH8yDaiunKovURiSmkgtgQeF0N9qWnoaG+7WbV61L/jeP/4Fus+eZRW7BzBSpM5+Gc8QOc\nzx4RLzaTt8XsczC2pRnqUvOQ2dt/nzhubsKm50xLrpvpJYTYG6gRZdQRKTXd/q/e87xXgX8AbxKk\ndnAIpgJ/Axzhuu5HBKNev8lBP0Vyxm5Yh3/29GCfw7LyIBlpZw0YlPk435YuwvQLAi07P9gKKD5F\nFtPSrAXyAGvXYD5/TCLAHhrmtho1Fir7EV22BP+6n2e81a5chn/WdPzf/Bi7bEnb6/Pfwp8xDTt3\nNnbFp4kLfvjcNaIlUnJ6lEfL87zLgMvSipsIRrdEClJsT0IAJk1ts2C8IynrdAYWUKAF0D98QzKW\nKX7B+9jX/4fZ+7P561OBsb4fJA8dlBiNdC74FXbB+5jKfti0KUMAdtgt2KcQUt84Xbcaxm+V2v4b\nLwPgX/9LKCsnctM/gwuxADeiXc9ESo3GsaX0bErKn5u8H2FXFdKIFsT3ZzS77Rsv8h+4CwjXo4Vs\nKe+D2NgQpOJI2svSjBmPc1Dwb0Nz/Ekp1c2p5wYBdSxQem9u/JrdGPw9stbi//s+7MfvpWbkb23B\nxkayYp+aOhQpOfqvXkrP5o2J49joT3cUwIiWc8m1sN3OwUmY88t84dhEhTUr8f96Y+rPXALb89h1\na7BrVra9EHsZYEDmTcPNmAkM/+1fEucHHhbkKwsDLVuzKlF543psYwP2n3diH74H/7ZrsbOeS21w\n86Z4XUBThyIlSIGWlJ7koKMHOkx0uoWYSVMxk7YJTsJf4ulpCOwLj8GmDYmCTNNjRca/8Az8i2dg\n33kdCF5+sGtWxhe5mw5GI8smbQ3b74pz/uXBs4xEEiNSmzcFU7EDBkLNKuzfb8M+/kBwLQzszGnn\n4Zz9s6AfF5wSBH1P/Cuoo0BLpORowYCUHLtpI2y1NWaP/TEHHNrl+53vXITdVEDbdyZNC8Y4v7gB\n/9KzEgVJgZZ9+WnM0V/bEj3LO/8Pv4Bd9w6CpTmv4pz38+BCOyNaAKayH5ELZiYKnCDQsi3Nwbqs\nzxwA9XXY/z2Z+f5td4Z+iTdA/ZuS3geKKNASKTUa0ZKSYlcthw/fwUzeFue4EzHVGTcu6JDZ60Cc\nQ4/NXnELMZ89HEaOwex7SKJs7ETYbZ/4uV21LHH8wF3YpLVGxcamTwe/8zrMeRUA/8FgzVqX1tdF\nIhD1gz0uW4N0IOagw+OXnUuvw3z5m8HxBTMxI8dgkncJWPRR/LC3t2USkcKjQEtKip33ZvDL8pjp\n+e5KzpitphL51c2YYSNSy5OmNu39f0m55v/txi3St3ywzzzS/sUlnwSfsc3COyOcOrSfhLmzpm6f\nmuh04hTMF7+Cc/VdmO13jZc7P7gi0cbgoTi/v6fz3ykiRUOBlpQU+/S/g4Me7l3XF7QZ2QEGfv30\n4MD3g8Sb69du4V5tAZs6XoNnjnUxXZnCiy2GX7MSBg3GDBnWZmTKRCKYIVWpZTvujjnGDY4PPx5T\nAC9PiMiWp0BLSoatr4PVwX7nJTGFE47emBMSW5AOnH4qOA5UDce/9lL8H5+Wp871HrtqGYydiHPp\ndTg/vTpe7lx0JfTrj+nqtG9sjdYLj8PgRDDlXPM3nKvv7PjWL5+Mc72HU0QjqCLSNQq0pCTYeW/h\nnxfkSDLT/i/PvdlCwozn5vDj40UmUhas5VpXAx+/196dBcXOfwu7tgtbpi5fAuMmBlN6k7fFnHgm\nzkVXYqbuQOSP92NimeA7K+IEWfV9P5FFHjCDh2CGZG+rKwlxRaT46K1DKQn+Q3fHj80XjstjT7Yc\n56yfwuoVmMp+OJdcEyTqhGBj7HVr8tu5TrIb1+NfexmMn4Rz8VWYikqiV/0UyiuInJe+KUWwDyFr\nVmL2+1y8zDmsh3/ekfJ4Hq3kdkVEOkOBlpSGxob4oeng1f5iYqqGQ1WQ+T6eawtgeHWeetR19tXn\ngoNli/HPmo7zpwfhg3fav2HJJ2AtZsLk3HWiKmkUqxtvqYpIadPUoZSG2Aa//UsjyOrQwCEppzY2\n0lWA7N9vTzn3//iLjut/+G5wsO0uOeuD2WpqcDB+EkzeNmftikhp0IiWFD3bUB8/dn78qzz2pDAY\nxyEltLIWCvDlgHgAOGgI5pjpWO9WSN4QPL1+NIp97X8wflJqHqseMlN3wPnFjTBqbNfeVhQRQYGW\nlAAbJqt0zr4EM2FKnntTANKDKt8P3kQsNOG+hObor7XNqB7213/xCczEKeBEsCs+haULMWdekPOu\nmLETct6miJQGBVpS/GIbCU/ZLr/9KBROWqBl/fz0I5twX0IGDYbazanXfB/rR7F3XU/6xKfZ66At\n0j0Rkc4owH/GiuRYU1PwqdfsA6PHB5/hQnn8Ag20mpsBMBWVmM8fDZO2gT32x3z+mOD65k0Zb9P0\nnogUEgVaUvyaG4PPpC1pSpkZOxHnd7djjpgWFISBlp0/p7D2QGwNAi3KKzAVlUQuuYbIWRfDqLFB\neR9JUSEipU1Th1L8mhqhohJTiOuQ8sRUjcDGnofvY1ua8a+9FIDILQ/nsWdJWmKBVnlqeVl4vq4m\npdj833cwU/RWoIgUFgVaUvzq65TWIRMTTrH5Psx7M799yaQl3KuxLG0ksiz4vy07N3jJwZxwMqxe\ngXPoMVuydyIinaJAS4qe3bQBhgzNdzcKT2xEy0axsdGhSGH8X4KdPwc7d3Zwkj7lu+ijoM4rzwJg\nDj6iU1vhiIjkQ2H8v6pIb9qwFoYOz3cvCk8szYNvoTZcWB5txa5Ymtd0Btba+DQm0HbqcFhaZvtB\nucuZJSKSa1q0IkXNNjUF+/3FFlBLQtIareQ3+Oz7mRfE+/97kujMH2I3b2y3Sf+//yD6o1N71q9l\ni1PPh49MOTVHfTVxUjUC4+gtQxEpXAq0pKjZ/z0JTY2YvT+b764UnjDQsm/Pxi7+GAYPBcfB3vNn\n7OIFbarbO/8Iiz5q981Eay32gbtgwzpsLAdWN9hPPkg5T9+b0pSVBakeAHPQYd3+HhGRLUGBlhQt\nW7sJe9/NAJhtd8pzbwpQLNC6+0+w8ENoqMcc/39B2eKPUqr6Lz2VONm0IXN7SekW7CvPdL9fq1dk\nrzNwUPA5WGvvRKSwKdCS4vX+28Hn9rvmtx+FKi3dhdn3EMzhxwcnSz5JuWbv+EPipDZzolCSRsHs\n/X8JPq3Ff/4x7IL3O90t+/gDiZPd981cqaIy+Bw4uNPtiojkgxbDS9HyZz0Hg4fifP/yfHelMKWv\nbRozIR7A2Ocfwx8zHufwadhYmoWYurTtcEL200+CBfYV/aCpIbhv1TLs327EAs6Pfo3ZbucOu2Rj\nWfyrR+Ncel27SWbNhMnYOa9iqvSSg4gUNo1oSVHyX30e5s6GiVsHa3qkDZOeW6yhFpO04bS9/9bg\nYOXSoP6ZF8CY8e1ufcOq5VA9GvOVb4bny/BvuzbR3kfzsndq6UIAnK+diuk/oN0/O3Ps13HOvRSz\nw7sH4aYAAB/sSURBVG7Z2xQRySMFWlKcwuDAOfToPHekgPUfkHre2ACAc9bF8SJbX4dduQwItu5h\n0JCMbx3aus3Y116ENSuhX38A/MvPhU8XJur8629YP9phl/wH7gwOdti9w3qmrAyz694d1hERKQQK\ntKQ4DQoXSU/VIvh2heubzJEnYKZ9A3NcsBDe7LE/5uAjgzprVmD/cXtwPHgoZvR4WL4Ya21qW0kL\n2E2/tAAuaZ2VffbRdrtj166GD4NRLxNb7C4i0scp0JLi1BrbvkXThu0xYyfgXHIN5qun4nzp65jB\nicSfZp+DAbBPPpR4m3DgIJi8LdRuhk8XEv3Radg3Xg6uheu4zCnnpIyUOVfeTuTsSzDf/mHQ3n23\nBAFVJuGImjnkqFz+mCIieaVAS4qOjUaDjaQhsQGxZGQmbZN5s+0BwYiSffX5RN3yCszkIH+Vf8X3\nYcNa/L/eEFxsqA/qjJ+ceCMQMMNGAODs97l4mX/Rt9vk2bJzX8OfGQRjZrd9evQziYgUkh79c991\n3SrgL8AugAVOBz4A7gcmA4sA1/O89T3qpUgX+NdeCh+8E5xoRKt7hlZlLh8/OfW8bjO2sR67Ocyt\nNXBQPOhirwNTqjoXX43/qyCYYuVSmLoDAPadN/CvvyJRMX3LHRGRPqynI1rXAY95nrcDsDvwHnAR\n8LTnedsCT4fnIh2yLS3Y+tq2a3+6oHXZEvzZLySCLEh5i066IG1vSOfsSwAw5eWYI6alXPOv/lkQ\nOJWVw4hRmElTcb5zIc7p56fUM1O2xbnoyuBk47rE/X9IS7+hUUgRKSLd/ue+67pDgUOAUwE8z2sG\nml3XnQZ8Pqx2J/AccGFPOinFz/9esH+dc87PoBtTR3b1ctb+9Du57lbJSg5QnRv/iUkaZTJHfRX7\n/H9h1PggHcOij7CDh8LocZhIkJvL7HVQ5oarRwNgN26ANSvx77q+bZ2W5tz9ICIiedaTeZUpwBrg\ndtd1dwfeAM4DRnueF3sFaSUwOtPNruvOAGYAeJ5HdXV1D7pS/MrKyor2GdmWZmLLowc21jGgGz9n\n4wdziSUdcEaNxV+9goq9D2JYkT6z7urK36O6086l8YUnGDE2bUPu6mrsvc/gb1hLzRnTcIYOw6xe\nTtm2O1KVpW07bBirHYcBLU34L/yXhjB7/4Djvo4zcgy1t11H1aQplOfxz62Y/1vLFT2j7PSMsiuV\nZ9STQKsM+Axwjud5r7quex1p04Se51nXdTPOBXmedzNwc3hqa2pqetCV4lddXU2xPCP/lWeDKahw\no2eblACztqWV+m78nP4H88EYnD96mMpKIkAUiuaZ5UqX/h4deDgceHgH9Q1MmIxfPRreeR3/Mwd0\nru1h1dQv+jiebwugca+DYdxEnG12ZuOgKsjjn1sx/bfWW/SMstMzyq4vP6Nx48Z1um5P1mgtBZZ6\nnvdqeP4PgsBrleu6YwHCz3be5ZZSZP0o9rZr8f98ZaKwsT5xnL7dS2fatBY7ZxZlk7fBVFZmv0Fy\np6ISNqyDaDSRuyybrbbGLl6Ard0EI8fgnHcZjJuIMQYzckzv9ldEZAvrdqDled5K4FPXdbcPiw4D\n5gMPA6eEZacAD/Woh1Jc1q6JH1rfDw4a6hJlb72CfecN7IZ1+C8+gV2xtMPm7KYN+D84GT5dSP+j\nvtwrXZYOVPaDRR8Fx0PaeVMxjdlqKqxeDiuWBovnd9lLLy2ISNHq6bvv5wB3u65bAXwCnEYQvHmu\n654BLAbcHn6HFDhrLfZvN2L2OTj73nPhdi4A9tZrMWf+ENYn3kBj/hz8+XMSdQYNJnLt3e0251/z\nsyCBJtD/kC9SX1vXbl3pBck5s7btXBZ+M2kbLMDKpZgdtVehiBS3HgVanufNATJtOHZYT9qVPqZu\nM/aFx7EvPU3kTw90WNWuTIxQ2dnPY089B7tkQfs3hEFUxrbqamHZYgDM9NMx/fqDAq0tylRUBkHT\nqLGYEaM6d9PU7RPH47bqjW6JiBQMZYaXngv3pyPaiv/IfR3XXbkUBg7GfOvs8HxZsBHx8HbePJm0\nTfttvT8XAOfcy3COPKGLnZaciI1odWFtlRmQ2MfQKNASkSKnQEt6zP/fk/Fj+9A9wRY47bArl8LY\nCZgp2wXny5dgG+qh/8B4HefC32KO/HIQZFX2a/Nd0TOPJ/rbi7CvvwSRMtD0U/40NwFgttula/fF\nAuiJW+e4Q/L/27vzMCuKe//j7+ph2IZhcxBQBBE3Im6IqFEkoBgNGvdyjaBXMSYxxKvRuMZ43a8L\n/q4LLjFRwaUShWiMicaAgqBEMCEo7ogBI7Ij27B0/f6onjkzMnAGZs6c7fN6nnnO6e7qPtVfeg7f\nqa6uEpHcokRLGm7eZ7WX//Pv6rd+8Vds/NlZxG+8mmybh+nSDTrvCCYKLVxrVkHrMqLLbsKcMhyz\na2+iU8+F9h3hw1nEr/4xHGvpYvxj/xeO8/F7+Lcnw3adMBpJPHuSlkjTe9+t2i26+Nrw711jAmoR\nkUKkREsaxC9ZCEsXhRao6pU+TKkTx/hpr4c+XG9NxM+YCl8vhy7dwkjjZW1gxXJYsQzK2mL22Jvo\nuydVH8aUlYfDPf1QON6s6WHDjj1Sn1VjLCZpeubEc4h+fnN1C2W992vXAbPH3hmqlYhI7lCiJQ2z\n8EsAzJ77EP0smbPu6+XEPzoZ/8R9+H+9HdbN/ifxA7eEsl12DOvatMWvWgHLFmPq6qO1S41O04sX\nhPGagOiau6A8GbNJiVZWmZKSrb9tKCJSRJRoScOsSp4KbN+xuj+VnzElvE5+BZYv23SfrjuF14rt\nYfoUWLO6zs7w5tuDUwtfzocVS6FNebhV+PXypIwecBURkdzV0HG0pMj5pJWJ8rbQLFxO/rU/pwp8\n9UWt8qb/QMz2Ye48s09//KwZYUP77TY5tiltjjnrh/ixo4nvu6nWtuiym/FzPyI69MhGOhMREZHG\npxYtaZhPPgitWe06QqeudZdpXQZRRHTjaKILLq1ebfY/KPW+vO7pW8zAY+pev0cfoqM0EryIiOQ2\ntWhJg/iP38Ps+q0whUqzui+n6MYHwy2/b0yzYtpvF/phffoBVHSuc19jDOzeBz6cFY510ZWNewIi\nIiIZpBatAuHnfoJf3bSjovsli2DJQkg39UrLlpudyy664jaiWx6uvp1YZ5mLr00t6Ek1ERHJI0q0\nCoBfu5r4xkuIH74jLH8wC//vOZn9zOVL8W9PAsBUdW4HKG0eXlunBiBlC+NcmSjCbKY1q7pMy1aY\n754I3XthytpssayIiEgu0a3DPOff+wfx3deFhbkf4zdsIL7jKgCiex3mGyOrN5b4/90AVXMUtu+Y\n2lDWBpYtwZz4A/zY0QCbbc3aGtEp5zb4GCIiIk1NLVp5Ln50VGph+67w/szUtsvPw8/+52b39cuW\n4GdMwXu/9R9ccyLozjuk3ieDjJqq5Ktjp60/toiISIFQi1Ye8evXw/rK6kl5vfdhwM7lwD4Hwvy5\nxPdcn9ph9UriJ+7DDDgK/9zjmO+eWN0y5FetJP758FCuojPmxB+AiTD9Dk3bAuXXrg63Azesx5z1\nQ0xUUr0tOnkY8f03w+57E935eO1biCIiIkVGLVp5JH7kDuKRZ6YmbZ75d1gwH3P2jzA77waLv9p0\np5Jm+OSJPf+Xcalxr+Z+nCqzaAH+4TvwD90OSQuYX7SAjRd8n3jCi5sc0r85ETasJ7ryf4m+871a\n28ze/Sh54DlM6zJM2/aah1BERIqaEq08Ea9eBTOmAuDfeo2Nd1xNfO+NAJgDB2B27V1dNrrmLqIL\nLw8Lq76GRakEzL/3j/C6dHHY95BBtT7Hz/x7eH17cnh98sFN6uInvgQ9doWtnN9ORESk2OjWYZ5Y\nWSPh8b+p0S+rvB2mdRm+5ryAXbpheuyK+fQD/Ct/CNPVtO8Ibdvjn3kE3+9QWLoQAPODnxCddwkA\nG6/7Mf7VF9i4ZCFUtZoB/ovPMTt0D+8rK2H+XMzxZzVKJ3cREZFCphatPLHunWnQqQvmsCG11keX\n3AAQni4sbwe99kw9adgiNeGyOfpkomNOCf22rr8Y/7cXQ5JWmrq1Z3beNbx5581wW3Kv/cFE+Lff\nSH1g1S3Hmk8aioiISJ3UopUH4jcnhFal00fAusrq9eb4szA79axejm5/FEwqd/bzPkttO+K40Hm+\nojMs/DKs7N6r9gft3gemTkjtM+Ao4s8/xb/wFHFJCWbQUOK7wuChpku3RjxDERGRwqQWrTzgp08B\nCK1ZHZKWpN77Eh17Wq1yplkppqSk5p61txuDOemc1PI3kiXT/3DMMSdjBh8LvffFHHAo9AjJmB8/\nhnjkGbBxAzRvAb32bKSzExERKVxq0cpRfv06/B+ehBXL4B9v0ep7p7CuRQtoVYYHTPdd0h4jOucn\n+FatMadfUL3O9DsM//dJ8M6bmIFH1ypvmrfAnDSs9jGOOpF41oza5YaPVP8sERGRelCilWP8jCn4\nj2bj35oYOrEnWhx4GOsA9u6HOecnmIO/k/ZYprwdJunoXr3OGKIRl8NXX1R3cN+iXfbA9D8cP+31\n1DH6HlK/kxERESlySrSagF+/Dj/5r5hvH4Fp0YJ46gT8o3djhlqiE84OZVYsJf75uRDHqR07VBCd\nOQL/wSya9+kLy5aFuQEHHNWg+phmzaA+SRahk7254DI2fvguLFsMffp+4/akiIiIbI4SrSbgH78P\n/+YEKGsTWocevTusf9Hhh5yAn/wK/ve/qS5vjjsD06NXaL2KIsx+B4fkKIvM3gfgJ72M6dMvq/UQ\nERHJJ0q0mkDVIKDMm4Pfv/ZtNz/11VpJVjR6XE62GJlThkMcYw74drarIiIikjeUaDWFJHHyLz2L\nn/k2QJh/cNLL+Gd+nSq31/45mWQBmNZtMMN/mu1qiIiI5BUlWk1h/brU+/lzgTBtjp/8CvgwBEN0\nw/2YrhqbSkREpJBoHK0M8+sqYe0azHGnE932aGrDLntgDj0SAHPqeUqyRERECpBatDJt9kwATK/e\n0GE7TP+BmP4DwjQ5g4/Ff/AvTJ++Wa6kiIiIZIISrQzwK5ZCqzLYuJH4d4+GOQd37xNGZr/g0upy\nZqeelNz8UBZrKiIiIpmkRKuR+cpK4qt+CCUR5oSzYcF8zOkjak3eLCIiIsWhwYmWtbYEeBuY75w7\n1lrbEXgG2Bn4DLDOuaUN/Zy8MfsfULkGAP/kgwCYgw7PZo1EREQkSxqjM/xIYHaN5V8ArzrndgNe\nTZaLhv/ntNor9u2PadM2O5URERGRrGpQomWt7QYMBR6psfp44LHk/WPACQ35jHzi4434GVNhv4Mw\nhw0JK40e7BQRESlWDb11OAq4HCivsa6zc+4/yfsvgc517WitHQGMAHDOUVFR0cCqZN/Kpx9h1eqV\ntB18DM1778eiya/QZp++lDXCuTVr1qwgYpRJilF6ilF6ilF6ilF6ilF6xRKjbU60rLXHAl8556Zb\na79TVxnnnLfW+s1sewioeuTOL1q0aFurUicfbwQTYYxJWzZ+0eHHj8EMGkp05oXb/Jkb//QsACu7\n9cIQEd3zFKtbtmJNI5xbRUUFjR2jQqMYpacYpacYpacYpacYpZfPMdphhx3qXbYh97UOBb5vrf0M\neBoYbK0dAyyw1nYFSF6/asBnbLP4nhuIRxyPn/5G2rJ+/JjwOuFF/Lw52/6h7TvCbt/ClLcDwLQu\nw0S6dSgiIlKstjkLcM5d6Zzr5pzbGTgd+Jtz7mzgeWBYUmwY8IcG13Ir+TiG994BIB59G/Frf960\nTOVa/Pr1YaFjp+r18a9Gblp2zWp8ZeWWP/P9mfDvOZi+mnRZREREgkyMo3Ur4Ky1/wXMBWwGPmPL\n1q6utejH3E+8YT2mzwGYzqG5L77jaqhcS3Tt3bB0EeZ7p+Jf+n313IM1xZecBRs3QreemN33wpwy\nHFPaPHX85UuJH7wNOlRgBh6d2XMTERGRvNEoiZZzbiIwMXm/GDiiMY67zVav2mSVf/phfIdxlNz+\nKP6T9+Gzj8KGhV+G5KrrTpjjzsA//yTx2NH4t14juvpO/GsvhSQLYN6ccGtxx+6Yw0NC5SsriW+6\nFFZ+jRl+bq0ETERERIpbYXYgShKt6KJf1G5hWroIv+pr4mdSo1H4d94ECC1drVqHdRP/BGtWET/3\nOH7apOqy5sjvhzdf/SfcngT49H1YGjrzmf0PydQZiYiISB4q0ERrZXgtK4eee9Ta5Mc9AZ9/Anvu\nE5bHjwkJVpdumE5dah9nxhRYvgRz8jCiWx4mOu38sM9fxhH/7Cz8qpX4JSHJim64D9O6LLPnJSIi\nInml4BIt/9F7xHdeExZalWHKaiQ/nbrgp70OGzdi+qZan8zpIzCtWkO3nqmyNW4Bmp57YCq+MRzY\nmlX4vzwLn8yG1mXQqWsmTkdERETyWMElWvGfn00ttGoNrVNjqZpv7Qdrko7yzUohacEy3XqEdR0r\nYIfu0LoN0S9uh2SYBjqmBlSLrrkbOu8IgH/pWfwXn0Onrphmmp9bREREaiuY7MB7Tzzq+uphHehz\nAHSogHXrUmVWrqh+b3rtCfsfgn95HLTrGNYZQ3Tl7RCVYJq3ILp2FP7tyVCjNcv06EXJjQ8QT52A\nf/Ru+OR9zIEDmuQcRUREJL8URKLlN2zAv+hCklXejmjk9ZgevcK2sjapgsuWABD94nbMDt3hpHMw\ng76Hadehuohp2Tr1vsN2mCHH1/mZZsfuVA0EYU4/v3FPSERERApCYSRaT47GT3oZ9juI6PzLMC1a\npDaWJbcOv7U/0annhhasHrsCYEpKarVWbQ3TvRfRqLGhH5hGfxcREZE65H2i5WdMCUkWEF14OaZZ\naa3tprSU6Lp7oFMXTMtWmPMuabTPNmXl6QuJiIhI0crLphhfWUk88SX8yhXED9wKQHTTg5skWVXM\nTj0xLVs1ZRVFRERE8rNFyz8/Fv/yePzYB6rXme01vIKIiIjklrxr0fLLluBfHp9a0aqM6F6XvQqJ\niIiIbEZOtWj5tWtg3VpM2w6bLzN+DADmjBGYQwZDaXONYSUiIiI5KWcyFD9vDvEjd8H8uZQ8/Pzm\nyy1bHDq2DxqKMaYJaygiIiKydXLm1mH8q5Ewfy4Aft5n+A0bNinjly2GOR9C152UZImIiEjOy5lE\nq6b4Vz/F/2HsJuv9738Lq1cRHTKo6SslIiIispVy5tahOfPCMLr78qUA+PdnhtfFXxGP+mWYJueD\nf2GOPB7T77BsVlVERESkXnIm0YoGDcX3/TbxZcPCivlziV96Fv/Pt+DL+eEHMAcPzGItRUREROov\nt24d1pyXcP06/HOPhUmbh1oobR7Wd++VnbqJiIiIbKWcadECMM1KiUY9SXzjJbBoQWr9QQMxg4bC\nyhXqBC8iIiJ5I6cSLQBT1obo5GHEE/4E5W2JzrwwNa5Wu82PryUiIiKSa3Iu0QIw/Q6jRB3eRURE\nJM/lVh8tERERkQKiREtEREQkQ5RoiYiIiGSIEi0RERGRDFGiJSIiIpIhSrREREREMkSJloiIiEiG\nKNESERERyRAlWiIiIiIZokRLREREJEOUaImIiIhkiPHeZ7sOADlRCREREZF6MvUplCstWkY/W/6x\n1k7Pdh1y/UcxUowUI8UoV34Uo6KIUb3kSqIlIiIiUnCUaImIiIhkiBKt/PFQtiuQBxSj9BSj9BSj\n9BSj9BSj9IoiRrnSGV5ERESk4KhFS0RERCRDlGiJiIiIZIgSLckb1tp6P05brBQjEZHcokQrh1hr\nS7Jdhxyn6zW90mxXINdZayuSV/2+bYG1duds1yHXWWv7WWu3z3Y9cpm19khr7QHZrkc2qTN8lllr\nDwGOcc5dl+265CprbX/gp8AXwBPAu865OLu1yi3W2n7AFYQY/Q6Y6pzbmN1a5Y6kpa8V8Gugu3Pu\n0CxXKWdZa/sCtxOupXN1HW3KWrsX8DCwGLjUOfdhlquUc6y1+wM3A4cB5zvnnslylbJGLQRZZK0d\nBjwGXGOttcm6ZtmtVe6w1kbW2l8CjwAvAc2AHwP7ZrViOcRaa6y1twKjgT8CC4CfAN2zWrEc45zz\nzrnVyWKFtfYiCNdYFquVU5Jr6WrgKeBp59w5VUmWbklvYiQwzjl3XFWSpRgF1toSa+1DhET0QeBJ\noHeyrSh/34rypHPI58Bg4GjgTgDn3Ab9wgZJq9VcYLhzbixwE9AD0C2fhHPOAxOBIc65x4DfEOYO\nXZjNeuWaJInoSkhE/wu4yFrb3jkXF+uX/zcl11IpMNk59wiEVglrbbNkW9FLkoiOhN+xe5N1J1pr\nuxFaTIs+4UqS8z8DA5xz44HngEHW2pbFeidCtw6bkLV2ILDWOfdWsmyAkiS5mgxMcM5da60tdc6t\nz2pls6SOGLUE1gGlzrlKa60DnnDOvZDNembTN2NUY/0AYAzhls804I/OuVeyUMWsqxkja21U9QVv\nrR1PaPG7AlgFPOyc+ySLVc2qOn7fyoBngXeBwwmJ6XJC683vs1bRLNrMd9I7wKXAmUAF8CWwzjk3\nImsVzaItfCcZ4AjgNOAK59ySbNQv2/SXXBOw1pZba58DxgEXWms7JJsMUNX/4ULgp9bazsWYZNUR\no47JpkrnXJwkWaVAN+CDrFU0izZ3HdVokVlCaP07hPAfwRnW2j2zU9vsqCtGNZKs3YFPnXPzgFeA\nHwG/s9a2SK6torG5a8k5twp4HNgPuMw5dyzwOnB0Er+isYUYrSW0HN8PvOycOxq4GuhjrT0maxXO\ngi18JxlrrUlaQt8nJFstq7ZlrcJZokSraawD/gacTWhtOBXCrTHnnLfWljjn3iV0Yr4VoNh+Ydk0\nRqdA9e2MKr2BBc65D5Nf8P5NX82s2ux1lLy+65ybkJR9HegArMxCPbOpzhglvgB2s9Y+D/wv8Bow\n1zlXWYR/3Gw2Ts65J4FTnXOvJav+CnRC11LNa+l+QuJQAeCcmw9MBort1tjmvpN88n9blPxh8xZ1\nf6cXBSVaGWKtPcdaOzDpB1JJ6ND9V+BDoF/VX4dJdu8BnHPnA8OstUuBfQu978hWxKjqAYGOwGpr\n7XBgCrB3of91tJXXUU1DCL/fXzdphbOgvjECyoH/AJ8CBzjnjgN2KpZHz7fmWvrGLZ4hhO+ogk+0\n6hsj59xKwpPQw6y1+yUPVxwJfJalqjeZrbiOoqQPZDPgI8Kt+qKkPlqNKPnPrgvhKYsY+AQoA0Y6\n5xYlZXYDhhHuZ99YY7/uwN3AdsCPnXOzmv4MMm9bY5Ssv4XQt+a3wCjn3MymrX3TaMB11AIYANwG\nzCP0iXi/6c8g87YyRpXOuf9J1rVzzi2vcZxay4WmAddSRHgs/x7CQzu6lur+TjqN8BT0XsBVyZ2J\ngtOQ6yhJtu4GVjrnrs3KCWRZQbeYNKXk9p8n/NU83zl3BHARod9M9QzlzrmPgOnADtbaXZOOlQZY\nCtzqnBtYwEnWtsaodbLpBeAM59x5BZxkbWuMWhC+ABcAv3TOHV/A/zFubYy6JjFqBaxNjhElZQo5\nyWrId5IH5qNrCagzRmU2PLT0DHB1EqNCTbIach21Sjb/d7EmWaAWrQazYXTp/yEMOfAnoC1winNu\nWLI9Ity7Pq1GnwestVcB5wFtgMHOufeauu5NpZFiNMg5N7up695UFKP0FKP60XdSerqW0lOMGo9a\ntBrAhkdapxM6HX9MuCjXE8YM6Q/VHZWvT36q9juV8JTKBGCfAv9Ca6wYFewvq2KUnmJUP/pOSk/X\nUnqKUePSKOQNEwN3OueegOopB3oC1wEPAAckWf94YLC1tqdzbg5hzJWjnXOTslTvpqQYpacYpacY\n1Y/ilJ5ilJ5i1IjUotUw0wFnU5PTvkGYR+23QIm19uIk6+8GbEguRJxzk4roQlSM0lOM0lOM6kdx\nSk8xSk8xakRq0WoAl5o7rcoQoKqT9rnABdbaPwJ7UKPTYDFRjNJTjNJTjOpHcUpPMUpPMWpcSrQa\nQZL1e6Az8Hyy+mvgKqAPMMeFAe2KlmKUnmKUnmJUP4pTeopReopR41Ci1ThioDmwCNjHWjsKWAxc\n7JybnNWa5Q7FKD3FKD3FqH4Up/QUo/QUo0ag4R0aibX2YMJo5VOA3zjnfp3lKuUcxSg9xSg9xah+\nFKf0FKP0FKOGU4tW45lHeKz1LhemJZBNKUbpKUbpKUb1ozilpxilpxg1kFq0RERERDJEwzuIiIiI\nZIgSLREREZEMUaIlIiIikiFKtEREREQyRImWiIiISIZoeAcRyQvW2s8II1RvADYC7wGPAw8l865t\nad+dgTlAqXNuQ2ZrKiKSohYtEcknxznnyoEewK3AFYAGUBSRnKUWLRHJO8655cDz1tovgTettXcS\nkq8bgV7AcuDXzrnrk11eT16XWWsBhjjnplprzwN+DnQBpgEjnHNzm+5MRKTQqUVLRPKWc24aYeTq\nAcAq4BygPTAUuMhae0JS9PDktb1zrk2SZB1PmBz3JKATMAl4qinrLyKFTy1aIpLvvgA6Oucm1lg3\n01r7FDAQGL+Z/X4I3OKcmw1grb0ZuMpa20OtWiLSWJRoiUi+2xFYYq09iNBvqw/QHGgB/G4L+/UA\n7kluO1YxyfGUaIlIo1CiJSJ5y1p7ICExmkxouboXOMY5t9ZaOwqoSIrWNanrv4GbnHNjm6SyIlKU\n1EdLRPKOtbattfZY4GlgjHPuX0A5sCRJsvoDZ9bYZSEQA7vUWDcauNJau1dyzHbW2lOb5gxEpFgo\n0RKRfPKCtfZrQmvU1cBdwLnJth8BNyTbrwNc1U7OudXATcAb1tpl1tqDnXPjgNuAp621K4BZwDFN\ndyoiUgyM93W1qIuIiIhIQ6lFS0RERCRDlGiJiIiIZIgSLREREZEMUaIlIiIikiFKtEREREQyRImW\niIiISIYo0RIRERHJECVaIiIiIhmiREtEREQkQ/4/CQ5Rs5W0OywAAAAASUVORK5CYII=\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x10f4d2be0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fd.plot_data()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"1\n",
"2\n",
"3\n",
"4\n",
"5\n",
"6\n",
"7\n",
"8\n",
"9\n"
]
}
],
"source": [
"for i in range(10):\n",
" print(i)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"30.63\n",
"30.14\n",
"30.08\n",
"30.28\n",
"30.02\n",
"29.67\n",
"30.09\n",
"29.92\n",
"29.42\n",
"30.72\n"
]
}
],
"source": [
"for row in fd.data.iloc[:10].iterrows():\n",
" print(row[1]['Close'])"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'pandas.core.frame.DataFrame'>\n",
"DatetimeIndex: 1924 entries, 2010-01-05 to 2017-08-25\n",
"Data columns (total 2 columns):\n",
"Close 1924 non-null float64\n",
"Returns 1924 non-null float64\n",
"dtypes: float64(2)\n",
"memory usage: 45.1 KB\n"
]
}
],
"source": [
"fd.data.info()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"DatetimeIndex(['2010-01-05', '2010-01-06', '2010-01-07', '2010-01-08',\n",
" '2010-01-11', '2010-01-12', '2010-01-13', '2010-01-14',\n",
" '2010-01-15', '2010-01-19',\n",
" ...\n",
" '2017-08-14', '2017-08-15', '2017-08-16', '2017-08-17',\n",
" '2017-08-18', '2017-08-21', '2017-08-22', '2017-08-23',\n",
" '2017-08-24', '2017-08-25'],\n",
" dtype='datetime64[ns]', name='Date', length=1924, freq=None)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fd.data.index"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Timestamp('2010-01-12 00:00:00')"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fd.data.index[5]"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'2010-01-12'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"str(fd.data.index[5])[:10]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Backtesting Base Class"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are going to implement a **base class** for event-based backtesting with:\n",
"\n",
"* `__init__`\n",
"* `get_data`\n",
"* `plot_data`\n",
"* `print_balance`\n",
"* `get_date_price`\n",
"* `place_buy_order`\n",
"* `place_sell_order`\n",
"* `close_out`"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import math"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class BacktestingBase(FinData):\n",
" def __init__(self, symbol, start, end, ptc, ftc, amount):\n",
" FinData.__init__(self, symbol)\n",
" self.start = start\n",
" self.end = end\n",
" self.ptc = ptc\n",
" self.ftc = ftc\n",
" self.amount = amount # cash balance\n",
" self.initial_amount = amount # stores the amount value\n",
" self.trades = 0\n",
" self.units = 0\n",
" self.position = 0\n",
" \n",
" def print_balance(self, date=''):\n",
" print('%s | current cash balance %9.2f' % (date, self.amount))\n",
" \n",
" def get_date_price(self, bar):\n",
" date = str(self.data.index[bar])[:10]\n",
" price = self.data['Close'].iloc[bar]\n",
" return date, price\n",
" \n",
" def place_buy_order(self, bar, units=None, amount=None):\n",
" date, price = self.get_date_price(bar)\n",
" if units is None:\n",
" units = math.floor(amount / price) # additional checks might be in order\n",
" self.amount -= (units * price) * (1 + self.ptc) + self.ftc\n",
" self.units += units\n",
" self.trades += 1\n",
" print('%s | buying %5d units at %8.2f' % (date, units, price))\n",
" self.print_balance(date)\n",
" \n",
" def place_sell_order(self, bar, units=None, amount=None):\n",
" date, price = self.get_date_price(bar)\n",
" if units is None:\n",
" units = math.floor(amount / price) # additional checks might be in order\n",
" self.amount += (units * price) * (1 - self.ptc) - self.ftc\n",
" self.units -= units\n",
" self.trades += 1\n",
" print('%s | selling %4d units at %8.2f' % (date, units, price))\n",
" self.print_balance(date)\n",
" \n",
" def close_out(self, bar):\n",
" date, price = self.get_date_price(bar)\n",
" self.amount += self.units * price # additional checks might be in order / maybe add tc\n",
" print(55 * '=')\n",
" print('%s | buying/selling %4d units at %9.2f' % (date, self.units, price))\n",
" print('Final balance [$]: %9.2f' % self.amount)\n",
" perf = (self.amount - self.initial_amount) / self.initial_amount * 100\n",
" print('Performance [%%]: %9.2f' % perf)\n",
" # if self.units != 0:\n",
" # self.trades += 1 # might be added as well\n",
" print('# of Trades : %9d' % self.trades)\n",
" self.units = 0"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"bb = BacktestingBase('AAPL', '2010-1-1', '2015-1-1', 0.01, 10, 10000)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'pandas.core.frame.DataFrame'>\n",
"DatetimeIndex: 1924 entries, 2010-01-05 to 2017-08-25\n",
"Data columns (total 2 columns):\n",
"Close 1924 non-null float64\n",
"Returns 1924 non-null float64\n",
"dtypes: float64(2)\n",
"memory usage: 45.1 KB\n"
]
}
],
"source": [
"bb.data.info()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x10f4d2f60>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"bb.plot_data()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-06-01 | buying 50 units at 37.26\n",
"2010-06-01 | current cash balance 8108.37\n"
]
}
],
"source": [
"bb.place_buy_order(100, units=50)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-06-01 | buying 50 units at 37.26\n",
"2010-06-01 | current cash balance 6216.74\n"
]
}
],
"source": [
"bb.place_buy_order(100, units=50)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"100"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bb.units"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-10-21 | selling 77 units at 44.22\n",
"2010-10-21 | current cash balance 9577.63\n"
]
}
],
"source": [
"bb.place_sell_order(200, units=77)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"23"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bb.units"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=======================================================\n",
"2011-01-03 | buying/selling 23 units at 47.08\n",
"Final balance [$]: 10660.47\n",
"Performance [%]: 6.60\n",
"# of Trades : 3\n"
]
}
],
"source": [
"bb.close_out(250)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bb.units"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Long Only Backtesting Class"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"class BacktestLongOnly(BacktestingBase):\n",
" \n",
" def get_date_price(self, bar):\n",
" date = str(self.run.index[bar])[:10]\n",
" price = self.run['Close'].iloc[bar]\n",
" return date, price\n",
" \n",
" def run_sma_strategy(self, SMA1, SMA2):\n",
" self.trades = 0\n",
" self.units = 0\n",
" self.position = 0\n",
" self.amount = self.initial_amount\n",
" \n",
" # data preparation\n",
" self.run = self.data[(self.data.index >= self.start) &\n",
" (self.data.index <= self.end)].copy()\n",
" self.run['SMA1'] = self.run['Close'].rolling(SMA1).mean()\n",
" self.run['SMA2'] = self.run['Close'].rolling(SMA2).mean()\n",
" self.run.dropna(inplace=True)\n",
" \n",
" for bar in range(len(self.run)):\n",
" # print('current BAR is now %4d' % bar)\n",
" if self.position == 0:\n",
" if self.run['SMA1'].iloc[bar] > self.run['SMA2'].iloc[bar]:\n",
" # self.place_buy_order(bar, units=50)\n",
" # self.place_buy_order(bar, amount=5000)\n",
" self.place_buy_order(bar, amount=self.amount * 0.95)\n",
" self.position = 1 # long position\n",
" elif self.position == 1:\n",
" if self.run['SMA1'].iloc[bar] < self.run['SMA2'].iloc[bar]:\n",
" # self.place_sell_order(bar, units=50)\n",
" self.place_sell_order(bar, units=self.units)\n",
" self.position = 0 # market neutral\n",
" \n",
" self.close_out(bar)\n",
" \n",
" def run_momentum_strategy(self, momentum):\n",
" # place code & logic here\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"sma = BacktestLongOnly(symbol='SPY', start='2010-1-1', end='2017-6-30',\n",
" ptc=0.005, ftc=10, amount=10000)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-11-04 | buying 77 units at 122.26\n",
"2010-11-04 | current cash balance 528.91\n",
"2011-08-16 | selling 77 units at 119.56\n",
"2011-08-16 | current cash balance 9679.00\n",
"2012-01-27 | buying 69 units at 131.73\n",
"2012-01-27 | current cash balance 534.18\n",
"2015-08-27 | selling 69 units at 199.16\n",
"2015-08-27 | current cash balance 14197.51\n",
"2015-12-08 | buying 65 units at 206.95\n",
"2015-12-08 | current cash balance 668.50\n",
"2016-01-07 | selling 65 units at 194.05\n",
"2016-01-07 | current cash balance 13208.69\n",
"2016-04-19 | buying 59 units at 209.90\n",
"2016-04-19 | current cash balance 752.67\n",
"=======================================================\n",
"2017-06-30 | buying/selling 59 units at 241.80\n",
"Final balance [$]: 15018.87\n",
"Performance [%]: 50.19\n",
"# of Trades : 7\n",
"CPU times: user 59.2 ms, sys: 2.67 ms, total: 61.9 ms\n",
"Wall time: 60.7 ms\n"
]
}
],
"source": [
"%time sma.run_sma_strategy(42, 212)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"http://hilpisch.com/tpq_logo.png\" width=350px align=right>"
]
}
],
"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.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
#
# Simple Tick Client with ZeroMQ
#
import zmq
import datetime
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect('tcp://127.0.0.1:5555')
socket.setsockopt_string(zmq.SUBSCRIBE, 'AAPL')
while True:
msg = socket.recv_string()
t = datetime.datetime.now()
print('%s | ' % str(t), msg)
#
# Simple Tick Collector with ZeroMQ
#
import zmq
import datetime
import pandas as pd
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect('tcp://127.0.0.1:5555')
socket.setsockopt_string(zmq.SUBSCRIBE, 'AAPL')
data = pd.DataFrame()
ticks = 0
while ticks < 100:
ticks += 1
msg = socket.recv_string()
t = datetime.datetime.now()
print('%s | ' % str(t), msg)
sym, value = msg.split()
data = data.append(pd.DataFrame({sym: float(value)}, index=[t]))
if ticks % 10 == 0:
h5 = pd.HDFStore('data.h5', 'w')
h5['data'] = data
h5.close()
#
# Simple Tick Data Server with ZeroMQ
#
import zmq
import time
import random
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind('tcp://127.0.0.1:5555')
AAPL = 100.
while True:
AAPL += random.gauss(0, 1) * 0.5
msg = 'AAPL %.4f' % AAPL
socket.send_string(msg)
print(msg)
time.sleep(random.random() * 2)
#
# Simple Tick Trader with ZeroMQ
#
import zmq
import datetime
import pandas as pd
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect('tcp://127.0.0.1:5555')
socket.setsockopt_string(zmq.SUBSCRIBE, 'AAPL')
data = pd.DataFrame()
ticks = 0
position = 0
while ticks < 200:
ticks += 1
msg = socket.recv_string()
t = datetime.datetime.now()
sym, value = msg.split()
data = data.append(pd.DataFrame({sym: float(value)}, index=[t]))
resam = data.resample('2s', label='right').last()
resam['SMA1'] = resam['AAPL'].rolling(5).mean()
resam['SMA2'] = resam['AAPL'].rolling(10).mean()
resam.dropna(inplace=True)
if len(resam) > 2:
print('%3d | %s | ' % (ticks, str(t)), msg, '| %.3f | %.3f' %
(resam['SMA1'].iloc[-2], resam['SMA2'].iloc[-2]))
if position == 0 and resam['SMA1'].iloc[-2] > resam['SMA2'].iloc[-2]:
print('going long the market')
position = 1
#
# place trading code here (for buy order)
#
elif position == 1 and resam['SMA1'].iloc[-2] < resam['SMA2'].iloc[-2]:
print('going market neutral')
position = 0
#
# place trading code here (for sell order)
#
#if ticks % 10 == 0:
# h5 = pd.HDFStore('data.h5', 'w')
# h5['data'] = data
# h5.close()
#
# Simple Tick Trader LS with ZeroMQ
#
import zmq
import datetime
import pandas as pd
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect('tcp://127.0.0.1:5555')
socket.setsockopt_string(zmq.SUBSCRIBE, 'AAPL')
data = pd.DataFrame()
ticks = 0
position = 0
while ticks < 200:
ticks += 1
msg = socket.recv_string()
t = datetime.datetime.now()
sym, value = msg.split()
data = data.append(pd.DataFrame({sym: float(value)}, index=[t]))
resam = data.resample('2s', label='right').last()
resam['SMA1'] = resam['AAPL'].rolling(5).mean()
resam['SMA2'] = resam['AAPL'].rolling(10).mean()
resam.dropna(inplace=True)
if len(resam) > 2:
print('%3d | %s | ' % (ticks, str(t)), msg, '| %.3f | %.3f' %
(resam['SMA1'].iloc[-2], resam['SMA2'].iloc[-2]))
if position in [0, -1] and resam['SMA1'].iloc[-2] > resam['SMA2'].iloc[-2]:
print('going long the market')
position = 1
#
# place trading code here (for buy order)
#
elif position in [0, 1] and resam['SMA1'].iloc[-2] < resam['SMA2'].iloc[-2]:
print('going short the market')
position = -1
#
# place trading code here (for sell order)
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment