Skip to content

Instantly share code, notes, and snippets.

@yhilpisch
Last active October 29, 2017 07:53
Show Gist options
  • Save yhilpisch/b7abecc35ff1b87666b6fff2df16381d to your computer and use it in GitHub Desktop.
Save yhilpisch/b7abecc35ff1b87666b6fff2df16381d 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, 22. & 29. October 2017

Resources

Slides

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

Python

If you have either Miniconda or Anaconda already installed, there is no need to install anything new.

The code that follows uses Python 3.6. For example, download and install Miniconda 3.6 from https://conda.io/miniconda.html if you do not have conda already installed.

In any case, for Linux/Mac you should execute the following lines on the shell to create a new environment with the needed packages:

conda create -n fxcm python=3.6
source activate fxcm
conda install numpy pandas matplotlib statsmodels
pip install plotly cufflinks
conda install ipython jupyter
jupyter notebook

On Windows, execute the following lines on the command prompt:

conda create -n fxcm python=3.6
activate fxcm
conda install numpy pandas matplotlib statsmodels
pip install plotly cufflinks
pip install win-unicode-console
set PYTHONIOENCODING=UTF-8
conda install ipython jupyter
jupyter notebook

Read more about the management of environments under https://conda.io/docs/using/envs.html

ZeroMQ

