Files
TradingBot2/optimizers.py
2026-01-23 18:22:56 +01:00

70 lines
2.1 KiB
Python

import os
from typing import Dict, Any
import strategies
from optimizer import run_optimized_backtest
class Optimizer:
"""Base optimizer wrapper tying a strategy to an optimization grid."""
name = 'BaseOptimizer'
strategy_cls = None
optimize_kwargs: Dict[str, Any] = None
@classmethod
def run(cls, symbol):
# pass optimizer name as report_tag so output files are unique per optimizer
return run_optimized_backtest(symbol, strategy_cls=cls.strategy_cls, optimize_kwargs=cls.optimize_kwargs, report_tag=cls.name)
class RsiOptimizer(Optimizer):
name = 'RsiOptimizer'
strategy_cls = strategies.RsiStrategy
def constraint(p):
return p.rsi_upper > p.rsi_lower
optimize_kwargs = dict(
rsi_period=range(7, 30, 2),
rsi_lower=range(20, 40, 5),
rsi_upper=range(60, 80, 5),
maximize='Return [%]',
constraint=constraint,
atr_period=range(10, 20, 2),
stop_loss_atr_multiplier=[2.0, 2.5, 3.0, 3.5, 4.0],
)
class CrossEmaOptimizer(Optimizer):
name = 'CrossEmaOptimizer'
strategy_cls = strategies.CrossEmaStrategy
def constraint(p):
# ensure long EMA period is greater than short EMA period
return p.long_ema > p.short_ema
optimize_kwargs = dict(
short_ema=range(5, 20, 3),
long_ema=range(20, 60, 5),
maximize='Return [%]',
constraint=constraint,
atr_period=range(10, 20, 2),
stop_loss_atr_multiplier=[2.0, 2.5, 3.0, 3.5],
finalize_trades=False, # run final backtest with best params
)
def get_optimizer_by_name(name: str):
mapping = {cls.name: cls for cls in (RsiOptimizer, CrossEmaOptimizer)}
# allow passing class name as well
if name in mapping:
return mapping[name]
# try attribute lookup in module
cls = getattr(__import__('optimizers'), name, None)
return cls
def run_optimizer(symbol: str, optimizer_name: str):
cls = get_optimizer_by_name(optimizer_name)
if cls is None:
raise ValueError(f"Optimizer '{optimizer_name}' not found")
return cls.run(symbol)