{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "6825d6e0", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from itertools import product\n", "plt.style.use(\"seaborn\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "6f552c7c", "metadata": {}, "outputs": [], "source": [ "import tpqoa\n", "api = tpqoa.tpqoa(\"oandaMY.cfg\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "e7aaa3b4", "metadata": {}, "outputs": [], "source": [ "class SMABacktester():\n", " ''' Classe per il backtesting di strategie SMA'''\n", " \n", " def __init__(self, symbol, SMA_s, SMA_l, start, end):\n", " '''\n", " Parametri\n", " ---------\n", " symbol: str\n", " simbolo del ticker per OANDA\n", " SMA_s: int\n", " finestra corta\n", " SMA_l: int\n", " finestra lunga\n", " start: str\n", " data di inizio\n", " end: str\n", " data di fine\n", " '''\n", " self._symbol = symbol\n", " self._SMA_s = SMA_s\n", " self._SMA_l = SMA_l\n", " self._start = start\n", " self._end = end\n", " self._results = None\n", " self.get_data()\n", " self.prepare_data()\n", " \n", " def __repr__(self):\n", " return \"SMABacktester(symbol = {}, SMA_s = {}, SMA_l = {}, start = {}, end = {})\".format(self._symbol,self._SMA_s,self.SMA_l,self._start,self._end)\n", " \n", " def get_data(self): # carica i dati\n", " df = api.get_history(instrument = self._symbol, start = self._start, end = self._end, granularity = \"D\", price = \"M\")[\"c\"].to_frame().dropna()\n", " df[\"logRet\"]=np.log(df/df.shift(1))\n", " self.data=df\n", " \n", " def prepare_data(self): # contruisce il dataframe internamente \n", " self.data[\"SMA_s\"]=self.data[\"c\"].rolling(self._SMA_s).mean()\n", " self.data[\"SMA_l\"]=self.data[\"c\"].rolling(self._SMA_l).mean()\n", " #return self.data\n", " \n", " def set_parameters(self, SMA_s=None, SMA_l=None):\n", " if SMA_s is not None:\n", " self._SMA_s = SMA_s\n", " self.data[\"SMA_s\"]=self.data.c.rolling(SMA_s).mean()\n", " if SMA_l is not None:\n", " self._SMA_l = SMA_l\n", " self.data[\"SMA_l\"]=self.data.c.rolling(SMA_l).mean()\n", "\n", " def test_strategy(self):\n", " data=self.data.copy().dropna()\n", " data[\"posizione\"]=np.where(data.SMA_s>data.SMA_l,+1,-1)\n", " data[\"strategia\"]= data.posizione.shift(1) * data.logRet\n", " data.dropna(inplace=True)\n", " data[\"cumLogRet\"]= data.logRet.cumsum()\n", " data[\"cumStrategia\"]= data.strategia.cumsum()\n", " # performance = np.exp(data.cumStrategia.iloc[-1])\n", " # outPerformance = performance - np.exp(data.cumLogRet.iloc[-1])\n", " performance = data.cumStrategia.iloc[-1]\n", " outPerformance = performance - data.cumLogRet.iloc[-1]\n", " maxDrawdown=(data.strategia.cumsum().cummax()-data.strategia.cumsum()).max()\n", " self._results=data\n", " return round(performance,6),round(outPerformance,6),round(maxDrawdown,6)\n", " \n", " def plot_results(self):\n", " if self._results is None:\n", " print(\"Devi prima chiamare test_strategy()\")\n", " else:\n", " titolo=\"{} SMA_S = {} SMA_L = {}\".format(self._symbol,self._SMA_s,self._SMA_l)\n", " self._results[[\"cumLogRet\",\"cumStrategia\"]].plot(figsize=(25,15))\n", " plt.legend(fontsize=18)\n", " plt.title(titolo,fontsize=22)\n", " \n", " def optimize_parameters(self, SMA_s_range, SMA_l_range): # ranges are tuples\n", " ''' Trova la stretgia ottimale all\\'interno dei range dei parametri indicati\n", " \n", " Parametri\n", " ---------\n", " SMA_s_range: tuple di 2 o 3 int\n", " inizio e fine (e eventualmente step) del range per la finestra corta\n", " SMA_l_range: tuple di 2 o 3 int\n", " inizio e fine (e eventualmente step) del range per la finestra corta\n", " '''\n", " \n", " combinazioni = list(product(range(SMA_s_range[0],SMA_s_range[1]),range(SMA_l_range[0],SMA_l_range[1]) ))\n", " # combinazioni = list(product(range(*SMA_s_range),range(*SMA_l_range) ))\n", " risultati= []\n", " for comb in combinazioni:\n", " self.set_parameters(comb[0],comb[1])\n", " risultati.append(self.test_strategy()[0])\n", " \n", " best_performance = np.max(risultati)\n", " best_combinazione = combinazioni[np.argmax(risultati)]\n", " \n", " # eseguiamo la strategia migliore\n", " self.set_parameters(best_combinazione[0],best_combinazione[1])\n", " self.test_strategy()\n", " \n", " # mettiamo i risulati in un bel dataframe\n", " AllResults = pd.DataFrame(combinazioni, columns=[\"SMA_s\",\"SMA_l\"])\n", " AllResults[\"performance\"]= risultati\n", " self.results_overview = AllResults\n", " \n", " return best_combinazione, best_performance\n", " " ] }, { "cell_type": "code", "execution_count": 10, "id": "a4797b41", "metadata": {}, "outputs": [], "source": [ "trainer=SMABacktester(\"EUR_USD\",50,250,\"2008-10-10\",\"2019-10-10\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "c0901207", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | c | \n", "logRet | \n", "SMA_s | \n", "SMA_l | \n", "
---|---|---|---|---|
time | \n", "\n", " | \n", " | \n", " | \n", " |
2008-10-09 21:00:00 | \n", "1.33977 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
2008-10-10 21:00:00 | \n", "1.33923 | \n", "-0.000403 | \n", "NaN | \n", "NaN | \n", "
2008-10-11 21:00:00 | \n", "1.35705 | \n", "0.013218 | \n", "NaN | \n", "NaN | \n", "
2008-10-12 21:00:00 | \n", "1.35818 | \n", "0.000832 | \n", "NaN | \n", "NaN | \n", "
2008-10-13 21:00:00 | \n", "1.36174 | \n", "0.002618 | \n", "NaN | \n", "NaN | \n", "
2008-10-14 21:00:00 | \n", "1.34977 | \n", "-0.008829 | \n", "NaN | \n", "NaN | \n", "
2008-10-15 21:00:00 | \n", "1.34543 | \n", "-0.003221 | \n", "NaN | \n", "NaN | \n", "
2008-10-16 21:00:00 | \n", "1.34033 | \n", "-0.003798 | \n", "NaN | \n", "NaN | \n", "
2008-10-18 21:00:00 | \n", "1.34210 | \n", "0.001320 | \n", "NaN | \n", "NaN | \n", "
2008-10-19 21:00:00 | \n", "1.33425 | \n", "-0.005866 | \n", "NaN | \n", "NaN | \n", "
2008-10-20 21:00:00 | \n", "1.30618 | \n", "-0.021262 | \n", "NaN | \n", "NaN | \n", "
2008-10-21 21:00:00 | \n", "1.28546 | \n", "-0.015990 | \n", "NaN | \n", "NaN | \n", "
2008-10-22 21:00:00 | \n", "1.29329 | \n", "0.006073 | \n", "NaN | \n", "NaN | \n", "
2008-10-23 21:00:00 | \n", "1.26160 | \n", "-0.024809 | \n", "NaN | \n", "NaN | \n", "
2008-10-25 21:00:00 | \n", "1.25535 | \n", "-0.004966 | \n", "NaN | \n", "NaN | \n", "
2008-10-26 21:00:00 | \n", "1.24929 | \n", "-0.004839 | \n", "NaN | \n", "NaN | \n", "
2008-10-27 21:00:00 | \n", "1.26809 | \n", "0.014936 | \n", "NaN | \n", "NaN | \n", "
2008-10-28 21:00:00 | \n", "1.29589 | \n", "0.021686 | \n", "NaN | \n", "NaN | \n", "
2008-10-29 21:00:00 | \n", "1.29129 | \n", "-0.003556 | \n", "NaN | \n", "NaN | \n", "
2008-10-30 21:00:00 | \n", "1.27163 | \n", "-0.015342 | \n", "NaN | \n", "NaN | \n", "
2008-11-01 21:00:00 | \n", "1.27429 | \n", "0.002090 | \n", "NaN | \n", "NaN | \n", "
2008-11-02 22:00:00 | \n", "1.26421 | \n", "-0.007942 | \n", "NaN | \n", "NaN | \n", "
2008-11-03 22:00:00 | \n", "1.29795 | \n", "0.026339 | \n", "NaN | \n", "NaN | \n", "
2008-11-04 22:00:00 | \n", "1.29542 | \n", "-0.001951 | \n", "NaN | \n", "NaN | \n", "
2008-11-05 22:00:00 | \n", "1.27144 | \n", "-0.018685 | \n", "NaN | \n", "NaN | \n", "
2008-11-06 22:00:00 | \n", "1.27134 | \n", "-0.000079 | \n", "NaN | \n", "NaN | \n", "
2008-11-07 22:00:00 | \n", "1.27110 | \n", "-0.000189 | \n", "NaN | \n", "NaN | \n", "
2008-11-08 22:00:00 | \n", "1.28110 | \n", "0.007836 | \n", "NaN | \n", "NaN | \n", "
2008-11-09 22:00:00 | \n", "1.27498 | \n", "-0.004789 | \n", "NaN | \n", "NaN | \n", "
2008-11-10 22:00:00 | \n", "1.25220 | \n", "-0.018028 | \n", "NaN | \n", "NaN | \n", "
2008-11-11 22:00:00 | \n", "1.25045 | \n", "-0.001399 | \n", "NaN | \n", "NaN | \n", "
2008-11-12 22:00:00 | \n", "1.27675 | \n", "0.020814 | \n", "NaN | \n", "NaN | \n", "
2008-11-13 22:00:00 | \n", "1.25997 | \n", "-0.013230 | \n", "NaN | \n", "NaN | \n", "
2008-11-15 22:00:00 | \n", "1.25311 | \n", "-0.005459 | \n", "NaN | \n", "NaN | \n", "
2008-11-16 22:00:00 | \n", "1.26498 | \n", "0.009428 | \n", "NaN | \n", "NaN | \n", "
2008-11-17 22:00:00 | \n", "1.26173 | \n", "-0.002573 | \n", "NaN | \n", "NaN | \n", "
2008-11-18 22:00:00 | \n", "1.24879 | \n", "-0.010309 | \n", "NaN | \n", "NaN | \n", "
2008-11-19 22:00:00 | \n", "1.24522 | \n", "-0.002863 | \n", "NaN | \n", "NaN | \n", "
2008-11-20 22:00:00 | \n", "1.25823 | \n", "0.010394 | \n", "NaN | \n", "NaN | \n", "
2008-11-22 22:00:00 | \n", "1.25858 | \n", "0.000278 | \n", "NaN | \n", "NaN | \n", "
2008-11-23 22:00:00 | \n", "1.29560 | \n", "0.028990 | \n", "NaN | \n", "NaN | \n", "
2008-11-24 22:00:00 | \n", "1.30635 | \n", "0.008263 | \n", "NaN | \n", "NaN | \n", "
2008-11-25 22:00:00 | \n", "1.28782 | \n", "-0.014286 | \n", "NaN | \n", "NaN | \n", "
2008-11-26 22:00:00 | \n", "1.29027 | \n", "0.001901 | \n", "NaN | \n", "NaN | \n", "
2008-11-27 22:00:00 | \n", "1.26859 | \n", "-0.016945 | \n", "NaN | \n", "NaN | \n", "
2008-11-28 22:00:00 | \n", "1.26859 | \n", "0.000000 | \n", "NaN | \n", "NaN | \n", "
2008-11-29 22:00:00 | \n", "1.27105 | \n", "0.001937 | \n", "NaN | \n", "NaN | \n", "
2008-11-30 22:00:00 | \n", "1.26089 | \n", "-0.008026 | \n", "NaN | \n", "NaN | \n", "
2008-12-01 22:00:00 | \n", "1.27131 | \n", "0.008230 | \n", "NaN | \n", "NaN | \n", "
2008-12-02 22:00:00 | \n", "1.27146 | \n", "0.000118 | \n", "1.287394 | \n", "NaN | \n", "
2008-12-03 22:00:00 | \n", "1.27756 | \n", "0.004786 | \n", "1.286150 | \n", "NaN | \n", "
2008-12-04 22:00:00 | \n", "1.27112 | \n", "-0.005054 | \n", "1.284787 | \n", "NaN | \n", "
2008-12-05 22:00:00 | \n", "1.27138 | \n", "0.000205 | \n", "1.283074 | \n", "NaN | \n", "
2008-12-06 22:00:00 | \n", "1.27246 | \n", "0.000849 | \n", "1.281360 | \n", "NaN | \n", "
2008-12-07 22:00:00 | \n", "1.29625 | \n", "0.018523 | \n", "1.280050 | \n", "NaN | \n", "