The major resource for the ZeroMQ distributed messaging package based on sockets is http://zeromq.org/

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": [
"class FinancialData(object):\n",
" def __init__(self, symbol):\n",
" self.symbol = symbol\n",
" self.prepare_data()\n",
" \n",
" def prepare_data(self):\n",
" self.raw = pd.read_csv('http://hilpisch.com/tr_eikon_eod_data.csv',\n",
" index_col=0, parse_dates=True)\n",
" self.data = pd.DataFrame(self.raw[self.symbol])\n",
" self.data['Returns'] = np.log(self.data / self.data.shift(1))\n",
" \n",
" def plot_data(self, cols=None):\n",
" if cols is None:\n",
" cols = [self.symbol]\n",
" self.data[cols].plot(figsize=(10, 6), title=self.symbol)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"fd = FinancialData('AAPL.O')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'pandas.core.frame.DataFrame'>\n",
"DatetimeIndex: 1960 entries, 2010-01-04 to 2017-10-13\n",
"Data columns (total 2 columns):\n",
"AAPL.O 1960 non-null float64\n",
"Returns 1959 non-null float64\n",
"dtypes: float64(2)\n",
"memory usage: 45.9 KB\n"
]
}
],
"source": [
"fd.data.info()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>AAPL.O</th>\n",
" <th>Returns</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>2010-01-04</th>\n",
" <td>30.572827</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-05</th>\n",
" <td>30.625684</td>\n",
" <td>0.001727</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-06</th>\n",
" <td>30.138541</td>\n",
" <td>-0.016034</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-07</th>\n",
" <td>30.082827</td>\n",
" <td>-0.001850</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-08</th>\n",
" <td>30.282827</td>\n",
" <td>0.006626</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" AAPL.O Returns\n",
"Date \n",
"2010-01-04 30.572827 NaN\n",
"2010-01-05 30.625684 0.001727\n",
"2010-01-06 30.138541 -0.016034\n",
"2010-01-07 30.082827 -0.001850\n",
"2010-01-08 30.282827 0.006626"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fd.data.head()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x1129ccf28>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fd.plot_data()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Event-based View on Data"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x112a55240>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# vectorized data handling = complete data set in a single step\n",
"# fd.data['AAPL.O'].plot(figsize=(10, 6));\n",
"fd.plot_data()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"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 bar in range(10):\n",
" print(bar)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import time"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 30.57282657\n",
"1 30.62568366\n",
"2 30.13854129\n",
"3 30.08282706\n",
"4 30.28282686\n",
"5 30.01568427\n",
"6 29.67425604\n",
"7 30.09282705\n",
"8 29.91854151\n",
"9 29.41854201\n"
]
}
],
"source": [
"# event-based view on data = going bar by bar \"through time\"\n",
"for bar in range(10):\n",
" print(bar, fd.data['AAPL.O'].iloc[bar])\n",
" time.sleep(.2)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 2010-01-04 30.57282657\n",
"1 2010-01-05 30.62568366\n",
"2 2010-01-06 30.13854129\n",
"3 2010-01-07 30.08282706\n",
"4 2010-01-08 30.28282686\n",
"5 2010-01-11 30.01568427\n",
"6 2010-01-12 29.67425604\n",
"7 2010-01-13 30.09282705\n",
"8 2010-01-14 29.91854151\n",
"9 2010-01-15 29.41854201\n"
]
}
],
"source": [
"# event-based view on data = going bar by bar \"through time\"\n",
"for bar in range(10):\n",
" print(bar, str(fd.data['AAPL.O'].index[bar])[:10], fd.data['AAPL.O'].iloc[bar])\n",
" time.sleep(.2)"
]
},
{
"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",
"* `prepare_data` (`FinancialBase`)\n",
"* `plot_data` (`FinancialBase`)\n",
"* `get_date_price`\n",
"* `print_balance`\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": [
"amount = 5000\n",
"price = 27.85"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"179"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"units = math.floor(amount / price)\n",
"units"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4985.150000000001"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cost = units * price\n",
"cost"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class BacktestingBase(FinancialData):\n",
" def __init__(self, symbol, amount, verbose=True):\n",
" super(BacktestingBase, self).__init__(symbol)\n",
" self.amount = amount\n",
" self.initial_amount = amount\n",
" self.verbose = verbose\n",
" self.units = 0\n",
" self.trades = 0\n",
" \n",
" def get_date_price(self, bar):\n",
" date = str(self.data[self.symbol].index[bar])[:10]\n",
" price = self.data[self.symbol].iloc[bar]\n",
" return date, price\n",
" \n",
" def print_balance(self, bar):\n",
" date, price = self.get_date_price(bar)\n",
" print('%s | current cash balance is %8.2f' % (date, self.amount))\n",
" \n",
" def place_buy_order(self, bar, units=None, amount=None):\n",
" date, price = self.get_date_price(bar)\n",
" if amount is not None:\n",
" units = math.floor(amount / price)\n",
" self.amount -= units * price\n",
" self.units += units\n",
" self.trades += 1\n",
" if self.verbose is True:\n",
" print('%s | buying %3d units for %8.2f' % (date, units, price))\n",
" self.print_balance(bar)\n",
" \n",
" def place_sell_order(self, bar, units=None, amount=None):\n",
" date, price = self.get_date_price(bar)\n",
" if amount is not None:\n",
" units = math.floor(amount / price)\n",
" self.amount += units * price\n",
" self.units -= units\n",
" self.trades += 1\n",
" if self.verbose is True:\n",
" print('%s | selling %3d units for %8.2f' % (date, units, price))\n",
" self.print_balance(bar)\n",
" \n",
" def close_out(self, bar):\n",
" date, price = self.get_date_price(bar)\n",
" self.amount += self.units * price\n",
" print(50 * '=')\n",
" print('Closing out the position.')\n",
" print(50 * '=')\n",
" if self.units != 0:\n",
" self.trades += 1\n",
" print('%s | selling %3d units for %8.2f' % (date, self.units, price))\n",
" self.units -= self.units\n",
" self.print_balance(bar)\n",
" perf = ((self.amount - self.initial_amount) / self.initial_amount) * 100\n",
" print('%s | net performance %8.2f' % (date, perf))"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"bb = BacktestingBase('AAPL.O', 10000)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'pandas.core.frame.DataFrame'>\n",
"DatetimeIndex: 1960 entries, 2010-01-04 to 2017-10-13\n",
"Data columns (total 2 columns):\n",
"AAPL.O 1960 non-null float64\n",
"Returns 1959 non-null float64\n",
"dtypes: float64(2)\n",
"memory usage: 45.9 KB\n"
]
}
],
"source": [
"bb.data.info()"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('2010-11-01', 43.454242260000008)"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bb.get_date_price(209)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-11-01 | current cash balance is 10000.00\n"
]
}
],
"source": [
"bb.print_balance(209)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2010-11-01 | buying 15 units for 43.45\n",
"2010-11-01 | current cash balance is 9348.19\n"
]
}
],
"source": [
"bb.place_buy_order(209, units=15)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15 1\n"
]
}
],
"source": [
"print(bb.units, bb.trades)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2011-01-13 | buying 40 units for 49.38\n",
"2011-01-13 | current cash balance is 7372.87\n"
]
}
],
"source": [
"bb.place_buy_order(260, amount=2000)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"55 2\n"
]
}
],
"source": [
"print(bb.units, bb.trades)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2011-03-14 | selling 40 units for 50.51\n",
"2011-03-14 | current cash balance is 9393.21\n"
]
}
],
"source": [
"bb.place_sell_order(300, units=40)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2011-05-24 | selling 10 units for 47.46\n",
"2011-05-24 | current cash balance is 9867.77\n"
]
}
],
"source": [
"bb.place_sell_order(350, amount=500)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5 4\n"
]
}
],
"source": [
"print(bb.units, bb.trades)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2011-08-04 | selling 5 units for 53.91\n",
"2011-08-04 | current cash balance is 10137.32\n",
"2011-08-04 | net performance 1.37\n"
]
}
],
"source": [
"bb.close_out(400)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Long Only Backtesting Class"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"class LongOnlyBacktest(BacktestingBase):\n",
" # def __init__(self, *args):\n",
" # super(LongOnlyBacktest, self).__init__(*args)\n",
" \n",
" def run_strategy(self, SMA1, SMA2):\n",
" print('\\n\\nRunning strategy for %s | SMA1=%d | SMA2=%d' % (self.symbol, SMA1, SMA2))\n",
" print(50 * '=')\n",
" self.units = 0\n",
" self.trades = 0\n",
" self.position = 0\n",
" self.results = self.data.copy()\n",
" self.results['SMA1'] = self.results[self.symbol].rolling(SMA1).mean()\n",
" self.results['SMA2'] = self.results[self.symbol].rolling(SMA2).mean()\n",
" \n",
" for bar in range(SMA2 - 1, len(self.results)):\n",
" \n",
" if self.position == 0:\n",
" if self.results['SMA1'].iloc[bar] > self.results['SMA2'].iloc[bar]:\n",
" # self.place_buy_order(bar, units=100)\n",
" # self.place_buy_order(bar, amount=self.amount)\n",
" self.place_buy_order(bar, amount=5000)\n",
" date, price = self.get_date_price(bar)\n",
" self.entry_cost = self.units * price\n",
" # place whatever logic reflects your strategy\n",
" self.position = 1\n",
" \n",
" \n",
" if self.position == 1:\n",
" if self.results['SMA1'].iloc[bar] < self.results['SMA2'].iloc[bar]:\n",
" # self.place_sell_order(bar, units=100)\n",
" self.place_sell_order(bar, units=self.units)\n",
" self.position = 0\n",
" # stop loss logic (pls double check this code)\n",
" else:\n",
" date, price = self.get_date_price(bar)\n",
" current_position_value = self.units * price\n",
" if self.entry_cost - current_position_value > 1000:\n",
" # self.place_sell_order(bar, units=self.units)\n",
" self.close_out(bar)\n",
" self.position = 0\n",
" self.entry_cost = 0\n",
" # add more logic to make this really working\n",
" # avoid immediate re-entering the market\n",
" return 'Closing out due to stop loss.'\n",
" \n",
" self.close_out(bar)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"sma = LongOnlyBacktest('AAPL.O', 10000, True)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=42 | SMA2=252\n",
"==================================================\n",
"2010-12-31 | buying 108 units for 46.08\n",
"2010-12-31 | current cash balance is 5023.36\n",
"2012-12-18 | selling 108 units for 76.27\n",
"2012-12-18 | current cash balance is 13260.67\n",
"2013-10-03 | buying 72 units for 69.06\n",
"2013-10-03 | current cash balance is 8288.46\n",
"2015-09-08 | selling 72 units for 112.31\n",
"2015-09-08 | current cash balance is 16374.78\n",
"2016-09-09 | buying 48 units for 103.13\n",
"2016-09-09 | current cash balance is 11424.54\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 48 units for 156.99\n",
"2017-10-13 | current cash balance is 18960.06\n",
"2017-10-13 | net performance 89.60\n"
]
}
],
"source": [
"sma.run_strategy(42, 252)"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"sma = LongOnlyBacktest('AAPL.O', 10000, False)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=42 | SMA2=252\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 48 units for 156.99\n",
"2017-10-13 | current cash balance is 18960.06\n",
"2017-10-13 | net performance 89.60\n"
]
}
],
"source": [
"sma.run_strategy(42, 252)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=30 | SMA2=180\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 45 units for 156.99\n",
"2017-10-13 | current cash balance is 27339.59\n",
"2017-10-13 | net performance 173.40\n"
]
}
],
"source": [
"sma.run_strategy(30, 180)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from itertools import product"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"AAPL.O\n",
"MSFT.O\n",
"INTC.O\n",
"AMZN.O\n",
"GS.N\n",
"SPY\n",
".SPX\n",
".VIX\n",
"EUR=\n",
"XAU=\n"
]
}
],
"source": [
"for sym in sma.raw.columns.values:\n",
" print(sym)"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=30 | SMA2=180\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 45 units for 156.99\n",
"2017-10-13 | current cash balance is 18379.53\n",
"2017-10-13 | net performance 83.80\n",
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=30 | SMA2=252\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 46 units for 156.99\n",
"2017-10-13 | current cash balance is 26991.50\n",
"2017-10-13 | net performance 169.92\n",
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=42 | SMA2=180\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 46 units for 156.99\n",
"2017-10-13 | current cash balance is 37531.15\n",
"2017-10-13 | net performance 275.31\n",
"\n",
"\n",
"Running strategy for AAPL.O | SMA1=42 | SMA2=252\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 48 units for 156.99\n",
"2017-10-13 | current cash balance is 46491.21\n",
"2017-10-13 | net performance 364.91\n",
"\n",
"\n",
"Running strategy for MSFT.O | SMA1=30 | SMA2=180\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 88 units for 77.49\n",
"2017-10-13 | current cash balance is 13136.12\n",
"2017-10-13 | net performance 31.36\n",
"\n",
"\n",
"Running strategy for MSFT.O | SMA1=30 | SMA2=252\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 104 units for 77.49\n",
"2017-10-13 | current cash balance is 16750.51\n",
"2017-10-13 | net performance 67.51\n",
"\n",
"\n",
"Running strategy for MSFT.O | SMA1=42 | SMA2=180\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 86 units for 77.49\n",
"2017-10-13 | current cash balance is 20127.44\n",
"2017-10-13 | net performance 101.27\n",
"\n",
"\n",
"Running strategy for MSFT.O | SMA1=42 | SMA2=252\n",
"==================================================\n",
"==================================================\n",
"Closing out the position.\n",
"==================================================\n",
"2017-10-13 | selling 93 units for 77.49\n",
"2017-10-13 | current cash balance is 22061.81\n",
"2017-10-13 | net performance 120.62\n"
]
}
],
"source": [
"for sym in ['AAPL.O', 'MSFT.O']:\n",
" sma = LongOnlyBacktest(sym, 10000, False)\n",
" for SMA1, SMA2 in product([30, 42], [180, 252]):\n",
" sma.run_strategy(SMA1, SMA2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Some improvements (as an exercise):\n",
"\n",
"* long-short strategies\n",
"* include different signals (momentum)\n",
"* include proportional and fixed transaction costs\n",
"* allow for different time periods for the backtest\n",
"* incorporate stop loss"
]
},
{
"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.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
#
# Simple Tick Data Client
#
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, '')
while True:
msg = socket.recv_string()
t = datetime.datetime.now()
print(str(t) + ' | ' + msg)
#
# Simple Tick Data Collector
#
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, '')
raw = pd.DataFrame()
while True:
msg = socket.recv_string()
t = datetime.datetime.now()
print(str(t) + ' | ' + msg)
symbol, price = msg.split()
raw = raw.append(pd.DataFrame({'SYM': symbol, 'PRICE': price}, index=[t]))
data = raw.resample('5s', label='right').last()
if len(data) % 4 == 0:
print(50 * '=')
print(data.tail())
print(50 * '=')
# simple way of storing data, needs to be adjusted for your purposes
if len(data) % 20 == 0:
# h5 = pd.HDFStore('database.h5', 'a')
# h5['data'] = data
# h5.close()
pass
#
# Simple Tick Data Server
#
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 %.3f' % AAPL
socket.send_string(msg)
print(msg)
time.sleep(random.random() * 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment