{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# AI-Powered Algorithmic Trading with Python\n", "\n", "**ODSC London 2022**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dr. Yves J. Hilpisch | The Python Quants & The AI Machine\n", "\n", "https://tpq.io | https://aimachine.io | [@dyjh](http://twitter.com/dyjh)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Case Study: AI-Powered Strategy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Oanda API " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import tpqoa\n", "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pylab import plt\n", "plt.style.use('seaborn')\n", "%config InlineBackend.figure_format = 'svg'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import warnings\n", "warnings.simplefilter('ignore')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oanda = tpqoa.tpqoa('../oanda.cfg')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Data " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "data = oanda.get_history(\n", " instrument='BCO_USD',\n", " start='2022-06-09',\n", " end='2022-06-10',\n", " granularity='S5',\n", " price='M'\n", ")\n", "data.info()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data['r'] = np.log(data['c'] / data['c'].shift(1))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data['d'] = np.sign(data['r'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Strategy " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lags = 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cols = list()\n", "for lag in range(1, lags + 1):\n", " col = f'lag_{lag}'\n", " data[col] = data['r'].shift(lag)\n", " cols.append(col)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data.dropna(inplace=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data['d'] = data['d'].astype(int)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Train-Test Split" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "split = int(len(data) * 0.8)\n", "split" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "train = data.iloc[:split].copy()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mu, std = train.mean(), train.std()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "train_ = (train - mu) / std" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test = data.iloc[split:].copy()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test_ = (test - mu) / std" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Training of the Model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.neural_network import MLPClassifier\n", "from sklearn.metrics import accuracy_score" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model = MLPClassifier(hidden_layer_sizes=[24],\n", " shuffle=False,\n", " max_iter=500)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model.fit(train_[cols], train['d'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "accuracy_score(train['d'], model.predict(train_[cols]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testing of the Model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test['p'] = model.predict(test_[cols])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "accuracy_score(test['d'], test['p'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test['s'] = test['p'] * test['r']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test[['r', 's']].sum().apply(np.exp)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test[['r', 's']].cumsum().apply(np.exp).plot();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Trading Code" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oanda.on_success??" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oanda.stream_data('BCO_USD', stop=10) # streaming data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oanda.create_order('BCO_USD', units=100) # opening long position" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oanda.create_order('BCO_USD', units=-100) # closing long position" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Simple Deployment" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model.predict(test[cols])[-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class MLPTrader(tpqoa.tpqoa):\n", " def __init__(self, config_file, model, lags):\n", " super().__init__(config_file)\n", " self.model = model\n", " self.min_length = lags\n", " self.position = 0\n", " self.units = 100\n", " self.tick_data = pd.DataFrame()\n", " def on_success(self, time, bid, ask):\n", " trade = False\n", " print(self.ticks, end=' ')\n", " df = pd.DataFrame({'b': bid, 'a': ask, 'm': (ask + bid) / 2},\n", " index=[pd.Timestamp(time).tz_localize(tz=None)])\n", " self.tick_data = pd.concat((self.tick_data, df))\n", " # resampling the tick data to 5 second intervals\n", " self.data = self.tick_data.resample('5s', label='right').last().ffill()\n", " self.data['r'] = np.log(self.data['m'] / self.data['m'].shift(1))\n", " # self.data['m'] = self.data['r'].rolling(self.momentum).mean()\n", " self.data.dropna(inplace=True)\n", " if len(self.data) > self.min_length:\n", " self.min_length += 1\n", " # checking for long signal\n", " prediction = self.model.predict(\n", " self.data['m'].iloc[-lags-1:-1].values.reshape(1, -1))\n", " print(prediction)\n", " if prediction == 1 and self.position in [0, -1]:\n", " o = oanda.create_order(self.stream_instrument,\n", " units=(1 - self.position) * self.units,\n", " suppress=True, ret=True)\n", " print('\\n*** GOING LONG ***')\n", " self.print_transactions(tid=int(o['id']) - 1)\n", " self.position = 1\n", " # checking for short signal\n", " elif prediction == -1 and self.position in [0, 1]:\n", " o = oanda.create_order(self.stream_instrument,\n", " units=-(1 + self.position) * self.units,\n", " suppress=True, ret=True)\n", " print('\\n*** GOING SHORT ***')\n", " self.print_transactions(tid=int(o['id']) - 1)\n", " self.position = -1 " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mt = MLPTrader('../oanda.cfg', model, lags=lags)\n", "mt.stream_data('BCO_USD', stop=150)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pprint import pprint\n", "o = mt.create_order('BCO_USD', units=-mt.position * mt.units,\n", " suppress=True, ret=True)\n", "print('\\n*** POSITION CLOSED ***')\n", "mt.print_transactions(tid=int(o['id']) - 1)\n", "print('\\n')\n", "pprint(o)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.12" } }, "nbformat": 4, "nbformat_minor": 4 }