查找用于股票回测python的参数的最佳组合

use*_*418 0 python finance

给定一组5-6个参数,我很好奇该怎么做。在找到最大的价值增长时评估结果。

由于我拥有的参数数量,组合的数量似乎巨大。但是我的选择仅仅是使用for循环吗?

在此分配中,我一直在构建网格搜索策略(仅使用for循环),但还有更多变量。

http://nbviewer.ipython.org/github/cs109/content/blob/master/HW3.ipynb

Jon*_*tts 5

如果您具有复杂的黑匣子功能,并且需要以非线性方式调整输入,那么这听起来像是使用遗传算法(GA)的好应用程序。

什么是遗传算法?

通常,您会将参数的一种可能组合编码为一系列位。这将是您解决方案的“ DNA”。例如,您可以为每个值分配8位,参数1为位0-7,参数2为位8-15,依此类推。

之后,您将创建大量完全随机的解决方案(例如10,000个),并根据您的功能进行评估。在此之后,每种可能的解决方案都将获得与之相对的适应性。决定这一点的函数称为适应度函数,它是我们试图优化的目标函数。

根据此相对频率,您可以根据该频率选择5,000对解决方案,这样,最好的选择就会被更频繁地选择,但是即使最差的选择有时也可以通过。您可以通过在位DNA串上选择两个随机的剪接点,然后将这一部分从一个交换到另一个,以在下一个种群中产生两个新的后代,来“繁殖”每对。

此后,您一次又一次地重复整个过程,直到感到无聊或表现最佳的解决方案就足够了。

为什么行得通?

通常,最佳解决方案会更频繁地组合在一起。合并它们的过程允许将不同的成功解决方案混合在一起,以创建可能比任何一个父级更好的解决方案。

通用航空是正确的工具吗?

使用GA的好处是,它会在不真正了解它的情况下尝试优化您对它的投入。它也不关心您有多少个独立参数。如果您有100个参数,则嵌套循环确实是不可能的。重要的是您的健身功能的评估速度。速度越快,每秒可以计算的迭代次数就越多。

不利的一面是要创造大量的机制来使GA在一开始就可以工作,并且不能保证解决方案是最优的,也不能保证在任何特定的时间范围内都能达到目标。

但是在实践中,如果您无力搜索整个可能性空间,它们往往会在复杂问题上做得出奇地好。这是在您的工具箱中使用的好工具,因为您几乎可以将其扔到任何地方。

一个例子:

这是一个简单的GA示例。该行上方的代码是通用的,但是在下面的代码中,我们解决了找到一条有很多腿的忠诚动物的问题,该动物没有臭味或攻击性。这被编码为4个字节。

import random


class DNA(object):
    score = 0

    def __init__(self, bits):
        self.bits = bits
        self.length = len(bits)

    # https://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29#Two-point_crossover
    def two_point_crossover(self, other):
        start = random.randint(0, self.length - 1)
        end = random.randint(start, self.length - 1)

        child_1 = DNA(self.bits[:start] + other.bits[start:end] + self.bits[end:])
        child_2 = DNA(other.bits[:start] + self.bits[start:end] + other.bits[end:])
        return child_1, child_2

    # https://en.wikipedia.org/wiki/Mutation_%28genetic_algorithm%29
    def mutate(self, probability):
        self.bits = [bit if random.random() > probability else not bit for bit in self.bits]

    # Allow us to 'breed' two strings by doing dna_1 * dna_2
    def __mul__(self, other):
        return self.two_point_crossover(other)

    @staticmethod
    def decode_byte(bits):
        out = 0
        for bit in reversed(bits):
            out = out << 1
            out += bit

        return out

    def as_bytes(self):
        return [DNA.decode_byte(self.bits[start:start+8]) for start in xrange(0, self.length, 8)]


class Population(object):
    cumulative_scores = None
    total_score = 0
    best_score = 0
    best_member = None

    def __init__(self, members):
        self.members = members
        self.length = len(members)

    def rate(self, fitness_function):
        self.cumulative_scores = []
        self.total_scores = 0

        for member in self.members:
            score = fitness_function(member)
            member.score = score
            self.total_score += score
            self.cumulative_scores.append((self.total_score, member))

            if score > self.best_score:
                self.best_score = score
                self.best_member = member

    # https://en.wikipedia.org/wiki/Fitness_proportionate_selection
    def roulette_wheel_selection(self):
        pick = random.uniform(0, self.total_score)

        current = 0
        pos = 0

        while current < pick:
            (score, member) = self.cumulative_scores[pos]
            pos += 1
            current = score

        return member

    def mutate(self, mutation_rate):
        for member in self.members:
            member.mutate(mutation_rate)


class GeneticAlgorithm(object):
    def __init__(self, fitness_function, population, mutation_rate=0.01):
        self.population = population
        self.fitness_function = fitness_function
        self.mutation_rate=0.01

    def mutate(self):
        self.population.mutate(self.mutation_rate)

    def rate(self):
        self.population.rate(self.fitness_function)

    def breed(self):
        new_members = []
        while len(new_members) < self.population.length:
            parent_1 = self.population.roulette_wheel_selection()
            parent_2 = self.population.roulette_wheel_selection()

            new_members += parent_1 * parent_2

        self.population = Population(new_members[:self.population.length])


#----------------------------------------#
# My problem here 

def my_fitness(dna):
    angry, legs, smelly, loyalty = dna.as_bytes()

    score = float((510 - angry - smelly) * loyalty * legs) / float(510*255*255)
    return score


pop = Population([DNA([0] * 8 * 4) for _ in range(1000)])
pop.mutate(0.5)     # Totally randomise our starting set
ga = GeneticAlgorithm(my_fitness, pop)

for _ in range(100):
    ga.mutate()
    ga.rate()
    print "Best so far:", ga.population.best_score
    ga.breed()

# Finished!

ga.rate()
angry, legs, smelly, loyalty = ga.population.best_member.as_bytes()

print "Best score: ", ga.population.best_score
print "Angry", angry, "Legs", legs, "Smelly", smelly, "Loyalty", loyalty
Run Code Online (Sandbox Code Playgroud)