This is a standalone, purely mathematical engine for running algorithmic trading backtests and optimizations. It operates exclusively on pre-loaded raw data and instantiated strategy objects.
To use the optimization features, you must have pygmo installed. Pygmo is used for advanced heuristic optimization (using the DE1220 algorithm and an island-model archipelago) to find the most robust strategy parameters.
pip install pygmo numba numpy(Note: pygmo may require conda or specific system libraries depending on your OS. Refer to the pygmo documentation for more details.)
types.py: Defines canonical data structures used throughout the engine. Most importantly, it definesDataTuple—a standard tuple of NumPy arrays(symbol, timestamps, opens, highs, lows, closes, volume).metrics.py: Containsnumba-optimized (JIT-compiled) risk metric calculations such ascalculate_sharpe,calculate_sortino,calculate_max_drawdown, andcalculate_value_at_risk. These are pure mathematical functions.backtest.py: Contains theexecute_backtestlogic. It takes a strategy instance and a list ofDataTuples, evaluates the strategy, and returns aBacktestResult(Net Profit, Win Rate, Sharpe, Sortino, Max Drawdown, etc.). Supports multiprocessing.optimize.py: Contains theexecute_optimizationlogic usingpygmo. It performs Walk-Forward Analysis (WFA) or single-period optimization over the raw data to find robust parameter combinations for a given strategy class.
This directory houses the foundational class and utilities that all trading strategies must inherit from.
BaseStrategy.py: TheBaseStrategyclass itself. Exposes user-friendly methods likebuy(),sell(), andclose().PositionManager.py: Tracks position sizing, entry prices, and calculates trade returns (handles both long and short positions).StrategyContext.py: Manages the execution state (current index) to strictly prevent look-ahead bias during historical simulation.IndicatorWrapper.py: Wraps indicators so they respect the current execution context and only return data up to the current simulation step.DataAccessor.py: Provides context-aware access to price data (self.data.close,self.data.high, etc.) during thenext()loop.
Because the engine is "dumb" and decoupled, you are responsible for feeding it clean DataTuples.
import numpy as np
from engine.base_strategy import BaseStrategy
from engine.backtest import execute_backtest
from engine.types import DataTuple
# 1. Define a strategy
class MyStrategy(BaseStrategy):
def next(self):
# Example logic: buy if close > open
if self.data.close[-1] > self.data.open[-1]:
self.buy(1.0)
else:
self.close()
# 2. Prepare raw data (symbol, timestamps, opens, highs, lows, closes, volumes)
data: DataTuple = (
"AAPL",
np.array([1, 2, 3]),
np.array([100, 101, 102]),
np.array([101, 103, 104]),
np.array([99, 100, 101]),
np.array([101, 102, 103]),
np.array([1000, 1500, 1200])
)
# 3. Execute
strategy_instance = MyStrategy()
results = execute_backtest(
strategy_instance=strategy_instance,
data_list=[data],
multiprocess=False
)
print(results)The optimizer requires your strategy to implement validate_params and get_optimization_params.
from engine.optimize import execute_optimization
class MyOptimizableStrategy(BaseStrategy):
def validate_params(self, **kwargs):
return True
@staticmethod
def get_optimization_params():
# param_name: (min, max)
return {
"ma_period": (10, 50),
"threshold": (1.0, 5.0)
}
# ... implement next() using kwargs ...
# Execute Walk-Forward Optimization
best_params_results = execute_optimization(
strategy_class=MyOptimizableStrategy,
data=data,
pop=40, # Population size per island
gen=50, # Generations
single=False # Set True for single-period optimization instead of WFA
)
print("Best Parameters from Walk-Forward Analysis:", best_params_results)