-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenetic.py
More file actions
91 lines (69 loc) · 3.05 KB
/
genetic.py
File metadata and controls
91 lines (69 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import numpy as np
import random
from numpy.random import RandomState
from utils import fitness
prng = RandomState(123456789)
random.seed(42)
# Genetic Algorithm Parameters
POPULATION_SIZE = 50
N_GENERATIONS = 1000
CROSSOVER_RATE = 0.5
MUTATION_RATE = 0.1
def initialize_population(POPULATION_SIZE, n_assets):
return [prng.dirichlet(np.ones(n_assets)) for _ in range(POPULATION_SIZE)]
def selection(population, fitness_values):
selected = []
for _ in range(len(population)):
# Tournament selection with two random individuals
i, j = random.sample(range(len(population)), 2)
if fitness_values[i] > fitness_values[j]:
selected.append(population[i])
else:
selected.append(population[j])
return selected
# Step 3: Crossover - Uniform crossover
def crossover(parent1, parent2):
crossover_point = random.randint(1, len(parent1) - 1)
child1 = np.concatenate([parent1[:crossover_point], parent2[crossover_point:]])
child2 = np.concatenate([parent2[:crossover_point], parent1[crossover_point:]])
return child1 / child1.sum(), child2 / child2.sum() # Normalize to sum to 1
# Step 4: Mutation - Gaussian mutation
def mutate(individual):
if random.random() < MUTATION_RATE:
mutation = individual + prng.normal(0, 0.1, len(individual))
mutation = np.clip(mutation, 0, 1)
mutation /= mutation.sum() # Ensure the weights sum to 1
return mutation
return individual
# Genetic Algorithm
def genetic_algorithm(expected_returns, cov_matrix):
# Initialize population
population = initialize_population(POPULATION_SIZE, len(expected_returns))
history = []
# Track best solution
best_solution = None
best_fitness = -float("inf")
for generation in range(N_GENERATIONS):
# Step 1: Evaluate fitness for the population
fitness_values = [fitness(individual, expected_returns, cov_matrix) for individual in population]
# Find the best individual in the current population
max_fitness_index = np.argmax(fitness_values)
if fitness_values[max_fitness_index] > best_fitness:
best_solution = population[max_fitness_index]
best_fitness = fitness_values[max_fitness_index]
history.append(best_fitness)
selected_population = selection(population, fitness_values)
# Step 3: Crossover and Mutation to create new population
new_population = []
for i in range(0, len(selected_population), 2):
parent1 = selected_population[i]
parent2 = selected_population[i + 1 if i + 1 < len(selected_population) else 0] # Handle odd size
# Apply crossover
child1, child2 = crossover(parent1, parent2)
# Apply mutation
child1 = mutate(child1)
child2 = mutate(child2)
new_population.extend([child1, child2])
# Replace old population with the new one
population = new_population[:POPULATION_SIZE] # Ensure population size consistency
return best_solution, best_fitness, history