Skip to content

Instantly share code, notes, and snippets.

@sharavsambuu
Last active April 6, 2024 14:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sharavsambuu/37ca6c7d574e0c361027688e4b28fa4b to your computer and use it in GitHub Desktop.
Save sharavsambuu/37ca6c7d574e0c361027688e4b28fa4b to your computer and use it in GitHub Desktop.
NSGA2 with DEAP and multi attributes with bounds
#%%
import warnings
warnings.filterwarnings("ignore")
def action_with_warnings():
warnings.warn("should not appear")
with warnings.catch_warnings(record=True):
action_with_warnings()
import sys
sys.path.insert(0, '.')
import os
import csv
import time
import math
import glob
import zipfile
import random
import pandas as pd
import numpy as np
import mplfinance as mpf
import matplotlib.pyplot as plt
import pyfolio as pf
from scipy.stats import norm
from backtesting import Backtest, Strategy
from tqdm import trange
from deap import base, creator, tools
#%%
#%%
#%%
NGEN = 200 # total generations
NPOP = 100 # total population number
CXPB = 0.5 # cross over probability is 50 percent
MUTPB = 0.3 # mutation probability is 30 percent
creator.create("Fitness", base.Fitness, weights=(1.0, -1.0,)) # maximize and minimize which is two different objectives
creator.create("Individual", list, fitness=creator.Fitness)
# register some handy functions for calling
toolbox = base.Toolbox()
toolbox.register("indices" , random.sample, range(NPOP), NPOP)
# definition of an individual & a population
MAFAST_LOWER = 10.0
MAFAST_UPPER = 200.0
MAFAST_N = 140
MASLOW_LOWER = 50.0
MASLOW_UPPER = 450.0
MASLOW_N = 400
PCT_EPS_LOWER = 0.05
PCT_EPS_UPPER = 10.0
PCT_EPS_N = 100
def ma_fast_attribute() : return random.choice(list(np.random.uniform(size=MAFAST_N , low=MAFAST_LOWER , high=MAFAST_UPPER )))
def ma_slow_attribute() : return random.choice(list(np.random.uniform(size=MASLOW_N , low=MASLOW_LOWER , high=MASLOW_UPPER )))
def pct_epsilon_attribute(): return random.choice(list(np.random.uniform(size=PCT_EPS_N, low=PCT_EPS_LOWER, high=PCT_EPS_UPPER)))
toolbox.register("attr_ma_fast" , ma_fast_attribute )
toolbox.register("attr_ma_slow" , ma_slow_attribute )
toolbox.register("attr_pct_epsilon", pct_epsilon_attribute)
toolbox.register(
"individual", tools.initCycle, creator.Individual,
(toolbox.attr_ma_fast, toolbox.attr_ma_slow, toolbox.attr_pct_epsilon)
)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# crossover strategy
toolbox.register("mate" , tools.cxUniform, indpb=CXPB) # indpb is probability of exchanging a gene between the parents
# mutation strategy
toolbox.register("mutate" , tools.mutGaussian, mu=0.0, sigma=2.0, indpb=0.1/3)
# selection strategy
toolbox.register("select" , tools.selNSGA2)
# fitness function
PARAM_NAMES = ["ma_fast", "ma_slow", "pct_epsilon"]
def evaluate(individual):
strategy_params = {k: v for k, v in zip(PARAM_NAMES, individual)}
if not (MAFAST_LOWER<strategy_params['ma_fast'] and strategy_params['ma_fast']<MAFAST_UPPER):
return [-np.inf, np.inf]
if not (MASLOW_LOWER<strategy_params['ma_slow'] and strategy_params['ma_slow']<MASLOW_UPPER):
return [-np.inf, np.inf]
if not (PCT_EPS_LOWER<strategy_params['pct_epsilon'] and strategy_params['pct_epsilon']<PCT_EPS_UPPER):
return [-np.inf, np.inf]
if not (strategy_params['ma_fast']<strategy_params['ma_slow']):
return [-np.inf, np.inf]
print(f"evaluation : {individual}")
return [random.randrange(-100, 100+1,1), random.randrange(-10, 10+1, 1)]
toolbox.register("evaluate", evaluate)
hall_of_fame = tools.HallOfFame(maxsize=5)
t = time.perf_counter()
pop = toolbox.population(n=NPOP)
for g in trange(NGEN):
# Select the next generation individuals
offspring = toolbox.select(pop, len(pop))
# Clone the selected individuals
offspring = list(map(toolbox.clone, offspring))
# Apply crossover on the offspring
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < CXPB:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values
# Apply mutation on the offspring
for mutant in offspring:
if random.random() < MUTPB:
toolbox.mutate(mutant)
del mutant.fitness.values
# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# The population is entirely replaced by the offspring
pop[:] = offspring
hall_of_fame.update(pop)
print(
"HALL OF FAME:\n"
+ "\n".join(
[
f" {_}: {ind}, Fitness: {ind.fitness.values}"
for _, ind in enumerate(hall_of_fame)
]
)
)
end_t = time.perf_counter()
print(f"Time Elapsed: {end_t - t:,.2f}")
#%%
#%%
#%%
#%%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment