Metadata-Version: 2.4
Name: strategytester5
Version: 2.0.4
Summary: A Python-based MetaTrader strategy tester for the MetaTrader5 module
Author-email: Omega Joctan Msigwa <omegajoctan@gmail.com>
License: MIT License
        
        Copyright (c) 2025 Omega Joctan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
Project-URL: Homepage, https://strategytester5.com
Project-URL: Repository, https://github.com/MegaJoctan/StrategyTester5
Keywords: MetaTrader5,MetaTrader4,Strategytester,strategytesting,MT5,trading,forex,backtesting,algorithmic trading
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: polars
Requires-Dist: matplotlib
Requires-Dist: seaborn
Requires-Dist: tqdm
Requires-Dist: numba
Requires-Dist: scipy
Requires-Dist: plotly
Requires-Dist: kaleido
Requires-Dist: nbformat
Requires-Dist: metatrader5
Dynamic: license-file

## What is StrategyTester5?

The Full documentation is found here: [strategytester5.com](https://strategytester5.com)

StrategyTester5 (ST5) is a Python framework for building, testing, and optimizing algorithmic trading strategies using the MetaTrader 5 platform.

It extends the native [MetaTrader 5 Python API](https://pypi.org/project/metatrader5/) by adding high-performance backtesting, simulation, and data handling capabilities that are not available out of the box.

![mt5config](docs/images/banner.png)

<!-- !["mt5"](images/terminal.png "mt5-terminal") -->

## Why StrategyTester5?

The official MetaTrader5 Python API provides access to market data and trading operations — but it lacks a built-in way to efficiently backtest and simulate trading strategies.

StrategyTester5 fills this gap by providing:

- ⚡ Fast historical data streaming (ticks & bars)
- 🧠 MetaTrader5 trade simulation engine
- 🔄 Multi-symbol backtesting support
- 📊 Strategy testing workflows similar to MT5 Strategy Tester
- 🧩 Seamless integration with the native MetaTrader5 API

<br>

Instead of building your own testing infrastructure from scratch, ST5 gives you a complete environment to develop and validate trading systems in Python.

> Built for developers who want full control over their trading logic without leaving the MetaTrader 5 ecosystem.

## How it Works

It works by mimicking a similar trading environment to that of the MetaTrader5 terminal, it then simulates that trading environment against actual ticks and bars history from the terminal.

## 🚀 Free vs Premium

| Feature | Free | Premium |
|--------|------|---------|
| High-precision backtesting | ✅ | ✅ |
| Backtesting speed | Fast | ⚡ Ultra-fast |
| Multi-symbol & multi-timeframe strategies | ✅ | ✅ |
| Visual mode (MetaTrader5 simulation) | ❌ | ✅ |
| Strategy optimization | ❌ | ✅ |
| Advanced logging & debugging | ❌ | ✅ |
| Priority support | ❌ | ✅ |

[Get your premium copy today!](https://omegajoctan.gumroad.com/l/strategytester5-pro)

# Quick Start | Build & Test your First Trading Robot

Every trading robot project needs atleast two files. The main Python file and a JSON configuration file.

![essential files](docs/images/botandjson.png "bot.py config.json")

These files can be named anything but it a good practice to use bot for the main trading robot and tester.json for the configuration file as it contains the so-called *tester configurations*.

## Tester Configurations

```json title="tester.json"
{
    "tester": {
        "bot_name": "Simple Trading Robot",
        "symbols": ["USDJPY"],
        "timeframe": "H1",
        "start_date": "01.01.2026 00:00",
        "end_date": "27.03.2026 00:00",
        "modelling" : "1 minute OHLC",
        "deposit": 1000,
        "leverage": "1:100"
    }
}
```

These configurations resemble those needed to backtest a trading robot in MetaTrader5 GUI.
![mt5config](docs/images/mt5tester%20config.png)


## Nescessary Imports

Inside the main Python script (trading robot), you start by importing all necessary modules

```python title="bot.py"
import logging
import os
import sys

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
sys.path.insert(0, ROOT)  # insert(0) so it wins over other paths

from strategytester5.tester import StrategyTester
import MetaTrader5 as mt5
from strategytester5.trade_classes.Trade import CTrade
import json
```

## Importing JSON configurations (Optional)

Instead of importing tester configurations from a JSON file, you could have a dictionary with the right keys and values.

In this case, we have configurations from a JSON file in the same directory (folder) as the main script *bot.py* so, let's import those.

```python title="bot.py"
# Get path to the folder where this script lives
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

try:
    with open(os.path.join(BASE_DIR, "tester.json"), 'r', encoding='utf-8') as file: # reading a JSON file
        # Deserialize the file data into a Python object
        tester_configs = json.load(file)
except Exception as e:
    raise RuntimeError(e)
```

## Initializing MetaTrader5

Despite the strategy tester simulating the MetaTrader5 terminal, it still relies of the platform for crucial information from instruments (symbols) and a broker's account.

So, we have to initialize the MetaTrader5 terminal using it's native API as we'll need it later.

```python title="bot.py"
if not mt5.initialize():
    raise RuntimeError("Failed to initialize mt5.")
```

## StrategyTester Initialization

```python

tester = StrategyTester(tester_config=tester_configs["tester"], mt5_instance=mt5, logging_level=logging.DEBUG)
```

We also initialize the class CTrade (a submodule for easy and effective ways to manage trades)

```python title="bot.py"
# ---------------------- variables/optional ----------------------------

symbol = "USDJPY" # it should be one among the symbols in symbols list from tester.json (config file/dictionary)
timeframe = "PERIOD_H1"
magic_number = 10012026
slippage = 100
sl = 700
tp = 500

# ---------------------------------------------------------

m_trade = CTrade(terminal=tester.simulated_mt5, magic_number=magic_number, filling_type_symbol=symbol, deviation_points=slippage, logger=tester.logger)
```

## Trading Strategy

```python title="bot.py"
def pos_exists(magic: int, type: int) -> bool:
    
    """Check if position exists"""

    positions_found = tester.simulated_mt5.positions_get()
    for position in positions_found:
        if position.type == type and position.magic == magic:
            return True

    return False

symbol_info = tester.simulated_mt5.symbol_info(symbol=symbol)

def on_tick():
    
    """The main function that gets called upon the receival of new tick(s)"""

    tick_info = tester.simulated_mt5.symbol_info_tick(symbol=symbol)
    if tick_info is None:
        return

    ask = tick_info.ask
    bid = tick_info.bid
    
    pts = symbol_info.point

    if not pos_exists(magic=magic_number, type=mt5.POSITION_TYPE_BUY):  # If a position of such kind doesn't exist
        m_trade.buy(volume=0.01, symbol=symbol, price=ask, sl=ask - sl * pts, tp=ask + tp * pts, comment="Tester buy")  # we open a buy position

    if not pos_exists(magic=magic_number, type=mt5.POSITION_TYPE_SELL):  # If a position of such kind doesn't exist
        m_trade.sell(volume=0.01, symbol=symbol, price=bid, sl=bid + sl * pts, tp=bid - tp * pts, comment="Tester sell")  # we open a sell position
```

## Running the Backtest

All it takes is one function call.

```python
tester.run(on_tick_function=on_tick) # very important!
```
