{"id":208447,"date":"2024-07-05T09:23:48","date_gmt":"2024-07-05T13:23:48","guid":{"rendered":"https:\/\/ibkrcampus.com\/?p=208447"},"modified":"2024-08-12T15:24:58","modified_gmt":"2024-08-12T19:24:58","slug":"build-a-custom-backtester-with-python","status":"publish","type":"post","link":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/","title":{"rendered":"Build a Custom Backtester with Python"},"content":{"rendered":"\n<p><em>The post &#8220;Build a Custom Backtester with Python&#8221; first appeared on <a href=\"https:\/\/algotrading101.com\/learn\/build-my-own-custom-backtester-python\/\">AlgoTrading101<\/a>.<\/em><\/p>\n\n\n\n<p><em>Excerpt<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-what-is-a-backtester\">What is a backtester?<\/h2>\n\n\n\n<p>A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data. It helps traders hone their strategies and provides valuable feedback on potential performance.<\/p>\n\n\n\n<p>Read more about it here: <a href=\"https:\/\/algotrading101.com\/learn\/backtesting-guide\/\">https:\/\/algotrading101.com\/learn\/backtesting-guide\/<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why should I build a custom backtester with Python?<\/h2>\n\n\n\n<p>Building a custom backtester can be challenging but also rewarding. Here are some reasons why you might want to do it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Knowledge&nbsp;<\/strong>\u2013 building a custom backtester will expand your knowledge of coding, trading, and more.<\/li>\n\n\n\n<li><strong>Ownership and transparency<\/strong>&nbsp;\u2013 you will own the entire backtesting pipeline and have full transparency on how the signals are calculated, and how the trades are performed, and have your hand on everything that happens.<\/li>\n\n\n\n<li><strong>Personalization<\/strong>&nbsp;<strong>and customization<\/strong>&nbsp;\u2013 you will be able to completely customize your tool to include all your required features, and personalize it to your preferred user experience.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Why shouldn\u2019t I build a custom backtester with Python?<\/h2>\n\n\n\n<p>The reasons why you shouldn\u2019t build a custom backtester are the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>It\u2019s hard<\/strong>&nbsp;\u2013 building a good custom backtester with all the bells and whistles can be hard.<\/li>\n\n\n\n<li><strong>Existing tools<\/strong>&nbsp;\u2013 there are already backtesting tools out there with various degrees of quality. Moreover, you might be able to modify these existing tools to suit your specialized needs.<\/li>\n\n\n\n<li><strong>Requires maintenance and time<\/strong>&nbsp;\u2013 your backtester is as good as the amount of time and effort you\u2019re willing to put into it to improve its quality.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">What are some existing Python backtesters?<\/h2>\n\n\n\n<p>Some existing Python backtesters that you might want to check out are the following ones:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/algotrading101.com\/learn\/backtesting-py-guide\/\">Backtesting.py<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/algotrading101.com\/learn\/vectorbt-guide\/\">VectorBT<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/algotrading101.com\/learn\/quantconnect-guide\/\">QuantConnect<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/algotrading101.com\/learn\/backtrader-for-backtesting\/\">Backtrader<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/algotrading101.com\/learn\/blankly-backtesting-guide\/\">Blankly<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Getting started<\/h2>\n\n\n\n<p>In this article, we will be creating a simple skeleton of a custom Python backtester that should have the following features<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Modularity&nbsp;<\/strong>\u2013 we want the backtester to be modular so that parts can be easily reorganized, swapped, or built upon.<\/li>\n\n\n\n<li><strong>Extendability&nbsp;<\/strong>\u2013 the code should be easily extendable.<\/li>\n\n\n\n<li><strong>Support single and multi-asset strategies<\/strong><\/li>\n\n\n\n<li><strong>Have access to historical equity data and multiple data providers<\/strong><\/li>\n\n\n\n<li><strong>Incorporate trading fee commission<\/strong><\/li>\n\n\n\n<li><strong>Have performance metrics<\/strong><\/li>\n<\/ul>\n\n\n\n<p>To make this possible, we will need to have several key components which are the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Data Management<\/strong>: Handles the ingestion, storage, and retrieval of OHLCV data, as well as any alternative data sources for generating signals.<\/li>\n\n\n\n<li><strong>Signal Generation<\/strong>: Contains the logic for analyzing data and generating buy\/sell signals based on predefined strategies or indicators.<\/li>\n\n\n\n<li><strong>Execution Engine<\/strong>: Simulates the execution of trades based on signals, considering commissions, slippage, and optionally, bid-ask spreads.<\/li>\n\n\n\n<li><strong>Performance Evaluation<\/strong>: Calculates key performance metrics such as return, volatility, Sharpe ratio, drawdowns, etc., to evaluate the strategy\u2019s effectiveness.<\/li>\n\n\n\n<li><strong>Utilities<\/strong>: Includes logging, configuration management, and any other supportive functionality.<\/li>\n<\/ul>\n\n\n\n<p>For this, I\u2019ll be leveraging the power of several Python libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Poetry&nbsp;<\/strong>\u2013 this will allow us to control all the dependencies (<code>pip install poetry<\/code>)<\/li>\n\n\n\n<li><a><strong>OpenBB Platform<\/strong>&nbsp;\u2013 This will provide us with seamless access to market data across multiple providers. You can read more about it&nbsp;<\/a><a href=\"https:\/\/algotrading101.com\/learn\/openbb-platform-guide\/\">here<\/a>.<\/li>\n\n\n\n<li><strong>Pandas&nbsp;<\/strong>\u2013 A staple when handling data.<\/li>\n\n\n\n<li><strong>Numpy&nbsp;<\/strong>\u2013 The fundamental package for scientific computing.<\/li>\n\n\n\n<li><strong>Matplotlib<\/strong>&nbsp;\u2013 The usual plotting library. Can be replaced or removed depending on your needs.<\/li>\n\n\n\n<li><strong>Ruff, Black, and MyPy&nbsp;<\/strong>\u2013 Linters that I prefer (optional). You can read more about that&nbsp;<a href=\"https:\/\/algotrading101.com\/learn\/python-linters-guide\/\">here<\/a>.<\/li>\n<\/ul>\n\n\n\n<p>You can find the code in our GitHub repository. Onde cloned, you can install everything by running the following inside your fresh new environment:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">poetry install<\/pre>\n\n\n\n<p>Allow me to share a bit about my thinking pattern when approaching this.<\/p>\n\n\n\n<p>My overarching design aim is to have a set of modules that govern the outlined key components. In other words, I want to have a module that specializes in data management, a module for trade execution, and so on.<\/p>\n\n\n\n<p>This allows for ease of extendability, it helps to decouple the code, it makes it cleaner, and more. The main pain point I wanted to address here is how hard it is to easily extend and customize existing backtesters out there.<\/p>\n\n\n\n<p>What I disliked about quite a few backtesters is how hard it is to design and run multi-asset strategies, or the fact that they gate-keep the data, that they only allow trading of a particular asset class, and more. All of these things should be mitigated.<\/p>\n\n\n\n<p>The main type of design I was going for was Object Oriented Programming (OOP) where classes are used and it allows us to maintain the state of the backtesting process.<\/p>\n\n\n\n<p><strong>Note: All strategies shown are very basic and for demo and learning purposes only. Please don\u2019t try to use them<\/strong>&nbsp;<strong>in a real market setting.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating a data handler with the OpenBB Platform<\/h2>\n\n\n\n<p>Creating a data handler with the OpenBB Platform is a rather straightforward experience. All headaches based on different API conventions, different providers, messy outputs, data validation, and the like are being handled for us.<\/p>\n\n\n\n<p>It also mitigates the need to create custom classes for data validation and processing. It allows you to seamlessly have access to many data providers, over hundreds of data points, different asset classes, and more. It also guarantees what is returned based on the standard it implements.<\/p>\n\n\n\n<p>Saying that, I\u2019ll stick with just the equity assets and constrain it to daily candles. You can easily expand this and change it to your liking. I\u2019ll allow the user to change the provider, symbol, start and end dates.<\/p>\n\n\n\n<p>What I like about the OpenBB Platform is that it has endpoints that allow you to pass multiple tickers and this is one of them. This means that we are already on a good track of supporting multiple asset trading by passing a comma-separated list of symbols.<\/p>\n\n\n\n<p><a>To set up the OpenBB Platform, I advise following this guide&nbsp;<\/a><a href=\"https:\/\/algotrading101.com\/learn\/python-linters-guide\/\">here<\/a>.<\/p>\n\n\n\n<p>Here is the&nbsp;<code>DataHandler<\/code>&nbsp;code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\"\"\"Data handler module for loading and processing data.\"\"\"\n\nfrom typing import Optional\n\nimport pandas as pd\nfrom openbb import obb\n\n\nclass DataHandler:\n    \"\"\"Data handler class for loading and processing data.\"\"\"\n\n    def __init__(\n        self,\n        symbol: str,\n        start_date: Optional[str] = None,\n        end_date: Optional[str] = None,\n        provider: str = \"fmp\",\n    ):\n        \"\"\"Initialize the data handler.\"\"\"\n        self.symbol = symbol.upper()\n        self.start_date = start_date\n        self.end_date = end_date\n        self.provider = provider\n\n    def load_data(self) -&gt; pd.DataFrame | dict[str, pd.DataFrame]:\n        \"\"\"Load equity data.\"\"\"\n        data = obb.equity.price.historical(\n            symbol=self.symbol,\n            start_date=self.start_date,\n            end_date=self.end_date,\n            provider=self.provider,\n        ).to_df()\n\n        if \",\" in self.symbol:\n            data = data.reset_index().set_index(\"symbol\")\n            return {symbol: data.loc[symbol] for symbol in self.symbol.split(\",\")}\n\n        return data\n\n    def load_data_from_csv(self, file_path) -&gt; pd.DataFrame:\n        \"\"\"Load data from CSV file.\"\"\"\n        return pd.read_csv(file_path, index_col=\"date\", parse_dates=True)<\/pre>\n\n\n\n<p>Notice how it returns a dictionary of Pandas dataframes when multiple symbols are being passed. I\u2019ve also added a function that can load data from a custom CSV file and use the&nbsp;<code>date<\/code>&nbsp;column as its index. Feel free to expand and change this to your liking and needs.<\/p>\n\n\n\n<p>To get some data, all we need to do is to initialize the class and call the&nbsp;<code>load_data<\/code>&nbsp;method like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">data = DataHandler(\"AAPL\").load_data()\ndata.head()<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"1093\" height=\"215\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester.jpg\" alt=\"\" class=\"wp-image-208498 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester.jpg 1093w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-700x138.jpg 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-300x59.jpg 300w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-768x151.jpg 768w\" data-sizes=\"(max-width: 1093px) 100vw, 1093px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1093px; aspect-ratio: 1093\/215;\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-creating-a-strategy-processor\">Creating a strategy processor<\/h2>\n\n\n\n<p>The next step is to have a module that will process our strategies. By this, I mean to say something that would be able to generate signals based on the strategy requirements and append them to the data so that they can be used by the executor for backtesting.<\/p>\n\n\n\n<p>What I\u2019m going for here is something like a base class for Strategies that developers can inherit from, change, or build their own custom ones. I also want it to work seamlessly when multiple assets so it applies the same signal logic over multiple assets.<\/p>\n\n\n\n<p>Here is what the code for it looks like:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Strategy:\n    \"\"\"Base class for trading strategies.\"\"\"\n\n    def __init__(self, indicators: dict, signal_logic: Any):\n        \"\"\"Initialize the strategy with indicators and signal logic.\"\"\"\n        self.indicators = indicators\n        self.signal_logic = signal_logic\n\n    def generate_signals(\n        self, data: pd.DataFrame | dict[str, pd.DataFrame]\n    ) -&gt; pd.DataFrame | dict[str, pd.DataFrame]:\n        \"\"\"Generate trading signals based on the strategy's indicators and signal logic.\"\"\"\n        if isinstance(data, dict):\n            for _, asset_data in data.items():\n                self._apply_strategy(asset_data)\n        else:\n            self._apply_strategy(data)\n        return data\n\n    def _apply_strategy(self, df: pd.DataFrame) -&gt; None:\n        \"\"\"Apply the strategy to a single dataframe.\"\"\"\n        for name, indicator in self.indicators.items():\n            df[name] = indicator(df)\n\n        df[\"signal\"] = df.apply(lambda row: self.signal_logic(row), axis=1)\n        df[\"positions\"] = df[\"signal\"].diff().fillna(0)<\/pre>\n\n\n\n<p>It works by taking a dictionary of indicators that need to be computed and also the logic to use for generating the signals that can be -1 for selling and +1 for buying. It also keeps track of the positions we\u2019re in.<\/p>\n\n\n\n<p>The way it is coded right now is that we pass it lambda functions which it applies to the dataframe.<\/p>\n\n\n\n<p>Here\u2019s an example of how we can use it on the data we retrieved in the previous step:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">strategy = Strategy(\n    indicators={\n        \"sma_20\": lambda row: row[\"close\"].rolling(window=20).mean(),\n        \"sma_60\": lambda row: row[\"close\"].rolling(window=60).mean(),\n    },\n    signal_logic=lambda row: 1 if row[\"sma_20\"] &gt; row[\"sma_60\"] else -1,\n)\ndata = strategy.generate_signals(data)\ndata.tail()<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"1093\" height=\"252\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-2.jpg\" alt=\"\" class=\"wp-image-208501 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-2.jpg 1093w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-2-700x161.jpg 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-2-300x69.jpg 300w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/06\/algotrading101-backtester-2-768x177.jpg 768w\" data-sizes=\"(max-width: 1093px) 100vw, 1093px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1093px; aspect-ratio: 1093\/252;\" \/><\/figure>\n\n\n\n<p>In the above example, I created a slow and fast-moving average on the closing prices and then defined my trading logic where I want to long when the fast-moving average crosses over the slow-moving average and vice-versa.<\/p>\n\n\n\n<p>Now that we have a way to get data and generate trading signals, all we\u2019re missing is a way to actually run the backtest. This is the most complex part.<\/p>\n\n\n\n<p><em>Visit <a href=\"https:\/\/algotrading101.com\/learn\/build-my-own-custom-backtester-python\/\">AlgoTrading101<\/a><\/em> <em>to learn about the main backtester logic.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.<\/p>\n","protected":false},"author":815,"featured_media":136026,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[339,343,349,338,341],"tags":[851,17293,4659,1225,17360,1224,17294,595],"contributors-categories":[13746],"class_list":{"0":"post-208447","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-science","8":"category-programing-languages","9":"category-python-development","10":"category-ibkr-quant-news","11":"category-quant-development","12":"tag-algo-trading","13":"tag-backtester","14":"tag-matplotlib","15":"tag-numpy","16":"tag-openbb-library","17":"tag-pandas","18":"tag-poetry-python-library","19":"tag-python","20":"contributors-categories-algotrading101"},"pp_statuses_selecting_workflow":false,"pp_workflow_action":"current","pp_status_selection":"publish","acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Build a Custom Backtester with Python | IBKR Quant<\/title>\n<meta name=\"description\" content=\"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/208447\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Custom Backtester with Python\" \/>\n<meta property=\"og:description\" content=\"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/\" \/>\n<meta property=\"og:site_name\" content=\"IBKR Campus US\" \/>\n<meta property=\"article:published_time\" content=\"2024-07-05T13:23:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-08-12T19:24:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Igor Radovanovic\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Igor Radovanovic\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\n\t    \"@context\": \"https:\\\/\\\/schema.org\",\n\t    \"@graph\": [\n\t        {\n\t            \"@type\": \"NewsArticle\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#article\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/\"\n\t            },\n\t            \"author\": {\n\t                \"name\": \"Igor Radovanovic\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/b43b33f424bad38d84a7b78eb0193592\"\n\t            },\n\t            \"headline\": \"Build a Custom Backtester with Python\",\n\t            \"datePublished\": \"2024-07-05T13:23:48+00:00\",\n\t            \"dateModified\": \"2024-08-12T19:24:58+00:00\",\n\t            \"mainEntityOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/\"\n\t            },\n\t            \"wordCount\": 1325,\n\t            \"commentCount\": 0,\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2022\\\/04\\\/python-letters.png\",\n\t            \"keywords\": [\n\t                \"Algo Trading\",\n\t                \"Backtester\",\n\t                \"Matplotlib\",\n\t                \"NumPy\",\n\t                \"openbb library\",\n\t                \"Pandas\",\n\t                \"Poetry Python Library\",\n\t                \"Python\"\n\t            ],\n\t            \"articleSection\": [\n\t                \"Data Science\",\n\t                \"Programming Languages\",\n\t                \"Python Development\",\n\t                \"Quant\",\n\t                \"Quant Development\"\n\t            ],\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"CommentAction\",\n\t                    \"name\": \"Comment\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#respond\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"WebPage\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/\",\n\t            \"name\": \"Build a Custom Backtester with Python | IBKR Campus US\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\"\n\t            },\n\t            \"primaryImageOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#primaryimage\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2022\\\/04\\\/python-letters.png\",\n\t            \"datePublished\": \"2024-07-05T13:23:48+00:00\",\n\t            \"dateModified\": \"2024-08-12T19:24:58+00:00\",\n\t            \"description\": \"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"ReadAction\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"ImageObject\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/build-a-custom-backtester-with-python\\\/#primaryimage\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2022\\\/04\\\/python-letters.png\",\n\t            \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2022\\\/04\\\/python-letters.png\",\n\t            \"width\": 1000,\n\t            \"height\": 563,\n\t            \"caption\": \"Python\"\n\t        },\n\t        {\n\t            \"@type\": \"WebSite\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"name\": \"IBKR Campus US\",\n\t            \"description\": \"Financial Education from Interactive Brokers\",\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"SearchAction\",\n\t                    \"target\": {\n\t                        \"@type\": \"EntryPoint\",\n\t                        \"urlTemplate\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/?s={search_term_string}\"\n\t                    },\n\t                    \"query-input\": {\n\t                        \"@type\": \"PropertyValueSpecification\",\n\t                        \"valueRequired\": true,\n\t                        \"valueName\": \"search_term_string\"\n\t                    }\n\t                }\n\t            ],\n\t            \"inLanguage\": \"en-US\"\n\t        },\n\t        {\n\t            \"@type\": \"Organization\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\",\n\t            \"name\": \"Interactive Brokers\",\n\t            \"alternateName\": \"IBKR\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"logo\": {\n\t                \"@type\": \"ImageObject\",\n\t                \"inLanguage\": \"en-US\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\",\n\t                \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"width\": 669,\n\t                \"height\": 669,\n\t                \"caption\": \"Interactive Brokers\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\"\n\t            },\n\t            \"publishingPrinciples\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/about-ibkr-campus\\\/\",\n\t            \"ethicsPolicy\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/cyber-security-notice\\\/\"\n\t        },\n\t        {\n\t            \"@type\": \"Person\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/b43b33f424bad38d84a7b78eb0193592\",\n\t            \"name\": \"Igor Radovanovic\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/author\\\/igor-radovanovic\\\/\"\n\t        }\n\t    ]\n\t}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Build a Custom Backtester with Python | IBKR Quant","description":"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/208447\/","og_locale":"en_US","og_type":"article","og_title":"Build a Custom Backtester with Python","og_description":"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.","og_url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/","og_site_name":"IBKR Campus US","article_published_time":"2024-07-05T13:23:48+00:00","article_modified_time":"2024-08-12T19:24:58+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","type":"image\/png"}],"author":"Igor Radovanovic","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Igor Radovanovic","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#article","isPartOf":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/"},"author":{"name":"Igor Radovanovic","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/b43b33f424bad38d84a7b78eb0193592"},"headline":"Build a Custom Backtester with Python","datePublished":"2024-07-05T13:23:48+00:00","dateModified":"2024-08-12T19:24:58+00:00","mainEntityOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/"},"wordCount":1325,"commentCount":0,"publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","keywords":["Algo Trading","Backtester","Matplotlib","NumPy","openbb library","Pandas","Poetry Python Library","Python"],"articleSection":["Data Science","Programming Languages","Python Development","Quant","Quant Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/","url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/","name":"Build a Custom Backtester with Python | IBKR Campus US","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#primaryimage"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","datePublished":"2024-07-05T13:23:48+00:00","dateModified":"2024-08-12T19:24:58+00:00","description":"A backtester is a tool that allows you to test your algorithmic trading strategies against real historical asset data.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/build-a-custom-backtester-with-python\/#primaryimage","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","width":1000,"height":563,"caption":"Python"},{"@type":"WebSite","@id":"https:\/\/ibkrcampus.com\/campus\/#website","url":"https:\/\/ibkrcampus.com\/campus\/","name":"IBKR Campus US","description":"Financial Education from Interactive Brokers","publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ibkrcampus.com\/campus\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ibkrcampus.com\/campus\/#organization","name":"Interactive Brokers","alternateName":"IBKR","url":"https:\/\/ibkrcampus.com\/campus\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","width":669,"height":669,"caption":"Interactive Brokers"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/"},"publishingPrinciples":"https:\/\/www.interactivebrokers.com\/campus\/about-ibkr-campus\/","ethicsPolicy":"https:\/\/www.interactivebrokers.com\/campus\/cyber-security-notice\/"},{"@type":"Person","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/b43b33f424bad38d84a7b78eb0193592","name":"Igor Radovanovic","url":"https:\/\/www.interactivebrokers.com\/campus\/author\/igor-radovanovic\/"}]}},"jetpack_featured_media_url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2022\/04\/python-letters.png","_links":{"self":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/208447","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/users\/815"}],"replies":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/comments?post=208447"}],"version-history":[{"count":0,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/208447\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media\/136026"}],"wp:attachment":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media?parent=208447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/categories?post=208447"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/tags?post=208447"},{"taxonomy":"contributors-categories","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/contributors-categories?post=208447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}