Skip to content

Optimizers

from qtradex.optimizers import QPSO, LSGA, IPSE, AION, GridSearch, RLPPO, MouseWheelTuner

All optimizers follow the same interface:

opt = Optimizer(data, wallet=wallet, options=options)
results = opt.optimize(bot, **kwargs)

Common interface

__init__(data, wallet=None, options=None)

Parameter Type Default
data Data required
wallet WalletBase varies by optimizer
options options class instance OptionsClass()

optimize(bot, **kwargs)

Runs the optimization. bot is a BaseBot subclass instance. Extra **kwargs pass through to backtest(). Returns a dict mapping metric names to (score_dict, bot) tuples, or None for MouseWheelTuner.

Optimizers

QPSO — Quantum Particle Swarm Optimization

Particle-swarm optimizer. Particles mutate across epochs with neuroplastic memory and cyclic simulated annealing.

from qtradex.optimizers import QPSO, QPSOoptions

opts = QPSOoptions()
opt = QPSO(data, options=opts)
best = opt.optimize(bot)

QPSOoptions parameters:

Parameter Type Default Description
epochs float inf Max iterations
improvements int 100000 Stop after this many score improvements
cooldown int 0 Iterations after an improvement before checking improvement limit
lag float 0.5 Feed-back lag positions for score trends
top_percent float 0.9 Top fraction of candidates to keep in plot
plot_period int 100 Iterations between live score plots (0 = never)
fitness_ratios list or None None Tradeoff between early vs late fitness scores
fitness_period int 200 Split point for fitness ratio scoring
fitness_inversion callable rotation lambda Rotates metric priorities each iteration
cyclic_amplitude float 3 Mutation step oscillation amplitude
cyclic_freq int 1000 Iterations per hot/cold cycle
digress float 0.99 Best-score decay factor (multiply every digress_freq)
digress_freq int 2500 Iterations between best-score degradation
temperature float 2.0 Base mutation step size
synapses int 50 Number of successful parameter sets to remember
neurons list [] Active parameter indices (empty = all)
show_terminal bool True Print progress to terminal
print_tune bool False Print best tune on completion
timeout float 0 Max wall-clock seconds. 0 = no limit. Calls end_optimization() and exits cleanly when exceeded.

LSGA — Local Search Genetic Algorithm

Genetic algorithm that inherits QPSO internals. Adds a population, crossover, walk-forward consistency gate, drawdown gate, directional synapses, and optional momentum / regularization.

from qtradex.optimizers import LSGA, LSGAoptions

opts = LSGAoptions()
opt = LSGA(data, options=opts)
best = opt.optimize(bot)

LSGAoptions parameters (inherits all QPSOoptions, adds):

Parameter Type Default Description
population int 20 Candidates per generation
offspring int 10 Offspring generated per generation
top_ratio float 0.20 Fraction kept as elite (higher = more diversity)
processes int cpu_count() or 3 Parallel workers
erode float 0.9999 Candidate erosion rate
erode_freq int 200 Erosion frequency in iterations
append_tune str "" File path to write tunes to
skew_check_period int 2 Skew-memory check interval (set high to disable)
skew_mc_iterations int 70 Monte Carlo iterations per skew check
skew_perturbation float 0.002 Perturbation for skew detection
skew_sigma float 0.01 Skew penalty sigma
skew_memory_cap int 1000 Max skew-memory entries
select_data Data, None, or False None Walk-forward consistency gate. None = auto-split (2/3 train + 1/3 select), Data = explicit select set, False = disable
consistency_fn callable or None None Walk-forward consistency function
consistency_target float 1.5 Target train/select ADR ratio at full intensity
reg_penalty float 0.0 Ridge penalty for params near clamp edges (e.g. 0.15 = up to 15% penalty at edge)
acceptance_temp float 0.0 Stochastic acceptance temperature. 0 = deterministic; >0 = probabilistic (filters noise)
momentum_decay float 0.0 Per-parameter Adam-style momentum. 0 = no momentum; 0.9 = smooth mutation directions across generations

Overridden defaults from QPSOoptions: fitness_period=20, cyclic_freq=25, improvements=10000, temperature=1.

The result dict includes wf_culled, wf_survived, and wf_intensity keys with walk-through gate metadata. Synapses are now directional and weighted by success score — frequently successful parameter combos are preferred during replay, and mutations are biased toward previously successful directions.


Samples random 2- or 3-parameter subspaces exhaustively. Good for exploring the parameter landscape without gradient-following.

from qtradex.optimizers import GridSearch, GridSearchOptions

opts = GridSearchOptions()
opt = GridSearch(data, options=opts)
best = opt.optimize(bot)

GridSearchOptions parameters:

Parameter Type Default Description
iterations int 50 Number of random subspaces to try
grid_dims int 2 Params per subspace (2 or 3)
grid_points int 10 Points per axis. Total evaluations = grid_points^grid_dims (100 for 2D, 1000 for 3D)
grid_margin float 0.0 Fraction to trim from each clamp edge. 0.15 restricts search to interior 70% of range
processes int cpu_count() or 4 Parallel workers
show_terminal bool True Print progress to terminal
print_tune bool False Print best tune on completion
epochs float inf Max iterations
improvements int inf Stop after this many improvements
timeout float 0 Max wall-clock seconds. 0 = no limit. Saves best tunes via end_optimization() and exits cleanly when exceeded.

