神经网络在量化中的应用

一、神经网络简介

1.什么是神经网络

根据周志华教授在《机器学习》一书中的定义,神经网络是由具有适应性简单单元组成的广泛并行互联的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。用一句话概述就是:神经网络能够模拟神经系统对输入作出一定反映。

2.神经元

神经元是神经网络中最基本的成分,有“兴奋”和“抑制”两种状态。神经网络是由一个个神经元按照一定结构组成,每个神经元和其他神经元相连。当某个神经元“兴奋”时,会向相连的下一个神经元传递化学物质,改变下一个神经元的电位,当电位超过一定阈值时,被刺激的神经元就会“兴奋”,这就是神经元的激活。在应用过程中,这个激活过程用激活函数表示。常见的激活函数包括:阶跃函数、Sigmoid函数。
在这里插入图片描述
(图片来源:周志华《机器学习》)

其中1表示神经元“兴奋”,2表示神经元“抑制”。最理想的激活函数为阶跃函数,即神经元要么抑制,要么兴奋。但由于阶跃函数不连续、不光滑,实际上常用Sigmoid作为激活函数。

3.神经网络的结构

两层神经元:感知机

在这里插入图片描述
输入层接收外界输入信号后经过w1,w2变换传递给输出层神经元,输出层神经元接收信号后根据阈值判断,超过阈值则变为“兴奋”状态,否则为“抑制”状态。

根据上述过程可以判断,w1、w2以及阈值的设计为神经网络的一大重点。怎样找到最优参数呢?一般情况下,输入一个初始值,然后需要给定训练数据集,根据训练数据集对权重进行调整。
在这里插入图片描述
其中为 η \eta η学习率,处于0-1之间。这种思想被称为梯度下降法。

多层网络之多层前馈神经元

感知机只有一层功能神经元(带有激活函数的),学习能力十分有限,想要解决更有难度的问题,需使用多层功能神经元。
在这里插入图片描述
如图是单隐层网络,还可以构建多隐层网络,既增加隐层神经元的数量。

二、最成功的神经网络学习算法——误差逆传播算法(BP)

在多层网络下,利用梯度下降法效率较低,误差逆传播算法能够很好解决这个问题。逆误差传播算法从最后一步的输出开始,基本思想是:计算当前参数下总体误差水平,再对其中各权重参数求偏导(表示各参数对整体误差产生了多少影响),以求出的偏导值*学习率对该权重参数进行更新,不断重复这个过程,直至误差处于我们能够接受的水平。步骤如下:

计算出当前参数下的总误差——对前一步权重求导——更新权重——重复上面的过程直到满足终止条件。

详细的推导过程可以参考CSDN上的文档:
大白话讲解BP算法

三、BP神经网络策略

策略思路:每个交易日9点,用前一日的开盘、收盘、成交量预测当日收益率。如果收益率>0.01,在10点时买入1手;如果收益率<0,清仓。

回测标的:DCE.i2105
回测时间:2020-09-01至2021-02-27
回测初始资金:10000000
回测手续费比率:0.0001
回测滑点比率:0.0001
回测结果如下图所示:
在这里插入图片描述
回测期收益为209.84%,年化收益率为427.88%,最大回撤85.34%,胜率为100%。

四、策略代码

注:本策略基于掘金量化平台编写,原文参考神经网络策略

# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *
import numpy as np
import pandas as pd


# 策略简介:
# 每天10点,用前1日的开盘、收盘、成交量预测当日的日收益率
# 如果预计日收益率>0.01,买入;



# 策略中必须有init方法
def init(context):
    # 定义标的
    context.symbol = 'DCE.i2105'
    # 设置定时任务1:每日9点用bp神经网络预测当日收盘价
    schedule(schedule_func=algo1,date_rule='1d',time_rule='09:00:00')
    # 设置定时任务2:每日10点开始调仓
    schedule(schedule_func=algo2, date_rule='1d', time_rule='10:00:00')


