ADD: added optimizer workflow
This commit is contained in:
69
optimizers.py
Normal file
69
optimizers.py
Normal file
@@ -0,0 +1,69 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user