RLPPO — Proximal Policy Optimization (optional)

Reinforcement learning optimizer using PPO (stable-baselines3). Optional dependency: pip install qtradex[rl]. Falls back to 1000 random trials if the RL dependencies are not installed — you can use it as a lightweight random search optimizer without installing PyTorch or stable-baselines3.

from qtradex.optimizers import RLPPO, RLPPOoptions

opts = RLPPOoptions()
opt = RLPPO(data, options=opts)
best = opt.optimize(bot)

RLPPOoptions parameters:

Parameter Type Default Description
total_timesteps int 50000 Total backtests across training
learning_rate float 3e-4 PPO learning rate
gamma float 0.99 Discount factor
gae_lambda float 0.95 GAE lambda for advantage estimation
clip_range float 0.2 PPO clip range
ent_coef float 0.01 Entropy bonus (higher = more exploration)
n_steps int 512 Steps per PPO update
batch_size int 64 PPO batch size
n_epochs int 10 Epochs per PPO update
walk_forward bool True Split data 2/3 + 1/3; reward = 0.7train + 0.3val composite
verbose int 1 SB3 verbosity (0 = silent)
show_terminal bool True Print progress to terminal
print_tune bool False Print best tune on completion
select_data bool False No walk-forward split (use walk_forward instead)
timeout float 0 Max wall-clock seconds. 0 = no limit. Saves best tunes via end_optimization() and exits cleanly when exceeded.

GridSearch and RLPPO both call end_optimization() on completion — their best tunes are auto-saved just like the other optimizers.

The reward function uses a composite score: sortino * (1 - max_dd) * min(1, trades/30). The training environment is a Gymnasium wrapper around the backtest loop.


IPSE — Iterative Parametric Space Expansion

Expands the search space outward from profitable regions. Brute-forces one parameter at a time via linear sweep.

from qtradex.optimizers import IPSE, IPSEoptions

opts = IPSEoptions()
opt = IPSE(data, options=opts)
best = opt.optimize(bot)

IPSEoptions parameters:

Parameter Type Default Description
acceleration float 0.8 Space shrinking rate (lower = faster shrink)
space_size int 25 Candidates per parameter per sweep
processes int cpu_count() Parallel workers
show_terminal bool True Print progress to terminal
print_tune bool False Print best tune on completion
timeout float 0 Max wall-clock seconds. 0 = no limit. Calls end_optimization() and exits cleanly when exceeded.

AION — Adaptive Intelligent Optimization Network

Multi-agent optimizer with separate Mutator, Filter, Evaluator, and Learner agents sharing state through OptState. Uses quantum tunneling, elite preservation, smart skip, and bad-region memory.

from qtradex.optimizers import AION, AIONoptions

opts = AIONoptions()
opt = AION(data, options=opts)
best = opt.optimize(bot)

AIONoptions parameters:

Parameter Type Default Description
epochs float inf Max iterations
improvements int 100000 Stop after this many improvements
cooldown int 0 Iterations after an improvement before checking limit
show_terminal bool True Print progress to terminal
print_tune bool True Print best tune on completion
plot_period int 100 Plot interval
quantum_tunneling_prob float 0.05 Probability of 5x escape jump
min_temperature float 0.05 Minimum mutation temperature
max_temperature float 3.0 Maximum mutation temperature
synapses int 50 Successful parameter sets to remember
neurons list [] Active parameter indices (empty = all)
fitness_ratios list or None None Fit / out-of-fit scoring ratio
enable_cache bool True Cache evaluated (tune → score) pairs
elite_preservation int 3 Number of top candidates preserved per epoch
smart_skip_threshold int 10 Max consecutive skips before forced exploration
bad_region_memory int 50 Max bad-region entries to track
timeout float 0 Max wall-clock seconds. 0 = no limit. Calls end_optimization() and exits cleanly when exceeded.

MouseWheelTuner — Interactive GUI

Launches a Tkinter window with scrollable knobs for each tune parameter. No options class.

from qtradex.optimizers import MouseWheelTuner

opt = MouseWheelTuner(data, wallet)
opt.optimize(bot)  # Blocks until window is closed

No return value. Manual tuning via the GUI only.

Result dict

opt.optimize() returns dict[str, tuple[dict, BaseBot]] mapping metric names to results:

result["roi"]       # -> (score_dict, best_bot_for_roi)
result["sharpe"]    # -> (score_dict, best_bot_for_sharpe)
# ... per metric

Each score_dict has the metric values for that bot's backtest. Each best_bot is a fresh bot instance with the optimal .tune set.

MouseWheelTuner returns None.

LSGA result metadata

When LSGA runs with the walk-forward consistency gate enabled (select_data not False), the result dict includes three extra keys alongside the per-metric entries:

Key Type Description
wf_culled int Candidates eliminated by the consistency gate
wf_survived int Candidates that passed the gate
wf_intensity float Gate intensity at end of run (0–1, higher = stricter)