def algo1(context):
    '''用bp神经网络预测当日收盘价'''
    # 获取原始数据(选择102个是因为:回测时最新一条是now的日频数据,应该删除)
    data = history_n(symbol=context.symbol,frequency='1d',end_time=context.now,count=52,fields='close,bob,pre_close,open,volume',df=True)
    data.drop(51,inplace=True)   # 把最新一期数据删除
    data['ret'] = (data['close'] - data['open'])/data['open']

    # 数据归一化
    data['x1_std'] = (data['close'] - min(data['close'])) / (max(data['close']) - min(data['close']))      # 前收
    data['x2_std'] = (data['open'] - min(data['open'])) / (max(data['open']) - min(data['open']))          # 前开
    data['x3_std'] = (data['volume'] - min(data['volume'])) / (max(data['volume']) - min(data['volume']))  # 前交易量
    data['y'] = data['ret'].shift(-1)
    data['y_std'] = (data['y'] - min(data['y'])) / (max(data['y']) - min(data['y']))

    # 设置神经网络的参数
    input_neural_number = 3   # 输入神经元个数
    hidden_neural_number = 2   # 隐藏层神经元个数
    output_neural_number = 1    # 输出神经元个数
    size = 50                  # 样本大小

    # 输入层-隐层的权重w1,隐层-输出层权重w2(初始值:随意设置)
    weight1 = np.random.rand(input_neural_number, hidden_neural_number)
    weight2 = np.random.rand(hidden_neural_number, output_neural_number)

    # 训练,得到最优阈值
    w1,w2 = iter_train(10000, data,size, weight1, weight2)

    # 用得到的权重进行预测
    x_new = (data[['x1_std', 'x2_std', 'x3_std']].iloc[-1]).values
    input_hidden = np.dot(x_new, w1)
    output_hidden = sigmoid(input_hidden)

    # 输出预测结果
    input_out = np.dot(output_hidden, w2)
    y = sigmoid(input_out)
    context.y_pre = (max(data['y']) - min(data['y'])) * y + min(data['y'])    # 反归一化




def algo2(context):
    data = history_n(symbol=context.symbol, frequency='60s', count=1, end_time=context.now, df=True,
                   fields='close')['close']
    if context.y_pre > 0.01:
        order_volume(symbol=context.symbol, volume=100, side=OrderSide_Buy, order_type=OrderType_Limit, price=data[0],position_effect=PositionEffect_Open)
        print('开多一手')

    if context.y_pre < 0:
        order_target_volume(symbol=context.symbol, volume=100, position_side=PositionSide_Long, order_type=OrderType_Limit, price=data[0])
        print('平全仓')



def iter_train(n,data, size, weight1, weight2):
    # 首次输入神经网络,设置变量记录误差和权重
    error, w1, w2 = BP(data, size, weight1, weight2)
    err_s = error  # 储存最小误差
    w1_err = w1  # 储存最小误差对应的w1
    w2_err = w2  # 储存最小误差对应的w2

    # 迭代n次
    for i in range(n):
        errorn, w1n, w2n = BP(data, size, w1, w2)
        print('第%s次迭代完成' % (i + 1))
        # 更新权重
        w1 = w1n
        w2 = w2n

        # 如果新训练的权重误差小于记录的最小误差,则更新最小误差
        if errorn < error:
            err_s = errorn
            w1_err = w1n
            w2_err = w2n

    return w1_err,w2_err



def BP(data,size,weight1,weight2):
    '''BP神经网络预测函数'''
    '''data:原始数据集
'''

    # 将初始化参数输入到编写好的函数中,获得预测收盘价
    x = (data[['x1_std', 'x2_std', 'x3_std']].iloc[:-1]).values
    y = data['y_std'].iloc[0:-1].values.reshape(size, 1)

    # 隐层输入、输出
    input_hidden = np.dot(x, weight1)
    output_hidden = sigmoid(input_hidden)

    # 输出层输入、输出
    input_out = np.dot(output_hidden, weight2)
    output_out = sigmoid(input_out)

    # 更新矩阵
    r = 0.01  # 学习速度
    g = np.multiply(np.multiply(output_out, (1 - output_out)), y - output_out)
    b = np.dot(g, weight2.T)
    e = np.multiply(b, np.multiply(output_hidden, 1 - output_hidden))
    weight1_change = r * np.dot(np.transpose(x), e)
    weight2_change = r * np.dot(np.transpose(output_hidden), g)
    weight1 += weight1_change
    weight2 += weight2_change

    # 更新后的误差
    input_hidden = np.dot(x, weight1)
    output_hidden = sigmoid(input_hidden)
    input_out = np.dot(output_hidden, weight2)
    output_out = sigmoid(input_out)
    error = ((y - output_out).T * (y - output_out))[0, 0] / size  # 误差选择均方误差
    return error,weight1,weight2



def sigmoid(x):
    return 1/(1+np.exp(-x))



if __name__ == '__main__':
    '''
        strategy_id策略ID, 由系统生成
        filename文件名, 请与本文件名保持一致
        mode运行模式, 实时模式:MODE_LIVE回测模式:MODE_BACKTEST
        token绑定计算机的ID, 可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式, 不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
        '''
    run(strategy_id='strategy_id',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='token',
        backtest_start_time='2020-09-01 08:00:00',
        backtest_end_time='2021-02-27 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

おすすめ

転載: blog.csdn.net/weixin_42219751/article/details/115022636
おすすめ